/*!
# **kalast**

Thermophysical model for binary systems of asteroids.

## Using **kalast**

You will need the last stable build of the [rust compiler](https://www.rust-lang.org)
and the official package manager: [cargo](https://github.com/rust-lang/cargo).

Simply add the following to your `Cargo.toml` file:

```.ignore
[dependencies]
kalast = "0.1.9"
```

Useful functionalities of **kalast** are grouped in the root module `kalast::`.

## **kalast** in action

```
use kalast::{
    BinarySystem, EnvironmentSystem, Properties, Time, World, ASTRONAUMICAL_UNIT, DAY, HOUR,
    MINUTE, V3, YEAR,
};

// Two spheres to test case the mutual heating.
let mut binary_system = BinarySystem::new(
    "Didymos system",
    V3::new(0.0, 1.0, 0.0) * ASTRONAUMICAL_UNIT * 1.664,
)
.with_primary(
    "rsc/obj/sphere.obj",
    Properties::new(
        1.0 * YEAR, // rotation period
        2.7 * HOUR, // revolution period
        0.0,        // obliquity
        100.0,      // thermal inertia
        2146.0,     // density
        600.0,      // heat capacity
        0.1,        // albedo
        0.9,        // emissivity
    ),
)
.with_secondary(
    "rsc/obj/sphere.obj",
    Properties::new(
        11.92 * HOUR, // rotation period
        11.92 * HOUR, // revolution period
        0.0,          // obliquity 162.0 * TAU / 360.
        500.0,        // thermal inertia
        2146.0,       // density
        600.0,        // heat capacity
        0.07,         // albedo
        0.9,          // emissivity
    ),
    -V3::new(1.0, 0.0, 0.0) * 1.5e3, // relative position
);

binary_system.complete_model(true);
binary_system.set_target_secondary(true);
binary_system.primary_mut().fixed(true);
binary_system.secondary_mut().fixed(true);

// Time
let time = Time::new(10.0 * DAY, 30.0 * MINUTE);

// World
let mut world = World::new(time, binary_system);
world.start();
world.save("rsc/data/tmp.txt");

println!(
    "min: {:.2}, max: {:.2}",
    world.environment_system.body().surface_temperatures().min(),
    world.environment_system.body().surface_temperatures().max()
);
```

You can also read other [examples](https://gitlab-as.oma.be/gregoireh/kalast/-/tree/main/examples).

## Features

**kalast** is meant for binary system of asteroids surface thermophysical modelling. The physics of this engine includes these features:

+ custom shape model
+ celestial body revolution
+ compute surface temperatures from solar flux
+ ground 1D heat transfert conduction
+ celestial body mask view (example only equator)
+ mutual heating from primary/moon
+ self heating
+ TODO: 3D conduction / FEM
+ TODO: mutual occultations
+ TODO: shadowing

## Explore

If your want to explore the documentation, you can visite these pages:

+ [`Object3D`]: parse 3D object file and compute atributes of faces (centers, normals, ...)
+ [`Body`]: the representation for a celestial body
+ [`BinarySystem`]: the environment system for binary system of asteroids
+ [`World`]: the simulation manager
+ [`Properties`]: all the properties to characterise a body
*/

extern crate alga;
extern crate indicatif;
#[macro_use]
extern crate itertools;
extern crate log;
extern crate nalgebra as na;
extern crate num_traits;
extern crate obj;
extern crate simplelog;

/// Base features.
pub mod base;
/// Collection of generic functions for math, physics, matrix operations, or for the usage of other
/// crates.
#[macro_use]
pub mod toolbox;
/// Bindings to matplotlib.
#[macro_use]
pub mod matplotlib;

use alga::general::RingCommutative;
use na::Scalar;
use na::{
    DVector, Dynamic, Matrix, Matrix3, Matrix3x1, Matrix3xX, SliceStorage, SliceStorageMut,
    VecStorage, U1, U10,
};
use num_traits::{NumCast, ToPrimitive};
use std::cmp::PartialOrd;

pub use crate::base::*;
pub use crate::matplotlib::*;
pub use crate::toolbox::*;

/// Type alias for [`Matrix3x1`]. The matrix has a fixed number of rows (3) and a fixed number of
/// columns (1).
pub type V3<T> = Matrix3x1<T>;

/// Type alias for [`DVector`]. The matrix is a vector of X columns.
pub type VX<T> = DVector<T>;

/// Type alias for [`Matrix3xX`]. The matrix has a fixed number of rows (3) and a dynamical number
/// of columns.
pub type V3X<T> = Matrix3xX<T>;

/// Type alias for [`Matrix3`]. The matrix has a fixed number of rows (3) and a fixed number of
/// columns (3).
pub type M3<T> = Matrix3<T>;

/// Type alias for [`Object3D`]. The matrix has a fixed number of rows (10) and a dynamical number
/// of columns.
pub type Matrix10xX<T> = Matrix<T, U10, Dynamic, VecStorage<T, U10, Dynamic>>;

/// Type alias for [`Object3D`]. The slice matrix has a fixed number of rows (10) and a fixed
/// number of columns (1).
pub type MatrixSlice10x1<'a, T, RStride = U1, CStride = U10> =
    Matrix<T, U10, U1, SliceStorage<'a, T, U10, U1, RStride, CStride>>;

/// Type alias for [`Object3D`]. The mutable slice matrix has a fixed number of rows (10) and a
/// fixed number of columns (1).
pub type MatrixSliceMut10x1<'a, T, RStride = U1, CStride = U10> =
    Matrix<T, U10, U1, SliceStorageMut<'a, T, U10, U1, RStride, CStride>>;

/// Trait that extends [`Scalar`] to create integer matrices like float matrices. It aims to be the
/// equivalent of [`RealField`][nalgebra::RealField] but for integer.
pub trait SuperScalar:
    Scalar + RingCommutative + PartialOrd + std::ops::Div + ToPrimitive + NumCast + Copy
{
}

impl<T> SuperScalar for T where
    T: Scalar + RingCommutative + PartialOrd + std::ops::Div + ToPrimitive + NumCast + Copy
{
}
