pub(crate) mod model;
pub(crate) mod routines;
pub(crate) mod timers;
use honeycomb_core::{cmap::CMap2, geometry::CoordsFloat};
use thiserror::Error;
use vtkio::Vtk;
use crate::{
grid_generation::GridBuilder,
grisubal::{
model::{Boundary, Geometry2},
routines::{
clip_left, clip_right, compute_intersection_ids, compute_overlapping_grid,
detect_orientation_issue, generate_edge_data, generate_intersection_data,
group_intersections_per_edge, insert_edges_in_map, insert_intersections,
remove_redundant_poi,
},
timers::{finish, start_timer, unsafe_time_section},
},
};
#[derive(Default)]
pub enum Clip {
Left,
Right,
#[default]
None,
}
#[derive(Error, Debug)]
pub enum GrisubalError {
#[error("boundary isn't consistently oriented - {0}")]
InconsistentOrientation(&'static str),
#[error("input shape isn't conform to requirements - {0}")]
InvalidShape(&'static str),
#[error("invalid/corrupted data in the vtk file - {0}")]
BadVtkData(&'static str),
#[error("unsupported data in the vtk file - {0}")]
UnsupportedVtkData(&'static str),
}
#[allow(clippy::missing_errors_doc)]
#[allow(clippy::needless_pass_by_value)]
pub fn grisubal<T: CoordsFloat>(
file_path: impl AsRef<std::path::Path>,
grid_cell_sizes: [T; 2],
clip: Clip,
) -> Result<CMap2<T>, GrisubalError> {
start_timer!(instant);
let geometry_vtk = match Vtk::import(file_path) {
Ok(vtk) => vtk,
Err(e) => panic!("E: could not open specified vtk file - {e}"),
};
unsafe_time_section!(instant, timers::Section::ImportVTK);
let mut geometry = Geometry2::try_from(geometry_vtk)?;
unsafe_time_section!(instant, timers::Section::BuildGeometry);
detect_orientation_issue(&geometry)?;
unsafe_time_section!(instant, timers::Section::DetectOrientation);
let ([nx, ny], origin) = compute_overlapping_grid(&geometry, grid_cell_sizes, false)?;
let [cx, cy] = grid_cell_sizes;
unsafe_time_section!(instant, timers::Section::ComputeOverlappingGrid);
remove_redundant_poi(&mut geometry, grid_cell_sizes, origin);
unsafe_time_section!(instant, timers::Section::RemoveRedundantPoi);
start_timer!(kernel);
let mut cmap = GridBuilder::<2, T>::default()
.n_cells([nx, ny])
.len_per_cell([cx, cy])
.origin([origin.0, origin.1])
.add_attribute::<Boundary>() .build()
.expect("E: unreachable"); unsafe_time_section!(instant, timers::Section::BuildMeshInit);
let (new_segments, intersection_metadata) =
generate_intersection_data(&cmap, &geometry, [nx, ny], [cx, cy], origin);
let n_intersec = intersection_metadata.len();
let (edge_intersec, dart_slices) =
group_intersections_per_edge(&mut cmap, intersection_metadata);
let intersection_darts = compute_intersection_ids(n_intersec, &edge_intersec, &dart_slices);
unsafe_time_section!(instant, timers::Section::BuildMeshIntersecData);
insert_intersections(&cmap, &edge_intersec, &dart_slices);
unsafe_time_section!(instant, timers::Section::BuildMeshInsertIntersec);
let edges = generate_edge_data(&cmap, &geometry, &new_segments, &intersection_darts);
unsafe_time_section!(instant, timers::Section::BuildMeshEdgeData);
insert_edges_in_map(&mut cmap, &edges);
unsafe_time_section!(instant, timers::Section::BuildMeshInsertEdge);
unsafe_time_section!(kernel, timers::Section::BuildMeshTot);
match clip {
Clip::Left => clip_left(&mut cmap)?,
Clip::Right => clip_right(&mut cmap)?,
Clip::None => {}
}
unsafe_time_section!(instant, timers::Section::Clip);
cmap.remove_attribute_storage::<Boundary>();
finish!(instant);
Ok(cmap)
}
#[cfg(test)]
mod tests;