| 145 /// Rust-side helper for minimising P2 elements. This bypasses poorly documented basix, |
146 /// Rust-side helper for minimising P2 elements. This bypasses poorly documented basix, |
| 146 /// and does things at a low level directly. |
147 /// and does things at a low level directly. |
| 147 /// `f` is the function, `simplex_coords` the coorindates of the triangle |
148 /// `f` is the function, `simplex_coords` the coorindates of the triangle |
| 148 /// see [`cell_coords_Function_f64_triangle`], `cell` is the cell number, |
149 /// see [`cell_coords_Function_f64_triangle`], `cell` is the cell number, |
| 149 /// and `max` indicates whether to maximise or minimise. |
150 /// and `max` indicates whether to maximise or minimise. |
| 150 unsafe fn minmax_dolfinx_p2_cell( |
151 unsafe fn minmax_dolfinx_p2( |
| 151 f: *const Function_f64, |
152 simplex_coords: [f64; 18], |
| 152 simplex_coords: &[f64; 9], |
153 vals: [f64; 6], |
| 153 cell: i32, |
|
| 154 max: bool, |
154 max: bool, |
| 155 ) -> CoordValuePair; |
155 ) -> CoordValuePair; |
| 156 } |
156 } |
| 157 } |
157 } |
| 158 |
158 |
| 159 use ffi::CoordValuePair; |
159 use ffi::CoordValuePair; |
| 160 |
|
| 161 /// Convert an array of 2D oordinates obtained from Fenics, which hard-codes weird 3D coordinates. |
|
| 162 #[inline] |
|
| 163 fn coords_from_fenics(&[x1, x2, _, y1, y2, _, z1, z2, _]: &[f64; 9]) -> [Loc<2, f64>; 3] { |
|
| 164 [Loc([x1, x2]), Loc([y1, y2]), Loc([z1, z2])] |
|
| 165 } |
|
| 166 // fn coords_from_fenics<const N: usize>(coords: &[[f64; 3]; N]) -> [Loc<F, 2>; N] { |
|
| 167 // coords.map(|[x1, x2, _]| Loc([x1, x2])) |
|
| 168 // } |
|
| 169 |
|
| 170 /// Convert an array of 2D oordinates to Fenics, which hard-codes weird 3D coordinates. |
|
| 171 #[inline] |
|
| 172 fn coords_to_fenics([Loc([x1, x2]), Loc([y1, y2]), Loc([z1, z2])]: [Loc<2, f64>; 3]) -> [f64; 9] { |
|
| 173 [x1, x2, 0.0, y1, y2, 0.0, z1, z2, 0.0] |
|
| 174 } |
|
| 175 // fn coords_to_fenics<const N: usize>(coords: [Loc<F, 2>; N]) -> [[f64; 3]; N] { |
|
| 176 // coords.map(|Loc([x1, x2])| [x1, x2, 0.0]) |
|
| 177 // } |
|
| 178 |
160 |
| 179 /// Given a dolphinx `Function` `f`, as well as 6 coordinates on a simplex in its mesh |
161 /// Given a dolphinx `Function` `f`, as well as 6 coordinates on a simplex in its mesh |
| 180 /// (the corners and midpoints), construct a new internal P2 model on `cell`. |
162 /// (the corners and midpoints), construct a new internal P2 model on `cell`. |
| 181 /// If `max` is true, the model is negated compared to `f`. |
163 /// If `max` is true, the model is negated compared to `f`. |
| |
164 #[inline] |
| 182 unsafe fn model_dolfinx_p2_cell( |
165 unsafe fn model_dolfinx_p2_cell( |
| 183 f: *const ffi::Function_f64, |
166 [p0x, p0y, _, p1x, p1y, _, p2x, p2y, _, p12x, p12y, _, p20x, p20y, _, p01x, p01y, _]: [f64; 18], |
| 184 simplex_coords: &[f64; 9], |
167 [v0, v1, v2, v12, v20, v01]: [f64; 6], |
| 185 cell: i32, |
|
| 186 max: bool, |
168 max: bool, |
| 187 ) -> (P2LocalModel<f64, 2, 3>, Simplex<f64, 2, 3>) { |
169 ) -> (P2LocalModel<f64, 2, 3>, Simplex<f64, 2, 3>) { |
| 188 // Form simplex |
170 // Form simplex |
| 189 let simplex = Simplex(coords_from_fenics(simplex_coords)); |
171 let coords = [Loc([p0x, p0y]), Loc([p1x, p1y]), Loc([p2x, p2y])]; |
| 190 // Form an array of all coordinates |
172 let simplex = Simplex(coords); |
| 191 let midpoints = simplex.midpoints(); |
173 let values = if max { |
| 192 let mut all_coords_uninit: [MaybeUninit<f64>; 6 * 3] = [const { MaybeUninit::uninit() }; 6 * 3]; |
174 [-v0, -v1, -v2, -v01, -v12, -v20] |
| 193 all_coords_uninit |
175 } else { |
| 194 .iter_mut() |
176 [v0, v1, v2, v01, v12, v20] |
| 195 .zip( |
177 }; |
| 196 simplex_coords |
|
| 197 .iter() |
|
| 198 .copied() |
|
| 199 .chain(coords_to_fenics(midpoints).into_iter()), |
|
| 200 ) |
|
| 201 .for_each(|(a, b)| { |
|
| 202 a.write(b); |
|
| 203 }); |
|
| 204 let all_coords = MaybeUninit::array_assume_init(all_coords_uninit); |
|
| 205 // Evaluate the function, and invert the signs of maximising |
|
| 206 let mut values = ffi::eval_Function_f64_cell_6(f, &all_coords, cell); |
|
| 207 if max { |
|
| 208 values.iter_mut().for_each(|v| *v = -*v); |
|
| 209 } |
|
| 210 // Form local model |
178 // Form local model |
| 211 let [ref n0, ref n1, ref n2] = simplex.0; |
179 let nodes = [Loc([p0x, p0y]), Loc([p1x, p1y]), Loc([p2x, p2y]), Loc([p01x, p01y]), Loc([p12x, p12y]), Loc([p20x, p20y])]; |
| 212 let [ref n01, ref n12, ref n20] = midpoints; |
|
| 213 let nodes = [*n0, *n1, *n2, *n01, *n12, *n20]; |
|
| 214 let model = P2LocalModel::<f64, 2, 3>::new(&nodes, &values); |
180 let model = P2LocalModel::<f64, 2, 3>::new(&nodes, &values); |
| 215 |
181 |
| 216 return (model, simplex); |
182 return (model, simplex); |
| 217 } |
183 } |
| 218 |
184 |
| 219 /// This is a helper routine for `minmax_dolfinx_p2`. It reconstructs a P2 |
185 /// This is a helper routine for `minmax_dolfinx_p2`. It reconstructs a P2 |
| 220 /// model on the cell by evaluating f at 6 points (the simplex corners given |
186 /// model on the cell by evaluating f at 6 points (the simplex corners given |
| 221 /// in `simplex_doords`, as well as edge midpoints). Then it minimises this |
187 /// in `simplex_doords`, as well as edge midpoints). Then it minimises this |
| 222 /// model. The result should be accurate, given that `f` is assumed to have a |
188 /// model. The result should be accurate, given that `f` is assumed to have a |
| 223 /// P2 model on the simplex. |
189 /// P2 model on the simplex. |
| 224 pub unsafe fn minmax_dolfinx_p2_cell( |
190 pub unsafe fn minmax_dolfinx_p2( |
| 225 f: *const ffi::Function_f64, |
191 simplex_coords: [f64; 18], |
| 226 simplex_coords: &[f64; 9], |
192 vals: [f64; 6], |
| 227 cell: i32, |
|
| 228 max: bool, |
193 max: bool, |
| 229 ) -> ffi::CoordValuePair { |
194 ) -> ffi::CoordValuePair { |
| 230 let (model, simplex) = model_dolfinx_p2_cell(f, simplex_coords, cell, max); |
195 let (model, simplex) = model_dolfinx_p2_cell(simplex_coords, vals, max); |
| 231 let (x, v) = model.minimise(&simplex); |
196 let (x, v) = model.minimise(&simplex); |
| 232 CoordValuePair { x: x.into(), v } |
197 CoordValuePair { x: x.into(), v } |
| 233 } |
198 } |
| 234 |
199 |
| 235 pub const NAME: &str = "dolfinx_access"; |
200 pub const NAME: &str = "dolfinx_access"; |