stem_material 0.3.4

Material definition for stem - a Simulation Toolbox for Electric Motors.
Documentation
use indoc::indoc;
use stem_material::prelude::unary::Linear;
use stem_material::prelude::*;

#[test]
fn test_serialize_material() {
    let mut material = Material::default();

    let linear = Linear::new(
        DynQuantity::new(
            2.0,
            Unit::from(PredefUnit::MagneticFluxDensity) / Unit::from(PredefUnit::Temperature),
        ),
        DynQuantity::new(1.0, PredefUnit::MagneticFluxDensity),
    );
    material.set_remanence(VarQuantity::try_from_quantity_function(linear).unwrap());
    material.set_intrinsic_coercivity(VarQuantity::Constant(MagneticFieldStrength::new::<
        ampere_per_meter,
    >(5.0)));

    let string = serde_yaml::to_string(&material).unwrap();
    let material: Material = serde_yaml::from_str(&string).unwrap();

    let conditions = [ThermodynamicTemperature::new::<degree_celsius>(20.0).into()];

    assert_eq!(material.remanence().get(&conditions).get::<tesla>(), 587.3);
    assert_eq!(
        material
            .intrinsic_coercivity()
            .get(&conditions)
            .get::<ampere_per_meter>(),
        5.0
    );
}

