0% found this document useful (0 votes)
2 views

code (1)

Uploaded by

ahmedmidoo1595
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

code (1)

Uploaded by

ahmedmidoo1595
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 5

use clap::Parser;

use ndarray::{Array1, Array2};


use num_traits::Float;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
use std::time::Instant;

#[cfg(feature = "plot")]
use gnuplot::{Axes2D, Figure, PlotOption};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(short = 'c', long, default_value = "100.0")]
cond: f64,
#[arg(short = 'p', long, default_value = "1000.0")]
cp: f64,
#[arg(short = 'a', long, default_value = "0.1")]
area: f64,
#[arg(short = 'l', long, default_value = "5.0")]
length: f64,
#[arg(short = 'n', long, default_value = "100")]
n_cells: usize,
#[arg(short = 'L', long, default_value = "100.0")]
temp_left: f64,
#[arg(short = 'R', long, default_value = "200.0")]
temp_right: f64,
#[arg(short = 'q', long, default_value = "1000.0")]
heat_source_per_vol: f64,
#[arg(short = 'v', long, default_value = "0.01")]
flow_velocity: f64,
#[arg(short = 'd', long, default_value = "1.0")]
fluid_density: f64,
#[arg(long, default_value = "true")]
plot: bool,
#[arg(long, default_value = "true")]
print_setup: bool,
#[arg(long, default_value = "true")]
print_solution: bool,
}
#[derive(Debug, Clone, Copy)]
struct SimulationParameters {
cond: f64,
cp: f64,
area: f64,
length: f64,
n_cells: usize,
temp_left: f64,
temp_right: f64,
heat_source_per_vol: f64,
flow_velocity: f64,
fluid_density: f64,
peclet_number: f64,
}

#[derive(Debug)]
enum SimulationError {
InvalidInput(String),
MatrixSolveError(String),
}

impl fmt::Display for SimulationError {


fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SimulationError::InvalidInput(msg) => write!(f, "Invalid input: {}",
msg),
SimulationError::MatrixSolveError(msg) => write!(f, "Matrix solution
error: {}", msg),
}
}
}

impl Error for SimulationError {}

