diff --git a/fastsim-core/fastsim-proc-macros/src/serde_api/serde_utils.rs b/fastsim-core/fastsim-proc-macros/src/serde_api/serde_utils.rs index c6ed66f4..ffc6572c 100644 --- a/fastsim-core/fastsim-proc-macros/src/serde_api/serde_utils.rs +++ b/fastsim-core/fastsim-proc-macros/src/serde_api/serde_utils.rs @@ -362,8 +362,7 @@ pub(crate) fn serde_attrs_for_si_fields(field: &mut syn::Field) -> Option<()> { // Determine the canonical (serialization) unit and serialize_with path. // - // With no field-level override: use the first entry from quantity_config, - // except Ratio which preserves a legacy bare-name canonical serialization key. + // With no field-level override: use the first entry from quantity_config. // With `#[si_unit(name)]`: use the specified unit, constructing a serialize_with // path of the form `fastsim_core::utils::serde_helpers::{quantity_snake}_as_{unit}` // unless the unit is the SI base unit (first entry, no global serialize_with), @@ -408,10 +407,6 @@ pub(crate) fn serde_attrs_for_si_fields(field: &mut syn::Field) -> Option<()> { (override_name.clone(), serialize_with) } } - } else if quantity == "Ratio" { - // Legacy escape hatch: keep bare field names canonical for Ratio fields - // unless an explicit override is provided. - (String::new(), None) } else { let canonical = unit_impls .first() @@ -511,8 +506,12 @@ fn quantity_config(quantity: &str) -> Option<(Vec<(TokenStream2, String)>, Optio None, )), "Energy" => Some(( - extract_units!(uom::si::energy::joule, uom::si::energy::kilowatt_hour), - None, + extract_units!( + uom::si::energy::kilojoule, + uom::si::energy::kilowatt_hour, + uom::si::energy::joule + ), + Some("fastsim_core::utils::serde_helpers::energy_as_kilojoules"), )), // "EnergyDensity" => Some(( // vec![( @@ -558,33 +557,23 @@ fn quantity_config(quantity: &str) -> Option<(Vec<(TokenStream2, String)>, Optio extract_units!(uom::si::moment_of_inertia::kilogram_square_meter), None, )), - // First entry = canonical serialization unit. - // To serialize Power in kilowatts, move kilowatt to first and set serialize_with: - // "Power" => Some(( - // extract_units!( - // uom::si::power::kilowatt, - // uom::si::power::watt, - // uom::si::power::horsepower - // ), - // Some("fastsim_core::utils::serde_helpers::power_as_kilowatts"), - // )), "Power" => Some(( extract_units!( - uom::si::power::watt, uom::si::power::kilowatt, + uom::si::power::watt, uom::si::power::horsepower ), - None, + Some("fastsim_core::utils::serde_helpers::power_as_kilowatts"), )), "PowerRate" => Some((extract_units!(uom::si::power_rate::watt_per_second), None)), "Pressure" => Some(( extract_units!( - uom::si::pressure::pascal, uom::si::pressure::kilopascal, + uom::si::pressure::pascal, uom::si::pressure::bar, uom::si::pressure::pound_force_per_square_inch ), - None, + Some("fastsim_core::utils::serde_helpers::pressure_as_kilopascals"), )), "Ratio" => Some(( extract_units!(uom::si::ratio::ratio, uom::si::ratio::percent), @@ -595,44 +584,47 @@ fn quantity_config(quantity: &str) -> Option<(Vec<(TokenStream2, String)>, Optio // as custom uom units (not present upstream). extract_custom_units! takes // ("path", "name") string literals because the proc-macro binary cannot link // against downstream crates to call Unit::plural(). - let mut units = extract_units!( - uom::si::available_energy::joule_per_kilogram, - uom::si::available_energy::kilojoule_per_kilogram - ); - units.extend(extract_custom_units!( - ( - "fastsim_core::si::watt_hour_per_kilogram", - "watt_hours_per_kilogram" - ), + let mut units = extract_custom_units!( ( "fastsim_core::si::kilowatt_hour_per_kilogram", "kilowatt_hours_per_kilogram" + ), + ( + "fastsim_core::si::watt_hour_per_kilogram", + "watt_hours_per_kilogram" ) + ); + units.extend(extract_units!( + uom::si::available_energy::kilojoule_per_kilogram, + uom::si::available_energy::joule_per_kilogram )); - Some((units, None)) + Some(( + units, + Some("fastsim_core::utils::serde_helpers::specific_energy_as_kilowatt_hours_per_kilogram"), + )) } "SpecificPower" => Some(( extract_units!( - uom::si::specific_power::watt_per_kilogram, - uom::si::specific_power::kilowatt_per_kilogram + uom::si::specific_power::kilowatt_per_kilogram, + uom::si::specific_power::watt_per_kilogram ), - None, + Some("fastsim_core::utils::serde_helpers::specific_power_as_kilowatts_per_kilogram"), )), "Temperature" => Some(( extract_units!( - uom::si::thermodynamic_temperature::kelvin, uom::si::thermodynamic_temperature::degree_celsius, + uom::si::thermodynamic_temperature::kelvin, uom::si::thermodynamic_temperature::degree_fahrenheit ), - None, + Some("fastsim_core::utils::serde_helpers::temperature_as_degrees_celsius"), )), "TemperatureInterval" => Some(( extract_units!( - uom::si::temperature_interval::kelvin, uom::si::temperature_interval::degree_celsius, + uom::si::temperature_interval::kelvin, uom::si::temperature_interval::degree_fahrenheit ), - None, + Some("fastsim_core::utils::serde_helpers::temperature_interval_as_degrees_celsius"), )), "ThermalConductance" => Some(( extract_units!(uom::si::thermal_conductance::watt_per_kelvin), @@ -784,11 +776,8 @@ pub fn generate_helper_struct( // Field-unit is canonical by default, with bare-field aliasing for the // SI base unit. A field-level `#[si_unit(unitless)]` override switches // canonical naming to bare field for the base unit. - // Legacy escape hatch: unannotated Ratio fields also serialize bare. - let ratio_escape_hatch = si_field.quantity == "Ratio"; - let use_bare_as_canonical = (si_field.unitless_canonical - || ratio_escape_hatch) - && idx == base_unit_idx; + let use_bare_as_canonical = + si_field.unitless_canonical && idx == base_unit_idx; let (canonical_name, unit_alias) = if use_bare_as_canonical { (bare_name.clone(), serde_key.clone()) } else { diff --git a/fastsim-core/src/drive_cycle.rs b/fastsim-core/src/drive_cycle.rs index 16191ebe..6fa96cee 100644 --- a/fastsim-core/src/drive_cycle.rs +++ b/fastsim-core/src/drive_cycle.rs @@ -31,6 +31,7 @@ pub struct Cycle { pub dist: Vec, /// road grade (expressed as a decimal, not percent) #[serde(default, skip_serializing_if = "Vec::is_empty")] + #[si_unit(percent)] pub grade: Vec, // TODO: consider trapezoidal integration scheme // TODO: @mokeefe, please check out how elevation is handled @@ -1604,6 +1605,7 @@ pub struct CycleElement { // `dist` is not included here because it is derived in `Init::init` /// road grade #[serde(alias = "cycGrade")] + #[si_unit(percent)] pub grade: Option, // `elev` is not included here because it is derived in `Init::init` /// road charging/discharing capacity diff --git a/fastsim-core/src/utils/serde_helpers.rs b/fastsim-core/src/utils/serde_helpers.rs index dbf92932..c3ee6e04 100644 --- a/fastsim-core/src/utils/serde_helpers.rs +++ b/fastsim-core/src/utils/serde_helpers.rs @@ -41,4 +41,36 @@ #[allow(unused_imports)] use crate::si; +crate::impl_si_serialize_as!(energy_as_kilojoules, si::Energy, uom::si::energy::kilojoule); +crate::impl_si_serialize_as!( + energy_as_kilowatt_hours, + si::Energy, + crate::si::kilowatt_hour +); crate::impl_si_serialize_as!(power_as_kilowatts, si::Power, uom::si::power::kilowatt); +crate::impl_si_serialize_as!( + pressure_as_kilopascals, + si::Pressure, + uom::si::pressure::kilopascal +); +crate::impl_si_serialize_as!(ratio_as_percent, si::Ratio, uom::si::ratio::percent); +crate::impl_si_serialize_as!( + specific_energy_as_kilowatt_hours_per_kilogram, + si::SpecificEnergy, + crate::si::kilowatt_hour_per_kilogram +); +crate::impl_si_serialize_as!( + specific_power_as_kilowatts_per_kilogram, + si::SpecificPower, + crate::si::kilowatt_per_kilogram +); +crate::impl_si_serialize_as!( + temperature_as_degrees_celsius, + si::Temperature, + uom::si::thermodynamic_temperature::degree_celsius +); +crate::impl_si_serialize_as!( + temperature_interval_as_degrees_celsius, + si::TemperatureInterval, + uom::si::temperature_interval::degree_celsius +); diff --git a/fastsim-core/src/vehicle/chassis.rs b/fastsim-core/src/vehicle/chassis.rs index 65e60c0b..9d0494f2 100755 --- a/fastsim-core/src/vehicle/chassis.rs +++ b/fastsim-core/src/vehicle/chassis.rs @@ -27,10 +27,12 @@ impl Init for DriveTypes {} /// Struct for simulating vehicle pub struct Chassis { /// Aerodynamic drag coefficient + #[si_unit(unitless)] pub drag_coef: si::Ratio, /// Projected frontal area for drag calculations pub frontal_area: si::Area, /// Wheel rolling resistance coefficient for the vehicle (i.e. all wheels included) + #[si_unit(unitless)] pub wheel_rr_coef: si::Ratio, /// Wheel inertia per wheel pub wheel_inertia: si::MomentOfInertia, @@ -45,6 +47,7 @@ pub struct Chassis { /// Vehicle center of mass height pub cg_height: si::Length, /// Wheel coefficient of friction + #[si_unit(unitless)] pub wheel_fric_coef: si::Ratio, /// Drive wheel configuration diff --git a/fastsim-core/src/vehicle/conv.rs b/fastsim-core/src/vehicle/conv.rs index 26ffcf1c..882a79ff 100644 --- a/fastsim-core/src/vehicle/conv.rs +++ b/fastsim-core/src/vehicle/conv.rs @@ -178,6 +178,7 @@ pub struct ConventionalVehicle { /// powertrain mass pub(crate) mass: Option, /// Alternator efficiency used to calculate aux mechanical power demand on engine + #[si_unit(percent)] pub alt_eff: si::Ratio, } diff --git a/fastsim-core/src/vehicle/hev.rs b/fastsim-core/src/vehicle/hev.rs index 8c9ee7cf..c89a754e 100644 --- a/fastsim-core/src/vehicle/hev.rs +++ b/fastsim-core/src/vehicle/hev.rs @@ -575,6 +575,7 @@ pub struct RGWDBState { /// SOC is below min buffer so FC is charging RES pub charging_for_low_soc: TrackedState, /// buffer at which FC is forced on + #[si_unit(percent)] pub soc_fc_on_buffer: TrackedState, } impl SerdeAPI for RGWDBState {} @@ -865,17 +866,20 @@ pub struct RESGreedyWithDynamicBuffers { /// vehicle at this speed that triggers ramp down in RES discharge. pub speed_soc_disch_buffer: Option, /// Coefficient for modifying amount of accel buffer + #[si_unit(percent)] pub speed_soc_disch_buffer_coeff: Option, /// RES energy delta from minimum SOC corresponding to kinetic energy of /// vehicle at this speed that triggers FC to be forced on. pub speed_soc_fc_on_buffer: Option, /// Coefficient for modifying amount of [Self::speed_soc_fc_on_buffer] + #[si_unit(percent)] pub speed_soc_fc_on_buffer_coeff: Option, /// RES energy delta from maximum SOC corresponding to kinetic energy of /// vehicle at current speed minus kinetic energy of vehicle at this speed /// triggers ramp down in RES discharge pub speed_soc_regen_buffer: Option, /// Coefficient for modifying amount of regen buffer + #[si_unit(percent)] pub speed_soc_regen_buffer_coeff: Option, /// Minimum time engine must remain on if it was on during the previous /// simulation time step. @@ -1268,6 +1272,7 @@ pub struct HEVStartStopControl { pub fc_min_time_on: Option, /// The range of usable SOC of the storage system below which the /// [FuelConverter] is forced on. + #[si_unit(percent)] pub soc_fc_forced_on: Option, /// Force engine, if on, to run at this fraction of power at which peak /// efficiency occurs or the required power, whichever is greater. If SOC is diff --git a/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin.rs b/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin.rs index 73c4e98b..b038950e 100644 --- a/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin.rs +++ b/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin.rs @@ -523,6 +523,7 @@ pub struct HVACSystemForLumpedCabinState { /// portion of total HVAC cooling/heating (negative/positive) cumulative energy due to derivative gain pub energy_d: TrackedState, /// coefficient of performance (i.e. efficiency) of vapor compression cycle + #[si_unit(unitless)] pub cop: TrackedState>, /// Aux power demand from [Vehicle::hvac] system pub pwr_aux_for_hvac: TrackedState, diff --git a/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin_and_res.rs b/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin_and_res.rs index f1285c93..7dcdf440 100644 --- a/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin_and_res.rs +++ b/fastsim-core/src/vehicle/hvac/hvac_sys_for_lumped_cabin_and_res.rs @@ -1200,6 +1200,7 @@ pub struct HVACSystemForLumpedCabinAndRESState { /// to [ReversibleEnergyStorage::thrml] due to derivative gain pub energy_d_res: TrackedState, /// coefficient of performance (i.e. efficiency) of vapor compression cycle + #[si_unit(unitless)] pub cop: TrackedState>, /// Reference temperature used to calculate coefficient of performance (i.e. /// efficiency) of vapor compression cycle diff --git a/fastsim-core/src/vehicle/powertrain/electric_machine.rs b/fastsim-core/src/vehicle/powertrain/electric_machine.rs index f8a06515..c2e6e541 100755 --- a/fastsim-core/src/vehicle/powertrain/electric_machine.rs +++ b/fastsim-core/src/vehicle/powertrain/electric_machine.rs @@ -877,15 +877,18 @@ pub struct ElectricMachineState { /// time step index pub i: TrackedState, /// Component efficiency based on current power demand. + #[si_unit(percent)] pub eff: TrackedState, // Component limits /// Maximum possible positive traction power. pub pwr_mech_fwd_out_max: TrackedState, /// efficiency in forward direction at max possible input power from `FuelConverter` and `ReversibleEnergyStorage` + #[si_unit(percent)] pub eff_fwd_at_max_input: TrackedState, /// Maximum possible regeneration power going to ReversibleEnergyStorage. pub pwr_mech_regen_max: TrackedState, /// efficiency in backward direction at max possible input power from `FuelConverter` and `ReversibleEnergyStorage` + #[si_unit(percent)] pub eff_at_max_regen: TrackedState, // Current values diff --git a/fastsim-core/src/vehicle/powertrain/fuel_converter.rs b/fastsim-core/src/vehicle/powertrain/fuel_converter.rs index d40ce51a..9da012dd 100755 --- a/fastsim-core/src/vehicle/powertrain/fuel_converter.rs +++ b/fastsim-core/src/vehicle/powertrain/fuel_converter.rs @@ -567,6 +567,7 @@ pub struct FuelConverterState { /// max propulsion power fc can produce at current time pub pwr_prop_max: TrackedState, /// efficiency evaluated at current demand + #[si_unit(percent)] pub eff: TrackedState, /// instantaneous power going to drivetrain, not including aux pub pwr_prop: TrackedState, @@ -1152,6 +1153,7 @@ pub struct FuelConverterThermalState { /// Cumulative heat transfer energy to ambient pub energy_thrml_to_amb: TrackedState, /// Efficency coefficient, used to modify [FuelConverter] effciency based on temperature + #[si_unit(percent)] pub eff_coeff: TrackedState, /// Thermal power flowing from fuel converter to cabin pub pwr_thrml_fc_to_cab: TrackedState, diff --git a/fastsim-core/src/vehicle/powertrain/fuel_storage.rs b/fastsim-core/src/vehicle/powertrain/fuel_storage.rs index f422bf28..84db919f 100644 --- a/fastsim-core/src/vehicle/powertrain/fuel_storage.rs +++ b/fastsim-core/src/vehicle/powertrain/fuel_storage.rs @@ -21,6 +21,7 @@ pub struct FuelStorage { #[serde(default)] pub fuel_type: Option, /// energy capacity + #[si_unit(kilowatt_hours)] pub energy_capacity: si::Energy, /// Fuel and tank specific energy pub(crate) specific_energy: Option, diff --git a/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs b/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs index cd9c005f..2a6caaed 100644 --- a/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs +++ b/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs @@ -27,14 +27,17 @@ pub struct ReversibleEnergyStorage { pub pwr_out_max: si::Power, /// Total energy capacity of battery of full discharge SOC of 0.0 and 1.0 + #[si_unit(kilowatt_hours)] pub energy_capacity: si::Energy, /// interpolator for calculating [Self] efficiency pub eff_interp: RESEfficiency, /// Hard limit on minimum SOC, e.g. 0.05 + #[si_unit(percent)] pub min_soc: si::Ratio, /// Hard limit on maximum SOC, e.g. 0.95 + #[si_unit(percent)] pub max_soc: si::Ratio, /// struct for tracking current state #[serde(default)] @@ -889,17 +892,22 @@ pub struct ReversibleEnergyStorageState { pub i: TrackedState, /// state of charge (SOC) + #[si_unit(percent)] pub soc: TrackedState, /// SOC at which [ReversibleEnergyStorage] regen power begins linearly /// derating as it approaches maximum SOC + #[si_unit(percent)] pub soc_regen_buffer: TrackedState, /// SOC at which [ReversibleEnergyStorage] discharge power begins linearly /// derating as it approaches minimum SOC + #[si_unit(percent)] pub soc_disch_buffer: TrackedState, /// Chemical <-> Electrical conversion efficiency based on current power demand + #[si_unit(percent)] pub eff: TrackedState, /// State of Health (SOH) - pub soh: TrackedState, + #[si_unit(percent)] + pub soh: TrackedState, // TODO: add `pwr_out_neg_electrical` and `pwr_out_pos_electrical` and corresponding energies // powers to separately pin negative- and positive-power operation diff --git a/fastsim-core/src/vehicle/powertrain/transmission.rs b/fastsim-core/src/vehicle/powertrain/transmission.rs index 930eca77..3224b420 100644 --- a/fastsim-core/src/vehicle/powertrain/transmission.rs +++ b/fastsim-core/src/vehicle/powertrain/transmission.rs @@ -225,6 +225,7 @@ pub struct TransmissionState { pub pwr_out_regen_max: TrackedState, /// efficiency at current time step + #[si_unit(percent)] pub eff: TrackedState, /// Power at output side of transmission. Positive indicates forward power diff --git a/fastsim-core/src/vehicle/vehicle_model.rs b/fastsim-core/src/vehicle/vehicle_model.rs index e0169959..9fd50b86 100644 --- a/fastsim-core/src/vehicle/vehicle_model.rs +++ b/fastsim-core/src/vehicle/vehicle_model.rs @@ -1361,6 +1361,7 @@ pub struct VehicleState { /// cumulative distance traveled, integral of [Self::speed_ach] pub dist: TrackedState, /// current grade + #[si_unit(percent)] pub grade_curr: TrackedState, /// current grade // will be overridden during simulation anyway diff --git a/fastsim-core/tests/test_serde_api_integration.rs b/fastsim-core/tests/test_serde_api_integration.rs index 51744455..ef54af57 100644 --- a/fastsim-core/tests/test_serde_api_integration.rs +++ b/fastsim-core/tests/test_serde_api_integration.rs @@ -294,16 +294,16 @@ fn test_serialize_uses_prescribed_units() { serde_json::from_str(&serialized).expect("Failed to parse serialized JSON"); assert!(value.get("mass_kilograms").is_some()); - assert!(value.get("power_watts").is_some()); + assert!(value.get("power_kilowatts").is_some()); assert!(value.get("speed_meters_per_second").is_some()); assert!(value.get("duration_seconds").is_some()); assert!(value.get("area_square_meters").is_some()); - assert!(value.get("temperature_kelvin").is_some()); - assert!(value.get("energy_joules").is_some()); + assert!(value.get("temperature_degrees_celsius").is_some()); + assert!(value.get("energy_kilojoules").is_some()); assert!(value.get("efficiency").is_some()); // Ratio: bare name - assert!(value.get("tracked_power_watts").is_some()); + assert!(value.get("tracked_power_kilowatts").is_some()); assert!(value.get("tracked_efficiency").is_some()); // Ratio: bare name - assert!(value.get("renamed_power_watts").is_some()); + assert!(value.get("renamed_power_kilowatts").is_some()); } #[test] @@ -330,14 +330,15 @@ fn test_round_trip_conversion_preserves_values() { let value: serde_json::Value = serde_json::from_str(&serialized).expect("Failed to parse serialized JSON"); - // Values are preserved through round-trip (in primary units) + // Values are preserved through round-trip (in canonical serialized units) assert_eq!(value["mass_kilograms"], 2000.0); - assert_eq!(value["power_watts"], 150.0); + assert_eq!(value["power_kilowatts"], 0.15); assert_eq!(value["speed_meters_per_second"], 30.0); assert_eq!(value["duration_seconds"], 3600.0); assert_eq!(value["area_square_meters"], 5.0); - assert_eq!(value["temperature_kelvin"], 300.0); - assert_eq!(value["energy_joules"], 1000.0); + let temp_c = value["temperature_degrees_celsius"].as_f64().unwrap(); + assert!((temp_c - 26.85).abs() < 1e-9); + assert_eq!(value["energy_kilojoules"], 1.0); assert_eq!(value["efficiency"], 0.85); // Ratio: bare name } @@ -797,8 +798,8 @@ const SE_BASE: &str = r#"{ }"#; #[test] -fn test_specific_energy_serializes_as_joules_per_kilogram() { - // Primary serialization key for SpecificEnergy is joules_per_kilogram. +fn test_specific_energy_serializes_as_kilowatt_hours_per_kilogram() { + // Primary serialization key for SpecificEnergy is kilowatt_hours_per_kilogram. let json = SE_BASE.replace( "}", r#", "specific_energy_watt_hours_per_kilogram": 100.0}"#, @@ -807,14 +808,14 @@ fn test_specific_energy_serializes_as_joules_per_kilogram() { let serialized = serde_json::to_string(&device).unwrap(); let value: serde_json::Value = serde_json::from_str(&serialized).unwrap(); assert!( - value.get("specific_energy_joules_per_kilogram").is_some(), - "expected specific_energy_joules_per_kilogram in serialized output; got: {serialized}" + value.get("specific_energy_kilowatt_hours_per_kilogram").is_some(), + "expected specific_energy_kilowatt_hours_per_kilogram in serialized output; got: {serialized}" ); - // 100 Wh/kg = 360 000 J/kg - let stored = value["specific_energy_joules_per_kilogram"] + // 100 Wh/kg = 0.1 kWh/kg + let stored = value["specific_energy_kilowatt_hours_per_kilogram"] .as_f64() .unwrap(); - assert!((stored - 360_000.0).abs() < 1.0); + assert!((stored - 0.1).abs() < 1e-12); } #[test] @@ -908,10 +909,10 @@ fn test_si_unit_unitless_override_changes_ratio_canonical_name() { assert!(value.get("alt_eff_ratio").is_none()); assert!(value.get("cop_ratio").is_none()); - // Ratio escape hatch: unannotated ratio fields also serialize bare. + // With Ratio escape hatch disabled, unannotated ratio fields serialize with suffix. assert!( - value.get("grade").is_some(), - "expected bare grade in {json}" + value.get("grade_ratio").is_some(), + "expected grade_ratio in {json}" ); - assert!(value.get("grade_ratio").is_none()); + assert!(value.get("grade").is_none()); } diff --git a/pyproject.toml b/pyproject.toml index 88353a3b..a6328a69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,15 +63,6 @@ dev = [ "deepdiff>=8.4.2", ] -[tool.setuptools] -zip-safe = false - -[tool.setuptools.packages.find] -include = [ - "fastsim*", -] # package names should match these glob patterns (["*"] by default) -namespaces = false # to disable scanning PEP 420 namespaces (true by default) - [tool.maturin] profile = "release" python-source = "python"