#[test]
fn test_deserialize_material() {
    // Property thermal_conductivity is purposefully missing
    let serialized = indoc! {"
    ---
    name: M800-50A
    relative_permeability:
      FerromagneticPermeability:
        field_strength: '[
              0.0, 130.0, 141.0, 153.0, 166.0, 181.0, 198.0, 221.0, 252.0, 304.0, 409.0, 680.0, 1540.0,
              3789.0, 7752.0, 13730.0
              ] A/m'
        flux_density: '[
              0.0, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9
              ] T'
        iron_fill_factor: 0.95
    remanence: 0.0 T
    iron_losses:
      JordanModel:
        - frequency: 50.0 Hz
          characteristic:
            - flux_density: 0.5 T
              specific_loss: 0.86 W/kg
            - flux_density: 0.6 T
              specific_loss: 1.16 W/kg
            - flux_density: 0.7 T
              specific_loss: 1.47 W/kg
            - flux_density: 0.8 T
              specific_loss: 1.82 W/kg
            - flux_density: 0.9 T
              specific_loss: 2.2 W/kg
            - flux_density: 1.0 T
              specific_loss: 2.6 W/kg
            - flux_density: 1.1 T
              specific_loss: 3.06 W/kg
            - flux_density: 1.2 T
              specific_loss: 3.57 W/kg
            - flux_density: 1.3 T
              specific_loss: 4.14 W/kg
            - flux_density: 1.4 T
              specific_loss: 4.79 W/kg
            - flux_density: 1.5 T
              specific_loss: 5.52 W/kg
            - flux_density: 1.6 T
              specific_loss: 6.37 W/kg
            - flux_density: 1.7 T
              specific_loss: 7.08 W/kg
            - flux_density: 1.8 T
              specific_loss: 7.65 W/kg
            - flux_density: 1.9 T
              specific_loss: 8.12 W/kg
        - frequency: 100.0 Hz
          characteristic:
            - flux_density: 0.5 T
              specific_loss: 1.93 W/kg
            - flux_density: 0.6 T
              specific_loss: 2.62 W/kg
            - flux_density: 0.7 T
              specific_loss: 3.38 W/kg
            - flux_density: 0.8 T
              specific_loss: 4.22 W/kg
            - flux_density: 0.9 T
              specific_loss: 5.15 W/kg
            - flux_density: 1.0 T
              specific_loss: 6.19 W/kg
            - flux_density: 1.1 T
              specific_loss: 7.34 W/kg
            - flux_density: 1.2 T
              specific_loss: 8.65 W/kg
            - flux_density: 1.3 T
              specific_loss: 10.11 W/kg
            - flux_density: 1.4 T
              specific_loss: 11.74 W/kg
            - flux_density: 1.5 T
              specific_loss: 13.56 W/kg
        - frequency: 200.0 Hz
          characteristic:
            - flux_density: 0.5 T
              specific_loss: 4.63 W/kg
            - flux_density: 0.6 T
              specific_loss: 6.37 W/kg
            - flux_density: 0.7 T
              specific_loss: 8.35 W/kg
            - flux_density: 0.8 T
              specific_loss: 10.59 W/kg
            - flux_density: 0.9 T
              specific_loss: 13.2 W/kg
            - flux_density: 1.0 T
              specific_loss: 16.15 W/kg
            - flux_density: 1.1 T
              specific_loss: 19.31 W/kg
            - flux_density: 1.2 T
              specific_loss: 23.08 W/kg
            - flux_density: 1.3 T
              specific_loss: 27.24 W/kg
            - flux_density: 1.4 T
              specific_loss: 32.42 W/kg
            - flux_density: 1.5 T
              specific_loss: 37.56 W/kg
    intrinsic_coercivity: 5.0 A/m
    mass_density: 7650.0 kg / m^3
    electrical_resistivity:
      FirstOrderTaylor:
        base_value: 1 / 56 m/MS
        expansion_point: 20 °C
        slope: 0.393 % / K
    heat_capacity: 435.0 J / kg / K
    "};
    let material: Material = serde_yaml::from_str(&serialized).unwrap();

    let conditions = &[MagneticFluxDensity::new::<tesla>(0.5).into()];
    approx::assert_abs_diff_eq!(
        material.relative_permeability().get(conditions),
        3801.0,
        epsilon = 0.1
    );
    approx::assert_abs_diff_eq!(
        material
            .mass_density()
            .get(conditions)
            .get::<kilogram_per_cubic_meter>(),
        7650.0
    );

    approx::assert_abs_diff_eq!(
        material
            .electrical_resistivity()
            .get(conditions)
            .get::<ohm_meter>(),
        1.7857e-8,
        epsilon = 1e-12
    );

    let conditions = &[ThermodynamicTemperature::new::<degree_celsius>(120.0).into()];
    approx::assert_abs_diff_eq!(
        material
            .electrical_resistivity()
            .get(conditions)
            .get::<ohm_meter>(),
        2.4875e-8,
        epsilon = 1e-12
    );

    if let RelativePermeability::FerromagneticPermeability(model) = &material.relative_permeability
    {
        approx::assert_abs_diff_eq!(
            model.get(MagneticFluxDensity::new::<tesla>(0.5)),
            3801.0,
            epsilon = 0.1
        );
    } else {
        panic!("wrong model");
    }

    if let IronLosses::JordanModel(model) = &material.iron_losses {
        approx::assert_abs_diff_eq!(
            model.eddy_current_coefficient.get::<watt_per_kilogram>(),
            1.246,
            epsilon = 0.001
        );
        approx::assert_abs_diff_eq!(
            model.hysteresis_coefficient.get::<watt_per_kilogram>(),
            4.248,
            epsilon = 0.001
        );
    } else {
        panic!("wrong model");
    }
}

#[test]
fn test_serialize_and_deserialize_with_units() {
    let material = Material::default();
    let expected = indoc::indoc! {"
        ---
        name: default_name
        relative_permeability: 1.0
        iron_losses: 0 s^-3 m^2
        remanence: 0 s^-2 kg A^-1
        intrinsic_coercivity: 0 m^-1 A
        electrical_resistivity: inf s^-3 m^3 kg A^-2
        mass_density: 1000 m^-3 kg
        heat_capacity: 0 s^-2 m^2 K^-1
        thermal_conductivity: 0 s^-3 m kg K^-1
        "};
    let actual =
        serialize_with_units(|| serde_yaml::to_string(&material)).expect("serialization succeeds");
    assert_eq!(expected, actual);

    let de_material: Material = serde_yaml::from_str(&actual).expect("deserialization succeeds");
    assert_eq!(material, de_material);
}