Add interpolation grid generators
This commit is contained in:
		
							
								
								
									
										125
									
								
								gridgeneration/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								gridgeneration/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
use ndarray::Array2;
 | 
			
		||||
 | 
			
		||||
pub use sbp::{consts::*, grid::Grid, Float};
 | 
			
		||||
 | 
			
		||||
pub fn unit(ny: usize, nx: usize) -> Grid {
 | 
			
		||||
    let x = Array2::from_shape_fn((ny, nx), |(_j, i)| i as Float / (nx - 1) as Float);
 | 
			
		||||
    let y = Array2::from_shape_fn((ny, nx), |(j, _i)| j as Float / (ny - 1) as Float);
 | 
			
		||||
    Grid::new(x, y).unwrap()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn shell(ny: usize, nx: usize, mut inner: Float, mut outer: Float) -> Grid {
 | 
			
		||||
    let mut unit = unit(ny, nx);
 | 
			
		||||
 | 
			
		||||
    #[allow(unused)]
 | 
			
		||||
    enum Mode {
 | 
			
		||||
        Log,
 | 
			
		||||
        Exp,
 | 
			
		||||
        Normal,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mode = Mode::Log;
 | 
			
		||||
    match mode {
 | 
			
		||||
        Mode::Exp => {
 | 
			
		||||
            inner = inner.exp();
 | 
			
		||||
            outer = outer.exp();
 | 
			
		||||
        }
 | 
			
		||||
        Mode::Log => {
 | 
			
		||||
            inner = inner.ln();
 | 
			
		||||
            outer = outer.ln();
 | 
			
		||||
        }
 | 
			
		||||
        _ => {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let (mut gx, mut gy) = unit.components();
 | 
			
		||||
    gx.iter_mut().zip(gy.iter_mut()).for_each(|(x, y)| {
 | 
			
		||||
        let mut r = (*x) * (outer - inner) + inner;
 | 
			
		||||
        match mode {
 | 
			
		||||
            Mode::Exp => {
 | 
			
		||||
                r = r.ln();
 | 
			
		||||
            }
 | 
			
		||||
            Mode::Log => {
 | 
			
		||||
                r = r.exp();
 | 
			
		||||
            }
 | 
			
		||||
            _ => {}
 | 
			
		||||
        }
 | 
			
		||||
        let theta = *y * 2.0 * PI;
 | 
			
		||||
 | 
			
		||||
        *x = r * theta.cos();
 | 
			
		||||
        *y = r * theta.sin();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    unit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn vertical_interpolation(jlen: usize, north: &[Float], south: &[Float]) -> Grid {
 | 
			
		||||
    let ilen = north.len();
 | 
			
		||||
    assert_eq!(north.len(), south.len());
 | 
			
		||||
    let mut grid = unit(jlen, ilen);
 | 
			
		||||
 | 
			
		||||
    for j in 0..jlen {
 | 
			
		||||
        for i in 0..ilen {
 | 
			
		||||
            let y = grid.y()[(j, i)];
 | 
			
		||||
            grid.y_mut()[(j, i)] = (north[i] - south[i]) * y + south[i];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    grid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn horizontal_interpolation(ilen: usize, east: &[Float], west: &[Float]) -> Grid {
 | 
			
		||||
    let jlen = east.len();
 | 
			
		||||
    assert_eq!(east.len(), west.len());
 | 
			
		||||
    let mut grid = unit(jlen, ilen);
 | 
			
		||||
 | 
			
		||||
    for j in 0..jlen {
 | 
			
		||||
        for i in 0..ilen {
 | 
			
		||||
            let x = grid.x()[(j, i)];
 | 
			
		||||
            grid.x_mut()[(j, i)] = (east[j] - west[j]) * x + west[j];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    grid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn horizontal_interpolation_dual(
 | 
			
		||||
    ilen: usize,
 | 
			
		||||
    east: (&[Float], &[Float]),
 | 
			
		||||
    west: (&[Float], &[Float]),
 | 
			
		||||
) -> Grid {
 | 
			
		||||
    let jlen = east.0.len();
 | 
			
		||||
    assert_eq!(east.0.len(), east.1.len());
 | 
			
		||||
    assert_eq!(east.0.len(), west.0.len());
 | 
			
		||||
    assert_eq!(east.0.len(), west.1.len());
 | 
			
		||||
    let mut grid = unit(jlen, ilen);
 | 
			
		||||
 | 
			
		||||
    for j in 0..jlen {
 | 
			
		||||
        for i in 0..ilen {
 | 
			
		||||
            let x = grid.x()[(j, i)];
 | 
			
		||||
            grid.x_mut()[(j, i)] = (east.1[j] - west.1[j]) * x + west.1[j];
 | 
			
		||||
            grid.y_mut()[(j, i)] = (east.0[j] - west.0[j]) * x + west.0[j];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    grid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// [east] : fn([0, 1]) -> (y, x)
 | 
			
		||||
/// [west] : fn([0, 1]) -> (y, x)
 | 
			
		||||
pub fn horizontal_interpolation_dual2(
 | 
			
		||||
    ilen: usize,
 | 
			
		||||
    jlen: usize,
 | 
			
		||||
    east: impl Fn(Float) -> (Float, Float),
 | 
			
		||||
    west: impl Fn(Float) -> (Float, Float),
 | 
			
		||||
) -> Grid {
 | 
			
		||||
    let mut grid = unit(jlen, ilen);
 | 
			
		||||
 | 
			
		||||
    for j in 0..jlen {
 | 
			
		||||
        for i in 0..ilen {
 | 
			
		||||
            let x = grid.x()[(j, i)];
 | 
			
		||||
            let y = grid.y()[(j, i)];
 | 
			
		||||
            let east = east(y);
 | 
			
		||||
            let west = west(y);
 | 
			
		||||
            grid.x_mut()[(j, i)] = (east.1 - west.1) * x + west.1;
 | 
			
		||||
            grid.y_mut()[(j, i)] = (east.0 - west.0) * x + west.0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    grid
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								gridgeneration/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								gridgeneration/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
#![allow(unused)]
 | 
			
		||||
use gridgeneration::*;
 | 
			
		||||
use plotters::prelude::*;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    // let grid = Grid::unit(10, 11);
 | 
			
		||||
    // let grid = shell(30, 21, 0.1, 3.1);
 | 
			
		||||
    let grid = {
 | 
			
		||||
        let ybot = (0..100)
 | 
			
		||||
            .map(|x| (x as Float / 30.0).sin())
 | 
			
		||||
            .collect::<Vec<_>>();
 | 
			
		||||
        let ytop = (0..100)
 | 
			
		||||
            .map(|x| 2.5 + (x as Float / 10.0).sin())
 | 
			
		||||
            .collect::<Vec<_>>();
 | 
			
		||||
        // vertical_interpolation(10, &ytop, &ybot)
 | 
			
		||||
        // horizontal_interpolation(10, &ytop, &ybot)
 | 
			
		||||
        /*
 | 
			
		||||
        horizontal_interpolation_dual(
 | 
			
		||||
            30,
 | 
			
		||||
            (&[0.0, 0.0, 1.0, 3.0], &[0.0, 2.0, 4.0, 6.0]),
 | 
			
		||||
            (&[3.0, 5.0, 6.0, 7.0], &[0.0, 2.0, 3.0, 10.0]),
 | 
			
		||||
        )
 | 
			
		||||
        */
 | 
			
		||||
        /*
 | 
			
		||||
        horizontal_interpolation_dual2(
 | 
			
		||||
            30,
 | 
			
		||||
            40,
 | 
			
		||||
            move |t| ((t * 3.0).sin(), t + 0.2),
 | 
			
		||||
            move |t| ((5.0 * t).sin() + 2.5, t),
 | 
			
		||||
        )
 | 
			
		||||
        */
 | 
			
		||||
        horizontal_interpolation_dual2(
 | 
			
		||||
            30,
 | 
			
		||||
            40,
 | 
			
		||||
            move |t| (2.0 * t * std::f64::consts::PI).sin_cos(),
 | 
			
		||||
            move |t| {
 | 
			
		||||
                let (y, x) = (2.0 * t * std::f64::consts::PI).sin_cos();
 | 
			
		||||
                (0.1 * y, 0.1 * x)
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    };
 | 
			
		||||
    draw_grid(&grid, "grid.svg");
 | 
			
		||||
 | 
			
		||||
    let grid = horizontal_interpolation_dual2(
 | 
			
		||||
        200,
 | 
			
		||||
        200,
 | 
			
		||||
        move |t| {
 | 
			
		||||
            let ts = [0.05, 0.25, 0.75, 0.95];
 | 
			
		||||
            if t < ts[0] {
 | 
			
		||||
                let t = t / (ts[0] - 0.0);
 | 
			
		||||
                (t, 5.0)
 | 
			
		||||
            } else if t < ts[1] {
 | 
			
		||||
                let t = (t - ts[0]) / (ts[1] - ts[0]);
 | 
			
		||||
                (1.0, 5.0 - 5.0 * t)
 | 
			
		||||
            } else if t < ts[2] {
 | 
			
		||||
                let t = (t - ts[1]) / (ts[2] - ts[1]);
 | 
			
		||||
                (std::f64::consts::PI * (t + 0.5)).sin_cos()
 | 
			
		||||
            } else if t < ts[3] {
 | 
			
		||||
                let t = (t - ts[2]) / (ts[3] - ts[2]);
 | 
			
		||||
                (-1.0, 5.0 * t)
 | 
			
		||||
            } else {
 | 
			
		||||
                let t = (t - ts[3]) / (1.0 - ts[3]);
 | 
			
		||||
                (-1.0 + t, 5.0)
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        move |t| {
 | 
			
		||||
            let (y, x) = (2.0 * t * std::f64::consts::PI).sin_cos();
 | 
			
		||||
            (0.2 * y, 0.2 * x)
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    draw_grid(&grid, "ctype.svg");
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "serde")]
 | 
			
		||||
    println!("{}", json5::to_string(&grid).unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn linspace(range: std::ops::Range<Float>, steps: usize) -> Vec<Float> {
 | 
			
		||||
    let start = range.start;
 | 
			
		||||
    let end = range.end;
 | 
			
		||||
 | 
			
		||||
    let dx = (end - start) / (steps - 1) as Float;
 | 
			
		||||
 | 
			
		||||
    (0..steps).map(|i| i as Float * dx).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn draw_grid(grid: &Grid, name: &str) {
 | 
			
		||||
    let drawing_area = SVGBackend::new(name, (1000, 1000)).into_drawing_area();
 | 
			
		||||
    drawing_area.fill(&WHITE).unwrap();
 | 
			
		||||
 | 
			
		||||
    let x_minmax = grid
 | 
			
		||||
        .x()
 | 
			
		||||
        .iter()
 | 
			
		||||
        .fold((Float::INFINITY, -Float::INFINITY), |(min, max), &x| {
 | 
			
		||||
            (min.min(x), max.max(x))
 | 
			
		||||
        });
 | 
			
		||||
    let y_minmax = grid
 | 
			
		||||
        .y()
 | 
			
		||||
        .iter()
 | 
			
		||||
        .fold((Float::INFINITY, -Float::INFINITY), |(min, max), &y| {
 | 
			
		||||
            (min.min(y), max.max(y))
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    let mut chart = ChartBuilder::on(&drawing_area)
 | 
			
		||||
        .x_label_area_size(40)
 | 
			
		||||
        .y_label_area_size(40)
 | 
			
		||||
        .build_cartesian_2d(x_minmax.0..x_minmax.1, y_minmax.0..y_minmax.1)
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    chart
 | 
			
		||||
        .configure_mesh()
 | 
			
		||||
        .x_desc("x")
 | 
			
		||||
        .y_desc("y")
 | 
			
		||||
        .disable_mesh()
 | 
			
		||||
        .draw()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    let style = &BLACK.stroke_width(1);
 | 
			
		||||
    for axes in &[ndarray::Axis(1), ndarray::Axis(0)] {
 | 
			
		||||
        for (linex, liney) in grid.x().axis_iter(*axes).zip(grid.y().axis_iter(*axes)) {
 | 
			
		||||
            chart
 | 
			
		||||
                .draw_series(LineSeries::new(
 | 
			
		||||
                    linex.iter().zip(&liney).map(|(&x, &y)| (x, y)),
 | 
			
		||||
                    style.clone(),
 | 
			
		||||
                ))
 | 
			
		||||
                .unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
    let coord = |idx| (grid.x()[idx], grid.y()[idx]);
 | 
			
		||||
    let zero = coord((0, 0));
 | 
			
		||||
    let up = coord((1, 0));
 | 
			
		||||
    let right = coord((0, 1));
 | 
			
		||||
    chart
 | 
			
		||||
        .draw_series(PointSeries::of_element(
 | 
			
		||||
            [zero].iter().copied(),
 | 
			
		||||
            5,
 | 
			
		||||
            ShapeStyle::from(&RED).filled(),
 | 
			
		||||
            &|coord, size, style| {
 | 
			
		||||
                EmptyElement::at(coord)
 | 
			
		||||
                    + Circle::new((0, 0), size, style)
 | 
			
		||||
                    + Text::new("η", (1, 1), ("arial", 10))
 | 
			
		||||
            },
 | 
			
		||||
        ))
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    */
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user