fn validate_inputs(params: &SimulationParameters) -> Result<(), SimulationError> {


if params.cond <= 0.0
|| params.cp <= 0.0
|| params.area <= 0.0
|| params.length <= 0.0
|| params.fluid_density <= 0.0
{
return Err(SimulationError::InvalidInput(
"Physical parameters must be positive.".to_string(),
));
}
if params.n_cells < 20 {
println!("Warning: Low cell count ({}) may affect
accuracy.",params.n_cells)
}

let dx = params.length / params.n_cells as f64;


let pe = (params.fluid_density * params.flow_velocity * dx) / (2.0 *
params.cond);
if pe.abs() > 2.0 {
println!("Warning: Peclet number ({:.2}) > 2 may cause numerical
instability.",pe);
}
Ok(())
}

fn generate_mesh(params: &SimulationParameters) -> (Array1<f64>, Array1<f64>,


Array1<f64>) {
let n_cells = params.n_cells;
let x_faces = Array1::linspace(0.0, params.length, n_cells + 1);
let x_centroids = (x_faces.slice(1..) + x_faces.slice(..n_cells)) * 0.5;
let cell_length = x_faces.slice(1..) - x_faces.slice(..n_cells);
(x_faces, x_centroids, cell_length)
}

fn calculate_distances(x_centroids: &Array1<f64>, x_faces: &Array1<f64>) ->


Array1<f64> {
let n_cells = x_centroids.len();
let mut d_centroids = Array1::zeros(n_cells + 1);
d_centroids.slice_mut(1..n_cells).assign(& (x_centroids.slice(1..) -
x_centroids.slice(..n_cells -1)));
d_centroids[0] = 2.0 * (x_centroids[0] - x_faces[0]);
d_centroids[n_cells] = 2.0 * (x_faces[n_cells] - x_centroids[n_cells-1]);
d_centroids
}

fn assemble_matrix(
params: &SimulationParameters,
d_centroids: &Array1<f64>,
cell_length: &Array1<f64>
) -> (Array2<f64>, Array1<f64>) {

let n_cells = params.n_cells;


let da = params.area * params.cond / d_centroids;
let f = params.flow_velocity * params.fluid_density * params.area * params.cp;

let mut al = da.slice(..n_cells).to_owned() + 0.5 * f * Array1::ones(n_cells);


let mut ar = da.slice(1..).to_owned() - 0.5 * f * Array1::ones(n_cells);
al[0] = 0.0;
ar[n_cells-1] = 0.0;

let mut sp = Array1::zeros(n_cells);


sp[[0, n_cells - 1]] = [-2.0 * da[0] - f, -2.0 * da[n_cells] + f];
let ap = &al + &ar - &sp;

let mut su = params.heat_source_per_vol * cell_length * params.area;

su[0] += (2.0 * da[0] + f) * params.temp_left;


su[n_cells-1] += (2.0 * da[n_cells] - f) * params.temp_right;

let mut a = Array2::zeros((n_cells, n_cells));


for i in 0..n_cells {
if i > 0 {
a[[i, i - 1]] = -al[i];
}
a[[i, i]] = ap[i];
if i < n_cells - 1 {
a[[i, i + 1]] = -ar[i+1];
}
}
(a, su)
}

fn solve_system(a: &Array2<f64>, su: &Array1<f64>) -> Result<Array1<f64>,


SimulationError> {
let result = match ndarray_linalg::solve(a, su) {
Ok(x) => x,
Err(err) => {
return Err(SimulationError::MatrixSolveError(format!(
"Failed to solve the linear system: {}", err
)))
}
};
Ok(result)
}

fn print_setup_data(params: &SimulationParameters,a: &Array2<f64>, su:


&Array1<f64>)
{
println!("==========================================");
println!("Simulation Parameters:");
println!("==========================================");
println!(" Thermal Conductivity (cond): {}", params.cond);
println!(" Specific Heat Capacity (cp): {}", params.cp);
println!(" Cross-sectional Area (area): {}", params.area);
println!(" Length of the channel (length): {}", params.length);
println!(" Number of cells (n_cells): {}", params.n_cells);
println!(" Left Temperature (temp_left): {}", params.temp_left);
println!(" Right Temperature (temp_right): {}", params.temp_right);
println!(" Heat Source per Volume: {}", params.heat_source_per_vol);
println!(" Flow Velocity (flow_velocity): {}", params.flow_velocity);
println!(" Fluid Density (fluid_density): {}", params.fluid_density);
println!(" Peclet Number (Pe): {:.2}", params.peclet_number);
println!("==========================================");
println!("Matrix A:");
println!("{}", a);
println!("==========================================");
println!("Source Vector (Su):");
println!("{}", su);
println!("==========================================");
}

fn print_solution(t_vector: &Array1<f64>)
{
println!("==========================================");
println!("Temperature Vector (T):");
println!("{}", t_vector);
println!("==========================================");
}
#[cfg(feature = "plot")]
fn plot_solution(
x: &Array1<f64>,
t: &Array1<f64>,
params: &SimulationParameters,
) -> Result<(), Box<dyn Error>> {
let mut fg = Figure::new();
{
let axes: Axes2D = fg.axes2d();
axes.lines(
x.as_slice().unwrap(),
t.as_slice().unwrap(),
&[PlotOption::Caption("Numerical Solution"),
PlotOption::Color("blue")],
);
axes.set_x_label("Position (m)");
axes.set_y_label("Temperature (°C)");
axes.set_title(&format!("1D Convection-Diffusion (Pe =
{:.2})",params.peclet_number));
}
fg.show()
}

fn main() -> Result<(), Box<dyn Error>> {


let cli = Cli::parse();

let params = SimulationParameters {


cond: cli.cond,
cp: cli.cp,
area: cli.area,
length: cli.length,
n_cells: cli.n_cells,
temp_left: cli.temp_left,
temp_right: cli.temp_right,
heat_source_per_vol: cli.heat_source_per_vol,
flow_velocity: cli.flow_velocity,
fluid_density: cli.fluid_density,
peclet_number:0.0
};
let dx = params.length / params.n_cells as f64;
let mut params_with_pe = params.clone();
params_with_pe.peclet_number = (params.fluid_density * params.flow_velocity *
dx) / (2.0 * params.cond);

validate_inputs(&params_with_pe)?;

let (x_faces, x_centroids, cell_length) = generate_mesh(&params_with_pe);


let d_centroids = calculate_distances(&x_centroids, &x_faces);
let (a, su) = assemble_matrix(&params_with_pe, &d_centroids, &cell_length);
let start = Instant::now();
let t_vector = solve_system(&a, &su)?;
let duration = start.elapsed();
println!("Time taken to solve system: {:?}",duration);
if cli.print_setup {
print_setup_data(&params_with_pe, &a, &su);
}

if cli.print_solution {
print_solution(&t_vector);
}

if cli.plot {
let x_plot = Array1::from_iter(
std::iter::once(x_faces[0])
.chain(x_centroids.iter().copied())
.chain(std::iter::once(x_faces[x_faces.len() - 1]))
);
let t_plot = Array1::from_iter(
std::iter::once(params.temp_left)
.chain(t_vector.iter().copied())
.chain(std::iter::once(params.temp_right))
);
#[cfg(feature = "plot")]
plot_solution(&x_plot, &t_plot, &params_with_pe)?;
}

Ok(())
}

You might also like