diff --git a/Cargo.lock b/Cargo.lock index 447740505..2a3b1919b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1672,7 +1672,6 @@ dependencies = [ "clap", "colored", "derive_builder 0.20.0", - "either", "fnv", "getrandom", "log", @@ -1794,7 +1793,6 @@ version = "0.1.0" dependencies = [ "anyhow", "displaydoc", - "either", "log", "necsim-core", "necsim-core-bond", diff --git a/docs/simulate.ron b/docs/simulate.ron index d40aae811..2dc0e048d 100644 --- a/docs/simulate.ron +++ b/docs/simulate.ron @@ -280,6 +280,33 @@ tail_p: (0.0 < f64), ) ), + /* downscale the habitat to consider adjacent locations to be part + * of the same larger deme + * downscaling reduces the accuracy of the simulation but may speed + * up its execution with EventSkipping algorithm + * downscaling may be worth during the tail of the simulation, when + * few lineages remain, the speciation probability is low, and + * waiting for all lineages to speciate or coalesce dominates + * simulation times + * optional, default = None + * requires the `almost-infinite-downscaled-scenario` feature */ + downscale: ( + /* no downscaling is used */ + | None + /* downscale the habitat by separate dx and dy factors + * each of the 1/(dx*dy) habitable locations now has a deme of + * size dx*dy */ + | Downscale( + /* downscale factor along the x-axis of the habitat + * expressed either as a power-of-two integer + * or as a base-two scientific notation string */ + x: (u32 = 2^{1..=15}) or ("1B{1..=15}"), + /* downscale factor along the y-axis of the habitat + * expressed either as a power-of-two integer + * or as a base-two scientific notation string */ + y: (u32 = 2^{1..=15}) or ("1B{1..=15}"), + ) + ) ) /* (almost) infinite spatially-explicit scenario with (approximate) Gaussian distributed dispersal * each location (x, y) in the landscape has either habitat for exactly one individual, diff --git a/rustcoalescence/Cargo.toml b/rustcoalescence/Cargo.toml index a1553a3e5..2057aca57 100644 --- a/rustcoalescence/Cargo.toml +++ b/rustcoalescence/Cargo.toml @@ -24,15 +24,9 @@ almost-infinite-clark2dt-dispersal-scenario = [ "rustcoalescence-scenarios/almost-infinite-clark2dt-dispersal", "rustcoalescence-algorithms-cuda?/almost-infinite-clark2dt-dispersal-scenario", ] -almost-infinite-downscaled-normal-dispersal-scenario = [ - "rustcoalescence-scenarios/almost-infinite-normal-dispersal", - "rustcoalescence-scenarios/almost-infinite-downscaled", - "rustcoalescence-algorithms-cuda?/almost-infinite-downscaled-normal-dispersal-scenario", -] -almost-infinite-downscaled-clark2dt-dispersal-scenario = [ - "rustcoalescence-scenarios/almost-infinite-clark2dt-dispersal", +almost-infinite-downscaled-scenario = [ "rustcoalescence-scenarios/almost-infinite-downscaled", - "rustcoalescence-algorithms-cuda?/almost-infinite-downscaled-clark2dt-dispersal-scenario", + "rustcoalescence-algorithms-cuda?/almost-infinite-downscaled-scenario", ] non-spatial-scenario = [ "rustcoalescence-scenarios/non-spatial", @@ -58,8 +52,7 @@ wrapping-noise-scenario = [ all-scenarios = [ "almost-infinite-normal-dispersal-scenario", "almost-infinite-clark2dt-dispersal-scenario", - "almost-infinite-downscaled-normal-dispersal-scenario", - "almost-infinite-downscaled-clark2dt-dispersal-scenario", + "almost-infinite-downscaled-scenario", "non-spatial-scenario", "spatially-explicit-uniform-turnover-scenario", "spatially-explicit-turnover-map-scenario", @@ -111,4 +104,3 @@ tiny-keccak = { version = "2.0", features = ["keccak"] } derive_builder = "0.20" fnv = "1.0" adler = "1.0" -either = "1.10" diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 9e73991f5..4bf1eb22e 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -10,8 +10,7 @@ edition = "2021" [features] almost-infinite-normal-dispersal-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/almost-infinite-normal-dispersal-scenario"] almost-infinite-clark2dt-dispersal-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/almost-infinite-clark2dt-dispersal-scenario"] -almost-infinite-downscaled-normal-dispersal-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/almost-infinite-downscaled-normal-dispersal-scenario"] -almost-infinite-downscaled-clark2dt-dispersal-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/almost-infinite-downscaled-clark2dt-dispersal-scenario"] +almost-infinite-downscaled-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/almost-infinite-downscaled-scenario"] non-spatial-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/non-spatial-scenario"] spatially-explicit-uniform-turnover-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/spatially-explicit-uniform-turnover-scenario"] spatially-explicit-turnover-map-scenario = ["rustcoalescence-algorithms-cuda-cpu-kernel/spatially-explicit-turnover-map-scenario"] diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index bb9901810..bfe3586a5 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -10,8 +10,7 @@ edition = "2021" [features] almost-infinite-normal-dispersal-scenario = [] almost-infinite-clark2dt-dispersal-scenario = [] -almost-infinite-downscaled-normal-dispersal-scenario = [] -almost-infinite-downscaled-clark2dt-dispersal-scenario = [] +almost-infinite-downscaled-scenario = [] non-spatial-scenario = [] spatially-explicit-uniform-turnover-scenario = [] spatially-explicit-turnover-map-scenario = [] diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index c40203b84..1db971528 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -320,7 +320,10 @@ link_kernel!( necsim_impls_no_std::cogs::speciation_probability::uniform::UniformSpeciationProbability ); -#[cfg(feature = "almost-infinite-downscaled-normal-dispersal-scenario")] +#[cfg(all( + feature = "almost-infinite-normal-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", +))] link_kernel!( necsim_impls_no_std::cogs::habitat::almost_infinite::downscaled::AlmostInfiniteDownscaledHabitat< necsim_impls_cuda::cogs::maths::NvptxMathsCore @@ -347,7 +350,10 @@ link_kernel!( necsim_impls_no_std::cogs::speciation_probability::uniform::UniformSpeciationProbability ); -#[cfg(feature = "almost-infinite-downscaled-clark2dt-dispersal-scenario")] +#[cfg(all( + feature = "almost-infinite-clark2dt-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", +))] link_kernel!( necsim_impls_no_std::cogs::habitat::almost_infinite::downscaled::AlmostInfiniteDownscaledHabitat< necsim_impls_cuda::cogs::maths::NvptxMathsCore diff --git a/rustcoalescence/scenarios/Cargo.toml b/rustcoalescence/scenarios/Cargo.toml index 1a578f0f7..a2aedae2a 100644 --- a/rustcoalescence/scenarios/Cargo.toml +++ b/rustcoalescence/scenarios/Cargo.toml @@ -30,4 +30,3 @@ displaydoc = "0.2" log = "0.4" serde = { version = "1.0", features = ["derive"] } tiff = "0.9" -either = "1.10" diff --git a/rustcoalescence/scenarios/src/almost_infinite/downscaled.rs b/rustcoalescence/scenarios/src/almost_infinite/downscaled.rs index 48ae25732..9b7ebd8b9 100644 --- a/rustcoalescence/scenarios/src/almost_infinite/downscaled.rs +++ b/rustcoalescence/scenarios/src/almost_infinite/downscaled.rs @@ -32,6 +32,12 @@ pub struct AlmostInfiniteDownscaledScenario< _marker: PhantomData<(M, G, O)>, } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Downscale { + pub x: Log2U16, + pub y: Log2U16, +} + #[derive(Debug, Serialize, Deserialize)] #[allow(clippy::module_name_repetitions)] #[serde(rename = "AlmostInfiniteDownscaled")] @@ -39,8 +45,7 @@ pub struct AlmostInfiniteDownscaledScenario< pub struct AlmostInfiniteDownscaledArguments { #[serde(flatten)] pub args: O::Arguments, - pub downscale_x: Log2U16, - pub downscale_y: Log2U16, + pub downscale: Downscale, } impl< @@ -99,8 +104,8 @@ impl< let habitat = AlmostInfiniteDownscaledHabitat::new_with_habitat( habitat, - args.downscale_x, - args.downscale_y, + args.downscale.x, + args.downscale.y, ); let dispersal_sampler = AlmostInfiniteDownscaledDispersalSampler::new(&habitat, dispersal_sampler); diff --git a/rustcoalescence/scenarios/src/almost_infinite/mod.rs b/rustcoalescence/scenarios/src/almost_infinite/mod.rs index 76f8bbca2..03e7a88c6 100644 --- a/rustcoalescence/scenarios/src/almost_infinite/mod.rs +++ b/rustcoalescence/scenarios/src/almost_infinite/mod.rs @@ -1,4 +1,3 @@ -use either::Either; use necsim_impls_no_std::cogs::{ habitat::almost_infinite::AlmostInfiniteHabitat, origin_sampler::{ @@ -27,44 +26,102 @@ pub mod downscaled; #[cfg(feature = "almost-infinite-normal-dispersal")] pub mod normal; -#[derive(Debug, Serialize, Deserialize)] #[allow(clippy::module_name_repetitions)] +#[derive(Debug, Serialize, Deserialize)] #[serde(deny_unknown_fields)] #[serde(rename = "AlmostInfinite")] pub struct AlmostInfiniteArguments { sample: Sample, dispersal: Dispersal, - // TODO: add optional downscaled + #[cfg(feature = "almost-infinite-downscaled")] + #[serde(default)] + downscale: Option, } -#[cfg(feature = "almost-infinite-normal-dispersal")] -type NormalDispersalArguments = normal::AlmostInfiniteNormalDispersalArguments; -#[cfg(not(feature = "almost-infinite-normal-dispersal"))] -type NormalDispersalArguments = !; - -#[cfg(feature = "almost-infinite-clark2dt-dispersal")] -type Clark2DtDispersalArguments = clark2dt::AlmostInfiniteClark2DtDispersalArguments; -#[cfg(not(feature = "almost-infinite-clark2dt-dispersal"))] -type Clark2DtDispersalArguments = !; +#[allow(clippy::module_name_repetitions, clippy::empty_enum)] +pub enum AlmostInfiniteArgumentVariants { + #[cfg(feature = "almost-infinite-normal-dispersal")] + Normal(normal::AlmostInfiniteNormalDispersalArguments), + #[cfg(feature = "almost-infinite-clark2dt-dispersal")] + Clark2Dt(clark2dt::AlmostInfiniteClark2DtDispersalArguments), + #[cfg(all( + feature = "almost-infinite-downscaled", + feature = "almost-infinite-normal-dispersal" + ))] + DownscaledNormal( + downscaled::AlmostInfiniteDownscaledArguments< + normal::AlmostInfiniteNormalDispersalScenario, + >, + ), + #[cfg(all( + feature = "almost-infinite-downscaled", + feature = "almost-infinite-clark2dt-dispersal" + ))] + DownscaledClark2Dt( + downscaled::AlmostInfiniteDownscaledArguments< + clark2dt::AlmostInfiniteClark2DtDispersalScenario, + >, + ), +} impl AlmostInfiniteArguments { #[must_use] - pub fn load(self) -> Either { + pub fn load(self) -> AlmostInfiniteArgumentVariants { match self { #[cfg(feature = "almost-infinite-normal-dispersal")] Self { sample, dispersal: Dispersal::Normal { sigma }, - } => Either::Left(normal::AlmostInfiniteNormalDispersalArguments { sample, sigma }), + #[cfg(feature = "almost-infinite-downscaled")] + downscale: None, + } => AlmostInfiniteArgumentVariants::Normal( + normal::AlmostInfiniteNormalDispersalArguments { sample, sigma }, + ), #[cfg(feature = "almost-infinite-clark2dt-dispersal")] Self { sample, dispersal: Dispersal::Clark2Dt { shape_u, tail_p }, - } => Either::Right(clark2dt::AlmostInfiniteClark2DtDispersalArguments { + #[cfg(feature = "almost-infinite-downscaled")] + downscale: None, + } => AlmostInfiniteArgumentVariants::Clark2Dt( + clark2dt::AlmostInfiniteClark2DtDispersalArguments { + sample, + shape_u, + tail_p, + }, + ), + #[cfg(all( + feature = "almost-infinite-downscaled", + feature = "almost-infinite-normal-dispersal" + ))] + Self { sample, - shape_u, - tail_p, - }), + dispersal: Dispersal::Normal { sigma }, + downscale: Some(downscale), + } => AlmostInfiniteArgumentVariants::DownscaledNormal( + downscaled::AlmostInfiniteDownscaledArguments { + args: normal::AlmostInfiniteNormalDispersalArguments { sample, sigma }, + downscale, + }, + ), + #[cfg(all( + feature = "almost-infinite-downscaled", + feature = "almost-infinite-clark2dt-dispersal" + ))] + Self { + sample, + dispersal: Dispersal::Clark2Dt { shape_u, tail_p }, + downscale: Some(downscale), + } => AlmostInfiniteArgumentVariants::DownscaledClark2Dt( + downscaled::AlmostInfiniteDownscaledArguments { + args: clark2dt::AlmostInfiniteClark2DtDispersalArguments { + sample, + shape_u, + tail_p, + }, + downscale, + }, + ), } } @@ -74,6 +131,8 @@ impl AlmostInfiniteArguments { Self { sample: args.sample.clone(), dispersal: Dispersal::Normal { sigma: args.sigma }, + #[cfg(feature = "almost-infinite-downscaled")] + downscale: None, } } @@ -86,6 +145,8 @@ impl AlmostInfiniteArguments { shape_u: args.shape_u, tail_p: args.tail_p, }, + #[cfg(feature = "almost-infinite-downscaled")] + downscale: None, } } @@ -104,6 +165,7 @@ impl AlmostInfiniteArguments { dispersal: Dispersal::Normal { sigma: args.args.sigma, }, + downscale: Some(args.downscale.clone()), } } @@ -123,6 +185,7 @@ impl AlmostInfiniteArguments { shape_u: args.args.shape_u, tail_p: args.args.tail_p, }, + downscale: Some(args.downscale.clone()), } } } diff --git a/rustcoalescence/scenarios/src/spatially_explicit/mod.rs b/rustcoalescence/scenarios/src/spatially_explicit/mod.rs index 25b38ec51..98ade0b32 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/mod.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/mod.rs @@ -6,7 +6,7 @@ mod turnover; feature = "spatially-explicit-turnover-map", ))] #[allow(clippy::module_name_repetitions)] -pub use turnover::SpatiallyExplicitArguments; +pub use turnover::{SpatiallyExplicitArgumentVariants, SpatiallyExplicitArguments}; #[cfg(feature = "spatially-explicit-turnover-map")] pub use turnover::map; diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/mod.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/mod.rs index 07c3ec704..77a3cd21f 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/mod.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/mod.rs @@ -1,6 +1,5 @@ use std::path::PathBuf; -use either::Either; use serde::{Deserialize, Serialize}; use super::maps::MapLoadingMode; @@ -27,21 +26,17 @@ pub struct SpatiallyExplicitArguments { loading_mode: MapLoadingMode, } -#[cfg(feature = "spatially-explicit-uniform-turnover")] -type UniformTurnoverArguments = uniform::SpatiallyExplicitUniformTurnoverArguments; -#[cfg(not(feature = "spatially-explicit-uniform-turnover"))] -type UniformTurnoverArguments = !; - -#[cfg(feature = "spatially-explicit-turnover-map")] -type TurnoverMapArguments = map::SpatiallyExplicitTurnoverMapArguments; -#[cfg(not(feature = "spatially-explicit-turnover-map"))] -type TurnoverMapArguments = !; +#[allow(clippy::empty_enum)] +pub enum SpatiallyExplicitArgumentVariants { + #[cfg(feature = "spatially-explicit-uniform-turnover")] + UniformTurnover(uniform::SpatiallyExplicitUniformTurnoverArguments), + #[cfg(feature = "spatially-explicit-turnover-map")] + TurnoverMap(map::SpatiallyExplicitTurnoverMapArguments), +} impl SpatiallyExplicitArguments { #[allow(clippy::missing_errors_doc)] - pub fn try_load( - self, - ) -> Result, String> { + pub fn try_load(self) -> Result { match self { #[cfg(feature = "spatially-explicit-uniform-turnover")] Self { @@ -55,7 +50,7 @@ impl SpatiallyExplicitArguments { turnover_rate, loading_mode, ) - .map(Either::Left), + .map(SpatiallyExplicitArgumentVariants::UniformTurnover), #[cfg(feature = "spatially-explicit-turnover-map")] Self { habitat_map, @@ -68,7 +63,7 @@ impl SpatiallyExplicitArguments { turnover_map, loading_mode, ) - .map(Either::Right), + .map(SpatiallyExplicitArgumentVariants::TurnoverMap), } } diff --git a/rustcoalescence/src/args/config/scenario.rs b/rustcoalescence/src/args/config/scenario.rs index 2bcbf842f..4f5478ea8 100644 --- a/rustcoalescence/src/args/config/scenario.rs +++ b/rustcoalescence/src/args/config/scenario.rs @@ -50,11 +50,17 @@ impl Serialize for Scenario { Self::AlmostInfiniteClark2DtDispersal(ref args) => ScenarioRaw::AlmostInfinite( rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArguments::from_clark2dt(args), ), - #[cfg(feature = "almost-infinite-downscaled-normal-dispersal-scenario")] + #[cfg(all( + feature = "almost-infinite-normal-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] Self::AlmostInfiniteDownscaledNormalDispersal(ref args) => ScenarioRaw::AlmostInfinite( rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArguments::from_downscaled_normal(args), ), - #[cfg(feature = "almost-infinite-downscaled-clark2dt-dispersal-scenario")] + #[cfg(all( + feature = "almost-infinite-clark2dt-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] Self::AlmostInfiniteDownscaledClark2DtDispersal(ref args) => ScenarioRaw::AlmostInfinite( rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArguments::from_downscaled_clark2dt(args), ), @@ -74,19 +80,11 @@ impl<'de> Deserialize<'de> for Scenario { feature = "spatially-explicit-uniform-turnover-scenario", feature = "spatially-explicit-turnover-map-scenario", ))] - ScenarioRaw::SpatiallyExplicit(args) => { - match args.try_load().map_err(serde::de::Error::custom)? { - #[allow(clippy::match_single_binding)] - either::Either::Left(args) => match args { - #[cfg(feature = "spatially-explicit-uniform-turnover-scenario")] - args => Ok(Self::SpatiallyExplicitUniformTurnover(args)), - }, - #[allow(clippy::match_single_binding)] - either::Either::Right(args) => match args { - #[cfg(feature = "spatially-explicit-turnover-map-scenario")] - args => Ok(Self::SpatiallyExplicitTurnoverMap(args)), - }, - } + ScenarioRaw::SpatiallyExplicit(args) => match args.try_load().map_err(serde::de::Error::custom)? { + #[cfg(feature = "spatially-explicit-uniform-turnover-scenario")] + rustcoalescence_scenarios::spatially_explicit::SpatiallyExplicitArgumentVariants::UniformTurnover(args) => Ok(Self::SpatiallyExplicitUniformTurnover(args)), + #[cfg(feature = "spatially-explicit-turnover-map-scenario")] + rustcoalescence_scenarios::spatially_explicit::SpatiallyExplicitArgumentVariants::TurnoverMap(args) => Ok(Self::SpatiallyExplicitTurnoverMap(args)), }, #[cfg(feature = "non-spatial-scenario")] ScenarioRaw::NonSpatial(args) => Ok(Self::NonSpatial(args)), @@ -97,16 +95,20 @@ impl<'de> Deserialize<'de> for Scenario { feature = "almost-infinite-clark2dt-dispersal-scenario", ))] ScenarioRaw::AlmostInfinite(args) => match args.load() { - #[allow(clippy::match_single_binding)] - either::Either::Left(args) => match args { - #[cfg(feature = "almost-infinite-normal-dispersal-scenario")] - args => Ok(Self::AlmostInfiniteNormalDispersal(args)), - }, - #[allow(clippy::match_single_binding)] - either::Either::Right(args) => match args { - #[cfg(feature = "almost-infinite-clark2dt-dispersal-scenario")] - args => Ok(Self::AlmostInfiniteClark2DtDispersal(args)), - }, + #[cfg(feature = "almost-infinite-normal-dispersal-scenario")] + rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArgumentVariants::Normal(args) => Ok(Self::AlmostInfiniteNormalDispersal(args)), + #[cfg(feature = "almost-infinite-clark2dt-dispersal-scenario")] + rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArgumentVariants::Clark2Dt(args) => Ok(Self::AlmostInfiniteClark2DtDispersal(args)), + #[cfg(all( + feature = "almost-infinite-normal-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] + rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArgumentVariants::DownscaledNormal(args) => Ok(Self::AlmostInfiniteDownscaledNormalDispersal(args)), + #[cfg(all( + feature = "almost-infinite-clark2dt-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] + rustcoalescence_scenarios::almost_infinite::AlmostInfiniteArgumentVariants::DownscaledClark2Dt(args) => Ok(Self::AlmostInfiniteDownscaledClark2DtDispersal(args)), }, #[cfg(feature = "wrapping-noise-scenario")] ScenarioRaw::WrappingNoise(args) => Ok(Self::WrappingNoise(args)), diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/algorithm_scenario.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/algorithm_scenario.rs index 880d1bfe8..d2e6e4760 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/algorithm_scenario.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/algorithm_scenario.rs @@ -19,20 +19,17 @@ use rustcoalescence_algorithms_gillespie::{ #[cfg(feature = "independent-algorithm")] use rustcoalescence_algorithms_independent::IndependentAlgorithm; -#[cfg(any( - feature = "almost-infinite-clark2dt-dispersal-scenario", - feature = "almost-infinite-downscaled-clark2dt-dispersal-scenario", -))] +#[cfg(feature = "almost-infinite-clark2dt-dispersal-scenario")] use rustcoalescence_scenarios::almost_infinite::clark2dt::AlmostInfiniteClark2DtDispersalScenario; -#[cfg(any( - feature = "almost-infinite-downscaled-clark2dt-dispersal-scenario", - feature = "almost-infinite-downscaled-normal-dispersal-scenario", +#[cfg(all( + any( + feature = "almost-infinite-clark2dt-dispersal-scenario", + feature = "almost-infinite-normal-dispersal-scenario", + ), + feature = "almost-infinite-downscaled-scenario", ))] use rustcoalescence_scenarios::almost_infinite::downscaled::AlmostInfiniteDownscaledScenario; -#[cfg(any( - feature = "almost-infinite-normal-dispersal-scenario", - feature = "almost-infinite-downscaled-normal-dispersal-scenario", -))] +#[cfg(feature = "almost-infinite-normal-dispersal-scenario")] use rustcoalescence_scenarios::almost_infinite::normal::AlmostInfiniteNormalDispersalScenario; #[cfg(feature = "non-spatial-scenario")] use rustcoalescence_scenarios::non_spatial::NonSpatialScenario; @@ -243,7 +240,10 @@ pub(super) fn dispatch>( ) .into_ok() } => AlmostInfiniteClark2DtDispersalScenario, - #[cfg(feature = "almost-infinite-downscaled-normal-dispersal-scenario")] + #[cfg(all( + feature = "almost-infinite-normal-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] ScenarioArgs::AlmostInfiniteDownscaledNormalDispersal(scenario_args) => { AlmostInfiniteDownscaledScenario::new( scenario_args, @@ -251,7 +251,10 @@ pub(super) fn dispatch>( ) .into_ok() } => AlmostInfiniteDownscaledScenario, - #[cfg(feature = "almost-infinite-downscaled-clark2dt-dispersal-scenario")] + #[cfg(all( + feature = "almost-infinite-clark2dt-dispersal-scenario", + feature = "almost-infinite-downscaled-scenario", + ))] ScenarioArgs::AlmostInfiniteDownscaledClark2DtDispersal(scenario_args) => { AlmostInfiniteDownscaledScenario::new( scenario_args,