# Grid1D Decision Guide
This guide helps you make informed choices about which grid types, scalar types, and features to use in your application.
## Quick Decision Trees
### ๐ฏ Which Grid Type Should I Use?
```
START: What kind of spacing do I need?
โ
โโ Equal spacing everywhere?
โ โโ โ
Use Grid1DUniform
โ โข O(1) point location
โ โข Maximum performance
โ โข Perfect for regular discretizations
โ
โโ Custom/adaptive spacing?
โ โโ โ
Use Grid1DNonUniform
โ โข O(log n) point location
โ โข Flexible point distribution
โ โข Ideal for boundary layers, shock capturing
โ
โโ Combining multiple grids?
โโ โ
Use Grid1DUnion
โข Combines grids from different physics
โข Maintains mappings to original grids
โข For multi-physics simulations
```
### ๐ข Which Scalar Type Should I Use?
```
START: What are your priorities?
โ
โโ Maximum performance, fully trusted inputs?
โ โโ โ
Use f64
โ โข Zero overhead
โ โข Standard IEEE 754
โ โข โ ๏ธ No validation - can propagate NaN/Inf
โ
โโ Good performance + safety during development?
โ โโ โ
Use RealNative64StrictFiniteInDebug (โญ RECOMMENDED)
โ โข Same as f64 in release builds
โ โข Validates in debug builds
โ โข Perfect development โ production workflow
โ
โโ Safety-critical application?
โ โโ โ
Use RealNative64StrictFinite
โ โข Always validates (small overhead ~5-10%)
โ โข Guaranteed finite values
โ โข For medical, aerospace, financial
โ
โโ Need arbitrary precision?
โโ โ
Use RealRugStrictFinite<N>
โข N-bit precision (e.g., 256, 512, 1024)
โข For scientific computing, symbolic math
โข Requires `--features=rug`
```
## Detailed Comparison Tables
### Grid Type Comparison
| **Point Location** | O(1) analytical | O(log n) binary search | O(log n) on unified grid |
| **Memory Usage** | 8n + 40 bytes | 8n + 40 bytes | 8(n+m) + overhead |
| **Construction** | O(n) | O(n) | O(n+m) |
| **Best For** | Regular meshes, FDM | Adaptive meshes, FEM | Multi-physics coupling |
| **Spacing** | Uniform | Arbitrary | Combined |
| **Flexibility** | Low | High | Very High |
| **Performance** | โกโกโก Excellent | โกโก Good | โกโก Good |
*Where n = number of points, m = points in second grid*
### Scalar Type Comparison
| **f64** | โ None | โกโกโก | โกโกโก | Trusted inputs, maximum speed |
| **RealNative64StrictFiniteInDebug** | โ
Debug only | โกโก | โกโกโก | **Recommended default** |
| **RealNative64StrictFinite** | โ
Always | โกโก | โกโก | Safety-critical |
| **RealRugStrictFinite\<N\>** | โ
Always | โก | โก | Arbitrary precision |
### Interval Type Selection
| Include both endpoints | `IntervalClosed` | [a, b] | Standard bounded domains |
| Exclude both endpoints | `IntervalOpen` | (a, b) | Open sets, strict inequalities |
| Include left, exclude right | `IntervalLowerClosedUpperOpen` | [a, b) | Periodic domains, half-open ranges |
| Include right, exclude left | `IntervalLowerOpenUpperClosed` | (a, b] | Asymmetric boundaries |
| Unbounded above | `IntervalLowerClosedUpperUnbounded` | [a, +โ) | Semi-infinite domains |
| Unbounded below | `IntervalLowerUnboundedUpperClosed` | (-โ, b] | Semi-infinite domains |
| Single point | `IntervalSingleton` | {a} | Degenerate intervals |
## Use Case โ Recommended Configuration
### Finite Difference Methods (Regular Mesh)
**Scenario**: Solving PDEs on uniform grids
```rust
// Recommended configuration
type Real = RealNative64StrictFiniteInDebug; // Debug safety
type Domain = IntervalClosed<Real>; // Closed boundaries
let grid = Grid1D::uniform(
Domain::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
NumIntervals::try_new(1000).unwrap()
);
```
**Why?**
- โ
Uniform grid: O(1) point location for maximum performance
- โ
Debug validation: Catches NaN/Inf during development
- โ
Closed interval: Standard for boundary value problems
- โ
Release performance: Same as raw f64
### Finite Element Methods (Adaptive Mesh)
**Scenario**: FEM with mesh refinement in regions of interest
```rust
// Recommended configuration
type Real = RealNative64StrictFinite; // Always validated
type Domain = IntervalClosed<Real>;
// Start with coarse base mesh
let base_grid = Grid1D::uniform(/* ... */);
// Refine selectively where solution changes rapidly
let refined = base_grid.refine(&refinement_plan);
```
**Why?**
- โ
Non-uniform capability: Supports adaptive refinement
- โ
Always validated: Prevents propagation of numerical errors
- โ
Refinement tracking: Maintains parent-child relationships
- โ
Flexible spacing: Optimal resolution where needed
### Computational Fluid Dynamics (Boundary Layers)
**Scenario**: Viscous flow with wall boundary layers
```rust
// Recommended configuration
type Real = RealNative64StrictFiniteInDebug;
type Domain = IntervalClosed<Real>;
// Generate boundary layer mesh
let coords = create_boundary_layer_distribution(
wall_thickness,
num_boundary_points,
stretching_ratio
);
let grid = Grid1D::try_from_sorted(
Domain::new(/* ... */),
SortedSet::from_unsorted(coords)
).unwrap();
```
**Why?**
- โ
Non-uniform grid: Fine near wall, coarse in freestream
- โ
Custom distribution: Precise control over point clustering
- โ
Performance: Fast lookups even with non-uniform spacing
### Multi-Physics Coupling
**Scenario**: Coupling fluid flow with chemical reactions
```rust
// Recommended configuration
type Real = RealNative64StrictFinite; // Safety for complex coupling
// Separate grids for each physics
let flow_grid = Grid1D::uniform(/* coarse global */);
let chemistry_grid = Grid1D::try_from_sorted(/* fine local */);
// Unified grid for data transfer
let coupled = Grid1DUnion::try_new(&flow_grid, &chemistry_grid).unwrap();
// Map between grids
for (unified_id, flow_id, chem_id) in coupled.iter_interval_mappings() {
// Transfer data between physics
}
```
**Why?**
- โ
Grid union: Preserves both discretizations
- โ
Bidirectional mapping: Efficient data transfer
- โ
Validated scalars: Prevents coupling instabilities
### High-Precision Scientific Computing
**Scenario**: Numerical analysis requiring exact arithmetic
```rust
#[cfg(feature = "rug")]
{
// Recommended configuration
type Real = RealRugStrictFinite<256>; // 256-bit precision
type Domain = IntervalClosed<Real>;
let grid = Grid1D::uniform(
Domain::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
),
NumIntervals::try_new(100).unwrap()
);
}
```
**Why?**
- โ
Arbitrary precision: Eliminates rounding errors
- โ
Validated: Maintains numerical integrity
- โ
Same API: Easy to switch from f64
### Real-Time Applications
**Scenario**: Simulation loop with strict timing requirements
```rust
// Recommended configuration
type Real = f64; // Maximum performance, no validation
type Domain = IntervalClosed<Real>;
let grid = Grid1D::uniform(
Domain::new(0.0, 1.0),
NumIntervals::try_new(1000).unwrap()
);
// In real-time loop
loop {
// O(1) point location - predictable timing
let interval_id = grid.find_interval_id_of_point(&sensor_value);
// ... process ...
}
```
**Why?**
- โ
Raw f64: Zero overhead, predictable performance
- โ
Uniform grid: O(1) lookups, no branch prediction issues
- โ
No validation: No runtime checks in critical path
## Performance Tuning Guidelines
### When to Choose Uniform Grid
โ
**Choose uniform grid when:**
- All intervals need equal spacing
- Maximum performance is critical
- Simple, regular domain discretization
- Point location happens frequently
โ **Avoid uniform grid when:**
- Features occur at different scales
- Adaptive refinement is needed
- Boundary layer resolution required
### When to Choose Non-Uniform Grid
โ
**Choose non-uniform grid when:**
- Adaptive spacing is beneficial
- Multiple length scales present
- Boundary layer capture needed
- Features localized in space
โ **Avoid non-uniform grid when:**
- Uniform spacing is sufficient
- Maximum performance is critical
- Simple regular problem
### When to Use Grid Union
โ
**Use grid union when:**
- Coupling multiple physics
- Different solvers on different grids
- Need to preserve original grid structure
- Frequent data transfer between grids
โ **Avoid grid union when:**
- Single physics problem
- Don't need grid mapping
- Memory is constrained
## Scalar Type Performance Impact
### Benchmarked Overheads (relative to f64)
| Arithmetic | 1.0ร | 1.5-2.0ร | 1.0ร | 1.05-1.10ร |
| Comparison | 1.0ร | 1.3-1.5ร | 1.0ร | 1.02-1.05ร |
| Grid creation | 1.0ร | 1.5ร | 1.0ร | 1.10ร |
| Point location | 1.0ร | 1.2ร | 1.0ร | 1.05ร |
**Key takeaway**: `RealNative64StrictFiniteInDebug` has zero overhead in release builds.
## Migration Strategies
### From f64 to Validated Types
**Step 1**: Start with raw f64
```rust
let grid = Grid1D::uniform(
IntervalClosed::new(0.0_f64, 1.0_f64),
NumIntervals::try_new(100).unwrap()
);
```
**Step 2**: Add debug validation (no code changes needed in release!)
```rust
type Real = RealNative64StrictFiniteInDebug;
let grid = Grid1D::uniform(
IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
),
NumIntervals::try_new(100).unwrap()
);
```
**Step 3**: If safety-critical, use always-validated
```rust
type Real = RealNative64StrictFinite;
// Same code as Step 2
```
### From Uniform to Non-Uniform
**Before** (uniform):
```rust
let grid = Grid1D::uniform(domain, NumIntervals::try_new(100).unwrap());
```
**After** (non-uniform with custom spacing):
```rust
let coords = generate_custom_distribution();
let grid = Grid1D::try_from_sorted(domain, SortedSet::from_unsorted(coords)).unwrap();
```
## Common Pitfalls and Solutions
### Pitfall 1: Using Wrong Grid Type
โ **Wrong**:
```rust
// Using non-uniform grid when uniform would work
```
โ
**Correct**:
```rust
// Use uniform grid for better performance
let grid = Grid1D::uniform(
IntervalClosed::new(0.0, 1.0),
NumIntervals::try_new(100).unwrap()
);
```
### Pitfall 2: Over-validating in Performance-Critical Code
โ **Wrong**:
```rust
type Real = RealNative64StrictFinite; // Always validates
// In hot loop
for _ in 0..1_000_000 {
let result = a + b; // Validates every operation
}
```
โ
**Correct**:
```rust
type Real = RealNative64StrictFiniteInDebug; // Validates only in debug
// In hot loop - no overhead in release
for _ in 0..1_000_000 {
let result = a + b; // Fast in release
}
```
### Pitfall 3: Forgetting to Handle Errors
โ **Wrong**:
```rust
let grid = Grid1D::try_from_sorted(domain, coords).unwrap(); // Panics on error
```
โ
**Correct**:
```rust
let grid = Grid1D::try_from_sorted(domain, coords)
.map_err(|e| {
eprintln!("Grid creation failed: {:?}", e);
e
})?;
```
## Summary Recommendations
### For Most Users (โญ Recommended)
```rust
use grid1d::{Grid1D, intervals::IntervalClosed, scalars::NumIntervals};
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
type Domain = IntervalClosed<Real>;
// Uniform grid for regular problems
let grid = Grid1D::uniform(
Domain::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
NumIntervals::try_new(100).unwrap()
);
```
**This gives you**:
- โ
Maximum performance in release builds
- โ
Safety validation during development
- โ
O(1) point location for uniform grids
- โ
Easy to change if needs evolve
### Quick Reference Card
| Regular mesh, maximum speed | `Grid1DUniform` + `f64` |
| **Most applications** | **`Grid1DUniform` + `RealNative64StrictFiniteInDebug`** |
| Adaptive mesh | `Grid1DNonUniform` + `RealNative64StrictFiniteInDebug` |
| Safety-critical | Any grid + `RealNative64StrictFinite` |
| Multi-physics | `Grid1DUnion` + `RealNative64StrictFinite` |
| High precision | Any grid + `RealRugStrictFinite<N>` |
| Periodic domains | Any grid + `IntervalLowerClosedUpperOpen` |
---
For more details, see:
- [Complete Tutorial](./TUTORIAL.md)
- [API Documentation](https://docs.rs/grid1d)
- [README](./README.md)