pub mod builder;
use crate::lifting_line::simulation::Simulation as LiftingLineSimulation;
use crate::wind::{
environment::WindEnvironment,
wind_condition::WindCondition
};
use crate::controller::{
Controller,
input::ControllerInput,
};
use crate::common_utils::results::{
simulation::SimulationResult,
simplfied::SingleSailResult,
};
use builder::CompleteSailModelBuilder;
use stormath::{
type_aliases::Float,
spatial_vector::SpatialVector,
array_generation,
};
use crate::error::Error;
#[derive(Debug, Clone)]
pub struct CompleteSailModel {
pub lifting_line_simulation: LiftingLineSimulation,
pub wind_environment: WindEnvironment,
pub controller: Controller,
}
impl CompleteSailModel {
pub fn new_from_string(setup_string: &str) -> Result<Self, Error> {
let builder = CompleteSailModelBuilder::new_from_string(setup_string)?;
Ok(builder.build())
}
pub fn get_number_of_sails(&self) -> usize {
self.lifting_line_simulation.line_force_model.nr_wings()
}
pub fn simulate_condition_optimal_controller_loading(
&mut self,
wind_condition: &WindCondition,
ship_velocity: Float,
nr_loadings_to_test: usize,
) -> SimulationResult {
let loadings_to_test = array_generation::linspace(0.1, 1.0, nr_loadings_to_test);
let mut results: Vec<SimulationResult> = Vec::with_capacity(nr_loadings_to_test);
let mut effective_power: Vec<Float> = Vec::with_capacity(nr_loadings_to_test);
let mut max_effective_power = Float::NEG_INFINITY;
let mut best_index = 0;
for i in 0..nr_loadings_to_test {
let result = self.simulate_steady_state_condition(
wind_condition,
ship_velocity,
loadings_to_test[i]
);
let thrust = -result.integrated_forces_sum()[0];
let delivered_power = thrust * ship_velocity;
let input_power = result.input_power_sum();
effective_power.push(delivered_power - input_power);
if effective_power[i] > max_effective_power {
max_effective_power = effective_power[i];
best_index = i;
}
results.push(
result
);
}
results[best_index].clone()
}
pub fn simulate_steady_state_condition(
&mut self,
wind_condition: &WindCondition,
ship_velocity: Float,
controller_loading: Float
) -> SimulationResult {
self.apply_controller_based_on_wind_condition(
0.0,
1.0,
wind_condition,
ship_velocity,
controller_loading
);
self.do_step(
0.0,
1.0,
wind_condition,
ship_velocity
)
}
pub fn simulate_steady_state_condition_simple_output(
&mut self,
wind_condition: &WindCondition,
ship_velocity: Float,
controller_loading: Float
) -> Vec<SingleSailResult> {
let full_results = self.simulate_steady_state_condition(
wind_condition,
ship_velocity,
controller_loading
);
full_results.as_simplified()
}
pub fn do_multiple_steps(
&mut self,
end_time: Float,
time_step: Float,
wind_condition: &WindCondition,
ship_velocity: Float,
) -> Vec<SimulationResult> {
let mut results = Vec::new();
self.lifting_line_simulation.first_time_step_completed = false;
let mut current_time = 0.0;
while current_time < end_time {
results.push(
self.do_step(
current_time,
time_step,
wind_condition,
ship_velocity,
)
);
current_time += time_step;
}
results
}
pub fn do_step(
&mut self,
current_time: Float,
time_step: Float,
wind_condition: &WindCondition,
ship_velocity: Float
) -> SimulationResult {
let freestream_velocity = self.freestream_velocity(
wind_condition,
ship_velocity,
current_time
);
self.lifting_line_simulation.do_step(
current_time,
time_step,
&freestream_velocity
)
}
pub fn apply_controller_based_on_wind_condition(
&mut self,
current_time: Float,
time_step: Float,
wind_condition: &WindCondition,
ship_velocity: Float,
controller_loading: Float,
) {
let freestream_velocity = self.freestream_velocity(
wind_condition,
ship_velocity,
current_time
);
self.apply_controller_based_on_freestream(
current_time,
time_step,
controller_loading,
&freestream_velocity
);
}
pub fn freestream_velocity(
&self,
wind_condition: &WindCondition,
ship_velocity: Float,
time: Float
) -> Vec<SpatialVector> {
let freestream_velocity_points = self.lifting_line_simulation
.get_freestream_velocity_points();
let linear_velocity = ship_velocity * self.wind_environment.zero_direction_vector;
let nr_points = freestream_velocity_points.len();
let mut freestream_velocity = Vec::with_capacity(nr_points);
for i in 0..nr_points {
freestream_velocity.push(
self.wind_environment.unsteady_apparent_wind_velocity_vector_at_location(
wind_condition,
freestream_velocity_points[i],
linear_velocity,
time
)
);
}
let reference_height = 10.0;
let apparent_wind_direction = self.wind_environment
.apparent_wind_direction_from_condition_and_linear_velocity(
wind_condition,
linear_velocity,
reference_height
);
self.wind_environment.apply_inflow_corrections(
apparent_wind_direction,
&mut freestream_velocity,
&self.lifting_line_simulation.line_force_model.ctrl_points_global,
&self.lifting_line_simulation.line_force_model.wing_indices
);
freestream_velocity
}
pub fn apply_controller_based_on_freestream(
&mut self,
current_time: Float,
time_step: Float,
loading: Float,
freestream_velocity: &[SpatialVector]
) {
let nr_ctrl_points = self.lifting_line_simulation.line_force_model.nr_span_lines();
let ctrl_points_velocity = &freestream_velocity[0..nr_ctrl_points];
let controller_input = ControllerInput::new_from_velocity(
loading,
&self.lifting_line_simulation.line_force_model,
ctrl_points_velocity,
&self.controller.flow_measurement_settings,
&self.wind_environment,
);
let controller_output = self.controller.update(
current_time,
time_step,
&controller_input
);
if let Some(output) = &controller_output {
self.lifting_line_simulation.line_force_model.set_controller_output(
output
);
}
}
pub fn apply_controller_based_on_simulation_result(
&mut self,
current_time: Float,
time_step: Float,
loading: Float,
simulation_result: &SimulationResult
) {
let controller_input = ControllerInput::new_from_simulation_result(
loading,
&self.lifting_line_simulation.line_force_model,
simulation_result,
&self.controller.flow_measurement_settings,
&self.wind_environment,
self.controller.use_input_velocity_for_apparent_wind_direction
);
let controller_output = self.controller.update(
current_time,
time_step,
&controller_input
);
if let Some(output) = &controller_output {
self.lifting_line_simulation.line_force_model.set_controller_output(
output
);
}
}
pub fn set_local_wing_angles(&mut self, local_wing_angles: &[Float]) {
self.lifting_line_simulation
.line_force_model
.set_local_wing_angles(local_wing_angles);
}
pub fn set_section_models_internal_state(&mut self, internal_state: &[Float]) {
self.lifting_line_simulation
.line_force_model
.set_section_models_internal_state(internal_state);
}
}