1use crate::algs::communicator::{CommTag, Communicator, SectionCommTags};
9use crate::algs::completion::section_completion::complete_section_with_tags_and_ownership;
10use crate::data::constrained_section::{ConstraintSet, apply_constraints_to_section};
11use crate::data::hanging_node_constraints::{
12 HangingNodeConstraints, apply_hanging_constraints_to_section,
13};
14use crate::data::section::Section;
15use crate::data::storage::Storage;
16use crate::mesh_error::MeshSieveError;
17use crate::overlap::delta::{CopyDelta, ValueDelta};
18use crate::overlap::overlap::Overlap;
19use crate::topology::ownership::PointOwnership;
20
21#[derive(Copy, Clone, Debug)]
23pub struct AssemblyCommTags {
24 pub reduce: SectionCommTags,
26 pub complete: SectionCommTags,
28}
29
30impl AssemblyCommTags {
31 #[inline]
33 pub const fn from_base(base: CommTag) -> Self {
34 Self {
35 reduce: SectionCommTags::from_base(base),
36 complete: SectionCommTags::from_base(base.offset(2)),
37 }
38 }
39}
40
41pub fn assemble_section_with_tags_and_ownership<V, S, D, C, Con>(
48 section: &mut Section<V, S>,
49 overlap: &Overlap,
50 ownership: &PointOwnership,
51 comm: &C,
52 my_rank: usize,
53 tags: AssemblyCommTags,
54 constraints: &Con,
55) -> Result<(), MeshSieveError>
56where
57 V: Clone + Default + Send + PartialEq + bytemuck::Pod + Copy + 'static,
58 S: Storage<V>,
59 D: ValueDelta<V> + Send + Sync + 'static,
60 D::Part: bytemuck::Pod + Default + Copy,
61 C: Communicator + Sync,
62 Con: ConstraintSet<V>,
63{
64 complete_section_with_tags_and_ownership::<V, S, D, C>(
65 section,
66 overlap,
67 ownership,
68 comm,
69 my_rank,
70 tags.reduce,
71 )?;
72
73 apply_constraints_to_section(section, constraints)?;
74
75 complete_section_with_tags_and_ownership::<V, S, CopyDelta, C>(
76 section,
77 overlap,
78 ownership,
79 comm,
80 my_rank,
81 tags.complete,
82 )?;
83
84 Ok(())
85}
86
87pub fn assemble_section_with_hanging_constraints_and_ownership<V, S, D, C, Con>(
91 section: &mut Section<V, S>,
92 overlap: &Overlap,
93 ownership: &PointOwnership,
94 comm: &C,
95 my_rank: usize,
96 tags: AssemblyCommTags,
97 hanging_constraints: &HangingNodeConstraints<V>,
98 constraints: &Con,
99) -> Result<(), MeshSieveError>
100where
101 V: Clone
102 + Default
103 + Send
104 + PartialEq
105 + bytemuck::Pod
106 + Copy
107 + 'static
108 + core::ops::AddAssign
109 + core::ops::Mul<Output = V>,
110 S: Storage<V>,
111 D: ValueDelta<V> + Send + Sync + 'static,
112 D::Part: bytemuck::Pod + Default + Copy,
113 C: Communicator + Sync,
114 Con: ConstraintSet<V>,
115{
116 complete_section_with_tags_and_ownership::<V, S, D, C>(
117 section,
118 overlap,
119 ownership,
120 comm,
121 my_rank,
122 tags.reduce,
123 )?;
124
125 apply_hanging_constraints_to_section(section, hanging_constraints)?;
126 apply_constraints_to_section(section, constraints)?;
127
128 complete_section_with_tags_and_ownership::<V, S, CopyDelta, C>(
129 section,
130 overlap,
131 ownership,
132 comm,
133 my_rank,
134 tags.complete,
135 )?;
136
137 Ok(())
138}
139
140pub fn assemble_section_with_ownership<V, S, D, C, Con>(
142 section: &mut Section<V, S>,
143 overlap: &Overlap,
144 ownership: &PointOwnership,
145 comm: &C,
146 my_rank: usize,
147 constraints: &Con,
148) -> Result<(), MeshSieveError>
149where
150 V: Clone + Default + Send + PartialEq + bytemuck::Pod + Copy + 'static,
151 S: Storage<V>,
152 D: ValueDelta<V> + Send + Sync + 'static,
153 D::Part: bytemuck::Pod + Default + Copy,
154 C: Communicator + Sync,
155 Con: ConstraintSet<V>,
156{
157 let tags = AssemblyCommTags::from_base(CommTag::new(0xBEEF));
158 assemble_section_with_tags_and_ownership::<V, S, D, C, Con>(
159 section,
160 overlap,
161 ownership,
162 comm,
163 my_rank,
164 tags,
165 constraints,
166 )
167}
168
169use crate::data::closure::{
170 ClosureOrder, IdentitySectionSym, SectionSym, build_closure_index,
171 build_closure_index_unoriented,
172};
173use crate::data::global_map::LocalToGlobalMap;
174use crate::discretization::runtime::{ClosureDof, CsrPattern, DofMap, dof_map_from_closure_index};
175use crate::topology::point::PointId;
176use crate::topology::sieve::{Orientation, OrientedSieve, Sieve};
177use std::collections::{BTreeSet, HashMap};
178
179pub fn cell_closure_dof_map<T, V, Sct>(
181 topology: &T,
182 section: &Section<V, Sct>,
183 cell: PointId,
184 topology_version: u64,
185 order: &ClosureOrder,
186) -> Result<DofMap, MeshSieveError>
187where
188 T: Sieve<Point = PointId>,
189 Sct: Storage<V>,
190{
191 let index = build_closure_index_unoriented(
192 topology,
193 section,
194 cell,
195 topology_version,
196 order,
197 &IdentitySectionSym,
198 )?;
199 Ok(dof_map_from_closure_index(&index))
200}
201
202pub fn oriented_cell_closure_dof_map<T, V, Sct, O, Sym>(
204 topology: &T,
205 section: &Section<V, Sct>,
206 cell: PointId,
207 topology_version: u64,
208 order: &ClosureOrder,
209 sym: &Sym,
210) -> Result<DofMap, MeshSieveError>
211where
212 T: OrientedSieve<Point = PointId, Orient = O>,
213 Sct: Storage<V>,
214 O: Orientation + Eq + std::hash::Hash,
215 Sym: SectionSym<O>,
216{
217 let index = build_closure_index(topology, section, cell, topology_version, order, sym)?;
218 Ok(dof_map_from_closure_index(&index))
219}
220
221pub fn preallocation_csr_from_closure<T, V, Sct>(
223 topology: &T,
224 section: &Section<V, Sct>,
225 cells: impl IntoIterator<Item = PointId>,
226 topology_version: u64,
227 order: &ClosureOrder,
228) -> Result<CsrPattern, MeshSieveError>
229where
230 T: Sieve<Point = PointId>,
231 Sct: Storage<V>,
232{
233 let mut rows: HashMap<ClosureDof, BTreeSet<ClosureDof>> = HashMap::new();
234 for cell in cells {
235 let map = cell_closure_dof_map(topology, section, cell, topology_version, order)?;
236 let dofs = map.closure_dofs().to_vec();
237 for row in &dofs {
238 rows.entry(*row).or_default().extend(dofs.iter().copied());
239 }
240 }
241 Ok(csr_from_rows(rows))
242}
243
244pub fn global_preallocation_csr_from_closure<T, V, Sct>(
246 topology: &T,
247 section: &Section<V, Sct>,
248 global_map: &LocalToGlobalMap,
249 cells: impl IntoIterator<Item = PointId>,
250 topology_version: u64,
251 order: &ClosureOrder,
252) -> Result<GlobalCsrPattern, MeshSieveError>
253where
254 T: Sieve<Point = PointId>,
255 Sct: Storage<V>,
256{
257 let local = preallocation_csr_from_closure(topology, section, cells, topology_version, order)?;
258 let rows = local
259 .rows
260 .iter()
261 .map(|dof| {
262 global_map
263 .global_index(dof.point, dof.local_dof)
264 .map(|g| g as usize)
265 })
266 .collect::<Result<Vec<_>, _>>()?;
267 let adjncy = local
268 .adjncy
269 .iter()
270 .map(|dof| {
271 global_map
272 .global_index(dof.point, dof.local_dof)
273 .map(|g| g as usize)
274 })
275 .collect::<Result<Vec<_>, _>>()?;
276 Ok(GlobalCsrPattern {
277 xadj: local.xadj,
278 adjncy,
279 rows,
280 })
281}
282
283#[derive(Clone, Debug, PartialEq, Eq)]
285pub struct GlobalCsrPattern {
286 pub xadj: Vec<usize>,
288 pub adjncy: Vec<usize>,
290 pub rows: Vec<usize>,
292}
293
294fn csr_from_rows(mut rows: HashMap<ClosureDof, BTreeSet<ClosureDof>>) -> CsrPattern {
295 let mut row_dofs: Vec<_> = rows.keys().copied().collect();
296 row_dofs.sort_unstable();
297 let mut xadj = Vec::with_capacity(row_dofs.len() + 1);
298 let mut adjncy = Vec::new();
299 xadj.push(0);
300 for row in &row_dofs {
301 if let Some(cols) = rows.remove(row) {
302 adjncy.extend(cols);
303 }
304 xadj.push(adjncy.len());
305 }
306 CsrPattern {
307 xadj,
308 adjncy,
309 rows: row_dofs,
310 }
311}