1use crate::fcf;
2use crate::risk_measure;
3use crate::scenario;
4use crate::solver;
5use crate::state;
6use crate::stochastic_process;
7use crate::system;
8use std::sync::{Arc, Mutex};
9
10fn get_current_stage_objective(
16 total_stage_objective: f64,
17 solution: &solver::Solution,
18) -> f64 {
19 let future_objective = solution.colvalue.last().unwrap();
20 total_stage_objective - future_objective
21}
22
23fn set_default_solver_options(model: &mut solver::Model) {
26 model.set_option("presolve", "off");
27 model.set_option("solver", "simplex");
28 model.set_option("parallel", "off");
29 model.set_option("threads", 1);
30 model.set_option("primal_feasibility_tolerance", 1e-7);
31 model.set_option("dual_feasibility_tolerance", 1e-7);
32 model.set_option("time_limit", 300);
33}
34
35fn set_first_retry_solver_options(model: &mut solver::Model) {
37 model.set_option("primal_feasibility_tolerance", 1e-6);
38 model.set_option("dual_feasibility_tolerance", 1e-6);
39}
40
41fn set_second_retry_solver_options(model: &mut solver::Model) {
43 model.set_option("primal_feasibility_tolerance", 1e-5);
44 model.set_option("dual_feasibility_tolerance", 1e-5);
45}
46
47fn set_third_retry_solver_options(model: &mut solver::Model) {
49 model.set_option("simplex_strategy", 4);
50}
51
52fn set_final_retry_solver_options(model: &mut solver::Model) {
54 model.set_option("presolve", "on");
55 model.set_option("solver", "ipm");
56 model.set_option("primal_feasibility_tolerance", 1e-7);
57 model.set_option("dual_feasibility_tolerance", 1e-7);
58}
59
60fn set_retry_solver_options(model: &mut solver::Model, retry: usize) {
62 match retry {
63 1 => set_first_retry_solver_options(model),
64 2 => set_second_retry_solver_options(model),
65 3 => set_third_retry_solver_options(model),
66 4 => set_final_retry_solver_options(model),
67 _ => set_default_solver_options(model),
68 }
69}
70
71#[derive(Clone)]
73pub struct Variables {
74 pub deficit: Vec<usize>,
75 pub direct_exchange: Vec<usize>,
76 pub reverse_exchange: Vec<usize>,
77 pub thermal_gen: Vec<usize>,
78 pub turbined_flow: Vec<usize>,
79 pub spillage: Vec<usize>,
80 pub stored_volume: Vec<usize>,
81 pub inflow: Vec<usize>,
82 pub inflow_process: Vec<Vec<usize>>,
83 pub alpha: usize,
84}
85
86impl Variables {
87 pub fn with_capacity(system: &system::System) -> Self {
88 Self {
89 deficit: Vec::<usize>::with_capacity(system.meta.buses_count),
90 direct_exchange: Vec::<usize>::with_capacity(
91 system.meta.lines_count,
92 ),
93 reverse_exchange: Vec::<usize>::with_capacity(
94 system.meta.lines_count,
95 ),
96 thermal_gen: Vec::<usize>::with_capacity(
97 system.meta.thermals_count,
98 ),
99 turbined_flow: Vec::<usize>::with_capacity(system.meta.buses_count),
100 spillage: Vec::<usize>::with_capacity(system.meta.hydros_count),
101 stored_volume: Vec::<usize>::with_capacity(
102 system.meta.hydros_count,
103 ),
104 inflow: Vec::<usize>::with_capacity(system.meta.hydros_count),
105 inflow_process: Vec::<Vec<usize>>::with_capacity(
106 system.meta.hydros_count,
107 ),
108 alpha: 0,
109 }
110 }
111}
112
113#[derive(Clone)]
115pub struct Constraints {
116 pub load_balance: Vec<usize>,
117 pub hydro_balance: Vec<usize>,
118 pub inflow_process: Vec<Vec<usize>>,
119}
120
121impl Constraints {
122 pub fn with_capacity(system: &system::System) -> Self {
123 Self {
124 load_balance: Vec::<usize>::with_capacity(system.meta.buses_count),
125 hydro_balance: Vec::<usize>::with_capacity(
126 system.meta.hydros_count,
127 ),
128 inflow_process: Vec::<Vec<usize>>::with_capacity(
129 system.meta.hydros_count,
130 ),
131 }
132 }
133}
134
135#[derive(Clone)]
139pub struct Subproblem {
140 pub model: Option<solver::Model>,
141 pub state: Box<dyn state::State>,
142 pub variables: Variables,
143 pub constraints: Constraints,
144}
145
146impl Subproblem {
147 pub fn new(
148 system: &system::System,
149 state_choice: &str,
150 load_stochastic_process: &Box<
151 dyn stochastic_process::StochasticProcess,
152 >,
153 inflow_stochastic_process: &Box<
154 dyn stochastic_process::StochasticProcess,
155 >,
156 ) -> Self {
157 let state = state::factory(
158 state_choice,
159 system,
160 load_stochastic_process,
161 inflow_stochastic_process,
162 );
163 let mut pb = solver::Problem::new();
164 let variables = Subproblem::add_variables_to_subproblem(
165 &mut pb,
166 system,
167 &state,
168 load_stochastic_process,
169 inflow_stochastic_process,
170 );
171 let constraints = Subproblem::add_constraints_to_subproblem(
172 &mut pb,
173 &variables,
174 system,
175 &state,
176 load_stochastic_process,
177 inflow_stochastic_process,
178 );
179 Self::add_offset_to_subproblem(&mut pb, system);
180
181 let mut model = pb.optimise(solver::Sense::Minimise);
182 set_retry_solver_options(&mut model, 0);
183
184 Self {
185 model: Some(model),
186 state,
187 variables,
188 constraints,
189 }
190 }
191
192 fn add_variables_to_subproblem(
193 pb: &mut solver::Problem,
194 system: &system::System,
195 state: &Box<dyn state::State>,
196 load_stochastic_process: &Box<
197 dyn stochastic_process::StochasticProcess,
198 >,
199 inflow_stochastic_process: &Box<
200 dyn stochastic_process::StochasticProcess,
201 >,
202 ) -> Variables {
203 let deficit: Vec<usize> = system
204 .buses
205 .iter()
206 .map(|bus| pb.add_column(bus.deficit_cost, 0.0..))
207 .collect();
208 let direct_exchange: Vec<usize> = system
209 .lines
210 .iter()
211 .map(|line| {
212 pb.add_column(line.exchange_penalty, 0.0..line.direct_capacity)
213 })
214 .collect();
215 let reverse_exchange: Vec<usize> = system
216 .lines
217 .iter()
218 .map(|line| {
219 pb.add_column(line.exchange_penalty, 0.0..line.reverse_capacity)
220 })
221 .collect();
222 let thermal_gen: Vec<usize> = system
223 .thermals
224 .iter()
225 .map(|thermal| {
226 pb.add_column(
227 thermal.cost,
228 0.0..(thermal.max_generation - thermal.min_generation),
229 )
230 })
231 .collect();
232 let turbined_flow: Vec<usize> = system
233 .hydros
234 .iter()
235 .map(|hydro| {
236 pb.add_column(
237 0.0,
238 hydro.min_turbined_flow..hydro.max_turbined_flow,
239 )
240 })
241 .collect();
242 let spillage: Vec<usize> = system
243 .hydros
244 .iter()
245 .map(|hydro| pb.add_column(hydro.spillage_penalty, 0.0..))
246 .collect();
247 let stored_volume: Vec<usize> = system
248 .hydros
249 .iter()
250 .map(|hydro| {
251 pb.add_column(0.0, hydro.min_storage..hydro.max_storage)
252 })
253 .collect();
254 let inflow: Vec<usize> = system
255 .hydros
256 .iter()
257 .map(|_hydro| pb.add_column(0.0, 0.0..))
258 .collect();
259
260 let inflow_process = state.add_variables_to_subproblem(
262 pb,
263 &load_stochastic_process,
264 &inflow_stochastic_process,
265 );
266
267 let alpha = pb.add_column(1.0, 0.0..);
268
269 Variables {
270 deficit,
271 direct_exchange,
272 reverse_exchange,
273 thermal_gen,
274 turbined_flow,
275 spillage,
276 stored_volume,
277 inflow,
278 inflow_process,
279 alpha,
280 }
281 }
282
283 fn add_constraints_to_subproblem(
284 pb: &mut solver::Problem,
285 variables: &Variables,
286 system: &system::System,
287 state: &Box<dyn state::State>,
288 load_stochastic_process: &Box<
289 dyn stochastic_process::StochasticProcess,
290 >,
291 inflow_stochastic_process: &Box<
292 dyn stochastic_process::StochasticProcess,
293 >,
294 ) -> Constraints {
295 let mut load_balance: Vec<usize> = vec![0; system.meta.buses_count];
297 for bus in system.buses.iter() {
298 let mut factors = vec![(variables.deficit[bus.id], 1.0)];
299 for thermal_id in bus.thermal_ids.iter() {
300 factors.push((variables.thermal_gen[*thermal_id], 1.0));
301 }
302 for hydro_id in bus.hydro_ids.iter() {
303 factors.push((
304 variables.turbined_flow[*hydro_id],
305 system.hydros.get(*hydro_id).unwrap().productivity,
306 ));
307 }
308 for line_id in bus.source_line_ids.iter() {
309 factors.push((variables.reverse_exchange[*line_id], 1.0));
310 factors.push((variables.direct_exchange[*line_id], -1.0));
311 }
312 for line_id in bus.target_line_ids.iter() {
313 factors.push((variables.direct_exchange[*line_id], 1.0));
314 factors.push((variables.reverse_exchange[*line_id], -1.0));
315 }
316 load_balance[bus.id] = pb.add_row(0.0..0.0, &factors);
317 }
318
319 let mut hydro_balance: Vec<usize> = vec![0; system.meta.hydros_count];
321 for hydro in system.hydros.iter() {
322 let mut factors: Vec<(usize, f64)> = vec![
323 (variables.stored_volume[hydro.id], 1.0),
324 (variables.turbined_flow[hydro.id], 1.0),
325 (variables.spillage[hydro.id], 1.0),
326 (variables.inflow[hydro.id], -1.0),
327 ];
328 for upstream_hydro_id in hydro.upstream_hydro_ids.iter() {
329 factors
330 .push((variables.turbined_flow[*upstream_hydro_id], -1.0));
331 factors.push((variables.spillage[*upstream_hydro_id], -1.0));
332 }
333 hydro_balance[hydro.id] = pb.add_row(0.0..0.0, &factors);
334 }
335
336 let inflow_process = state.add_constraints_to_subproblem(
338 pb,
339 variables,
340 load_stochastic_process,
341 inflow_stochastic_process,
342 );
343
344 Constraints {
345 load_balance,
346 hydro_balance,
347 inflow_process,
348 }
349 }
350
351 fn add_offset_to_subproblem(
352 pb: &mut solver::Problem,
353 system: &system::System,
354 ) {
355 let mut offset = 0.0;
356 for thermal in system.thermals.iter() {
357 offset += thermal.cost * thermal.min_generation;
358 }
359 pb.offset = offset;
360 }
361
362 fn set_load_balance_rhs(&mut self, loads: &[f64]) {
363 if let Some(model) = self.model.as_mut() {
364 for (index, row) in self.constraints.load_balance.iter().enumerate()
365 {
366 model.change_rows_bounds(*row, loads[index], loads[index]);
367 }
368 }
369 }
370
371 fn set_hydro_balance_rhs(&mut self, initial_storages: &[f64]) {
372 if let Some(model) = self.model.as_mut() {
373 for (index, row) in
374 self.constraints.hydro_balance.iter().enumerate()
375 {
376 model.change_rows_bounds(
377 *row,
378 initial_storages[index],
379 initial_storages[index],
380 );
381 }
382 }
383 }
384
385 pub fn update_with_current_trajectory(
386 &mut self,
387 realizations: Vec<&Realization>,
388 ) {
389 let realization = realizations.last().unwrap();
390 self.set_hydro_balance_rhs(&realization.final_storage);
391 }
392
393 pub fn update_with_current_realization(
394 &mut self,
395 realization: &Realization,
396 ) {
397 self.state.update_with_current_realization(realization);
398 }
399
400 pub fn compute_new_cut(
401 &self,
402 forward_trajectory: &[&Realization],
403 branching_realizations: &Vec<Realization>,
404 risk_measure: &Box<dyn risk_measure::RiskMeasure>,
405 ) -> fcf::CutStatePair {
406 let mut visited_state = self.state.clone();
408 let cut = visited_state.compute_new_cut(
409 risk_measure,
410 forward_trajectory,
411 branching_realizations,
412 );
413 fcf::CutStatePair::new(cut, visited_state)
414 }
415
416 pub fn add_cut_and_evaluate_cut_selection(
417 &mut self,
418 cut_state_pair: fcf::CutStatePair,
419 future_cost_function: Arc<Mutex<fcf::FutureCostFunction>>,
420 ) {
421 let mut cut = cut_state_pair.cut;
422 let mut visited_state = cut_state_pair.state;
423
424 if let Some(model) = self.model.as_mut() {
425 self.state.add_cut_constraint_to_model(
426 &mut cut,
427 &self.variables,
428 model,
429 );
430 }
431 let mut fcf = future_cost_function.lock().unwrap();
432 cut.id = fcf.cut_pool.total_cut_count;
433 fcf.update_cut_pool_on_add(cut.id);
434 fcf.eval_new_cut_domination(&mut cut);
435
436 fcf.add_cut(cut);
437
438 let returning_cut_ids =
440 fcf.update_old_cuts_domination(&mut visited_state);
441
442 fcf.add_state(visited_state);
443
444 let mut removing_cut_ids = Vec::<usize>::new();
446 for cut in fcf.cut_pool.pool.iter_mut() {
447 if (cut.non_dominated_state_count <= 0) && cut.active {
448 removing_cut_ids.push(cut.id);
449 }
450 }
451
452 for cut_id in returning_cut_ids.iter() {
454 let cut = fcf.cut_pool.pool.get_mut(*cut_id).unwrap();
455 if let Some(model) = self.model.as_mut() {
456 self.state.add_cut_constraint_to_model(
457 cut,
458 &self.variables,
459 model,
460 );
461 }
462 fcf.update_cut_pool_on_return(*cut_id);
463 }
464
465 for cut_id in removing_cut_ids.iter() {
467 let cut_index = fcf.get_active_cut_index_by_id(*cut_id);
468 let row_index = self.first_cut_row_index() + cut_index;
469 if let Some(model) = self.model.as_mut() {
470 model.delete_row(row_index).unwrap();
471 }
472 fcf.update_cut_pool_on_remove(*cut_id, cut_index);
473 }
474 }
475
476 fn set_uncertainties<'a>(
477 &mut self,
478 bus_loads: &[f64],
479 hydros_inflow: &[f64],
480 ) {
481 self.set_load_balance_rhs(bus_loads);
482 if let Some(model) = self.model.as_mut() {
483 self.state.set_inflows_in_subproblem(
484 model,
485 &self.constraints,
486 hydros_inflow,
487 );
488 }
489 }
490
491 fn retry_solve(&mut self) {
492 let mut retry: usize = 0;
493 if let Some(model) = self.model.as_mut() {
494 loop {
495 if retry > 4 {
496 panic!("Error while solving model");
497 }
498 model.solve();
499
500 match model.status() {
501 solver::HighsModelStatus::Optimal => {
502 if retry != 0 {
503 set_default_solver_options(model);
504 }
505 return;
506 }
507 solver::HighsModelStatus::Infeasible => {
508 retry += 1;
509 set_retry_solver_options(model, retry);
510 }
511 _ => panic!("Error while solving model"),
512 }
513 }
514 }
515 }
516
517 fn first_cut_row_index(&self) -> usize {
518 self.constraints
519 .inflow_process
520 .last()
521 .unwrap()
522 .last()
523 .unwrap()
524 + 1
525 }
526
527 pub fn realize_uncertainties(
528 &mut self,
529 noises: &scenario::SampledBranchingNoises,
530 load_stochastic_process: &Box<
531 dyn stochastic_process::StochasticProcess,
532 >,
533 inflow_stochastic_process: &Box<
534 dyn stochastic_process::StochasticProcess,
535 >,
536 realization_container: &mut Realization,
537 ) -> Result<(), String> {
538 let load = load_stochastic_process.realize(noises.get_load_noises());
539 let inflow_noises =
540 inflow_stochastic_process.realize(noises.get_inflow_noises());
541
542 self.set_uncertainties(load, inflow_noises);
543
544 self.retry_solve();
545
546 match &self.model {
547 Some(model) => match model.status() {
548 solver::HighsModelStatus::Optimal => {
549 let mut solution = model.get_solution();
550 self.slice_solution_rows_to_problem_constraints(
551 &mut solution,
552 );
553
554 realization_container.basis.clone_from(&model.get_basis());
556
557 realization_container.total_stage_objective =
559 model.get_objective_value();
560 realization_container.current_stage_objective =
561 get_current_stage_objective(
562 realization_container.total_stage_objective,
563 &solution,
564 );
565
566 self.get_deficit_from_solution(
568 &solution,
569 realization_container,
570 );
571 self.get_marginal_cost_from_solution(
572 &solution,
573 realization_container,
574 );
575 self.get_net_exchange_from_solution(
577 &solution,
578 realization_container,
579 );
580 self.get_thermal_gen_from_solution(
582 &solution,
583 realization_container,
584 );
585 self.get_inflow_from_solution(
587 &solution,
588 realization_container,
589 );
590 self.get_final_storage_from_solution(
591 &solution,
592 realization_container,
593 );
594 self.get_turbined_flow_from_solution(
595 &solution,
596 realization_container,
597 );
598 self.get_spillage_from_solution(
599 &solution,
600 realization_container,
601 );
602 self.get_water_values_from_solution(
603 &solution,
604 realization_container,
605 );
606
607 model.clear_solver();
608 Ok(())
609 }
610 _ => Err(format!("Error while solving subproblem: {:?}", model.status())),
611 },
612 None => Err("Error while solving subproblem: Model is None".to_string()),
613 }
614 }
615
616 fn get_deficit_from_solution(
617 &self,
618 solution: &solver::Solution,
619 realization_container: &mut Realization,
620 ) {
621 let first = *self.variables.deficit.first().unwrap();
622 let last = *self.variables.deficit.last().unwrap() + 1;
623 realization_container
624 .deficit
625 .clone_from_slice(&solution.colvalue[first..last]);
626 }
627
628 fn get_net_exchange_from_solution(
629 &self,
630 solution: &solver::Solution,
631 realization_container: &mut Realization,
632 ) {
633 if !self.variables.direct_exchange.is_empty() {
634 let direct_first = *self.variables.direct_exchange.first().unwrap();
635 let direct_last =
636 *self.variables.direct_exchange.last().unwrap() + 1;
637 let reverse_first =
638 *self.variables.reverse_exchange.first().unwrap();
639 let reverse_last =
640 *self.variables.reverse_exchange.last().unwrap() + 1;
641 realization_container.exchange.clone_from_slice(
642 &solution.colvalue[direct_first..direct_last],
643 );
644 realization_container
645 .exchange
646 .iter_mut()
647 .zip(&solution.colvalue[reverse_first..reverse_last])
648 .for_each(|(direct, reverse)| *direct -= *reverse);
649 }
650 }
651
652 fn get_thermal_gen_from_solution(
653 &self,
654 solution: &solver::Solution,
655 realization_container: &mut Realization,
656 ) {
657 if !self.variables.thermal_gen.is_empty() {
658 let first = *self.variables.thermal_gen.first().unwrap();
659 let last = *self.variables.thermal_gen.last().unwrap() + 1;
660 realization_container
661 .thermal_generation
662 .clone_from_slice(&solution.colvalue[first..last]);
663 }
664 }
665
666 fn get_spillage_from_solution(
667 &self,
668 solution: &solver::Solution,
669 realization_container: &mut Realization,
670 ) {
671 let first = *self.variables.spillage.first().unwrap();
672 let last = *self.variables.spillage.last().unwrap() + 1;
673 realization_container
674 .spillage
675 .clone_from_slice(&solution.colvalue[first..last]);
676 }
677
678 fn get_turbined_flow_from_solution(
679 &self,
680 solution: &solver::Solution,
681 realization_container: &mut Realization,
682 ) {
683 let first = *self.variables.turbined_flow.first().unwrap();
684 let last = *self.variables.turbined_flow.last().unwrap() + 1;
685 realization_container
686 .turbined_flow
687 .clone_from_slice(&solution.colvalue[first..last]);
688 }
689
690 fn get_final_storage_from_solution(
691 &self,
692 solution: &solver::Solution,
693 realization_container: &mut Realization,
694 ) {
695 let first = *self.variables.stored_volume.first().unwrap();
696 let last = *self.variables.stored_volume.last().unwrap() + 1;
697 realization_container
698 .final_storage
699 .clone_from_slice(&solution.colvalue[first..last]);
700 }
701
702 fn get_inflow_from_solution(
703 &self,
704 solution: &solver::Solution,
705 realization_container: &mut Realization,
706 ) {
707 let first = *self.variables.inflow.first().unwrap();
708 let last = *self.variables.inflow.last().unwrap() + 1;
709 realization_container
710 .inflow
711 .clone_from_slice(&solution.colvalue[first..last]);
712 }
713
714 fn get_water_values_from_solution(
715 &self,
716 solution: &solver::Solution,
717 realization_container: &mut Realization,
718 ) {
719 let first = *self.constraints.hydro_balance.first().unwrap();
720 let last = *self.constraints.hydro_balance.last().unwrap() + 1;
721 realization_container
722 .water_value
723 .clone_from_slice(&solution.rowdual[first..last]);
724 }
725
726 fn get_marginal_cost_from_solution(
727 &self,
728 solution: &solver::Solution,
729 realization_container: &mut Realization,
730 ) {
731 let first = *self.constraints.load_balance.first().unwrap();
732 let last = *self.constraints.load_balance.last().unwrap() + 1;
733 realization_container
734 .marginal_cost
735 .clone_from_slice(&solution.rowdual[first..last]);
736 }
737
738 fn slice_solution_rows_to_problem_constraints(
739 &self,
740 solution: &mut solver::Solution,
741 ) {
742 let end = *self
743 .constraints
744 .inflow_process
745 .last()
746 .unwrap()
747 .last()
748 .unwrap()
749 + 1;
750 solution.rowvalue.truncate(end);
751 solution.rowdual.truncate(end);
752 }
753}
754
755#[derive(Debug, PartialEq, Clone)]
756pub enum StudyPeriodKind {
757 PreStudy,
758 Study,
759 PostStudy,
760}
761
762#[derive(Debug, Clone)]
763pub struct Realization {
764 pub kind: StudyPeriodKind,
765 pub loads: Vec<f64>,
766 pub deficit: Vec<f64>,
767 pub exchange: Vec<f64>,
768 pub inflow: Vec<f64>,
769 pub turbined_flow: Vec<f64>,
770 pub spillage: Vec<f64>,
771 pub thermal_generation: Vec<f64>,
772 pub water_value: Vec<f64>,
773 pub marginal_cost: Vec<f64>,
774 pub current_stage_objective: f64,
775 pub total_stage_objective: f64,
776 pub final_storage: Vec<f64>,
777 pub basis: solver::Basis,
778}
779
780impl Realization {
781 pub fn new(
782 loads: Vec<f64>,
783 deficit: Vec<f64>,
784 exchange: Vec<f64>,
785 inflow: Vec<f64>,
786 turbined_flow: Vec<f64>,
787 spillage: Vec<f64>,
788 thermal_generation: Vec<f64>,
789 water_value: Vec<f64>,
790 marginal_cost: Vec<f64>,
791 current_stage_objective: f64,
792 total_stage_objective: f64,
793 final_storage: Vec<f64>,
794 basis: solver::Basis,
795 ) -> Self {
796 Self {
797 kind: StudyPeriodKind::Study,
798 loads,
799 deficit,
800 exchange,
801 inflow,
802 turbined_flow,
803 spillage,
804 thermal_generation,
805 water_value,
806 marginal_cost,
807 current_stage_objective,
808 total_stage_objective,
809 final_storage,
810 basis,
811 }
812 }
813
814 pub fn with_capacity(
815 kind: &StudyPeriodKind,
816 system: &system::System,
817 ) -> Self {
818 Self {
819 kind: kind.clone(),
820 loads: vec![0.0; system.meta.buses_count],
821 deficit: vec![0.0; system.meta.buses_count],
822 exchange: vec![0.0; system.meta.lines_count],
823 inflow: vec![0.0; system.meta.hydros_count],
824 turbined_flow: vec![0.0; system.meta.hydros_count],
825 spillage: vec![0.0; system.meta.hydros_count],
826 thermal_generation: vec![0.0; system.meta.thermals_count],
827 water_value: vec![0.0; system.meta.hydros_count],
828 marginal_cost: vec![0.0; system.meta.buses_count],
829 current_stage_objective: 0.0,
830 total_stage_objective: 0.0,
831 final_storage: vec![0.0; system.meta.hydros_count],
832 basis: solver::Basis::new(),
833 }
834 }
835}
836
837impl Default for Realization {
838 fn default() -> Self {
839 Self {
840 kind: StudyPeriodKind::Study,
841 loads: vec![],
842 deficit: vec![],
843 exchange: vec![],
844 inflow: vec![],
845 turbined_flow: vec![],
846 spillage: vec![],
847 thermal_generation: vec![],
848 water_value: vec![],
849 marginal_cost: vec![],
850 current_stage_objective: 0.0,
851 total_stage_objective: 0.0,
852 final_storage: vec![],
853 basis: solver::Basis::new(),
854 }
855 }
856}
857
858#[cfg(test)]
859mod tests {
860
861 use super::*;
862
863 #[test]
864 fn test_create_subproblem_with_default_system() {
865 let system = system::System::default();
866 let load_stochastic_process = stochastic_process::factory("naive");
867 let inflow_stochastic_process = stochastic_process::factory("naive");
868 let subproblem = Subproblem::new(
869 &system,
870 "storage",
871 &load_stochastic_process,
872 &inflow_stochastic_process,
873 );
874 assert_eq!(subproblem.variables.deficit.len(), 1);
875 assert_eq!(subproblem.variables.direct_exchange.len(), 0);
876 assert_eq!(subproblem.variables.reverse_exchange.len(), 0);
877 assert_eq!(subproblem.variables.thermal_gen.len(), 2);
878 assert_eq!(subproblem.variables.turbined_flow.len(), 1);
879 assert_eq!(subproblem.variables.spillage.len(), 1);
880 assert_eq!(subproblem.variables.stored_volume.len(), 1);
881 assert_eq!(subproblem.variables.inflow.len(), 1);
882 }
883
884 #[test]
885 fn test_solve_subproblem_with_default_system() {
886 let system = system::System::default();
887 let load_stochastic_process = stochastic_process::factory("naive");
888 let inflow_stochastic_process = stochastic_process::factory("naive");
889 let mut subproblem = Subproblem::new(
890 &system,
891 "storage",
892 &load_stochastic_process,
893 &inflow_stochastic_process,
894 );
895 let inflow = [0.0];
896 let initial_storage = [83.333];
897 let load = [50.0];
898
899 subproblem.set_hydro_balance_rhs(&initial_storage);
900 subproblem.set_uncertainties(&load, &inflow);
901
902 if let Some(mut model) = subproblem.model {
903 model.solve();
904 assert_eq!(model.status(), solver::HighsModelStatus::Optimal);
905 }
906 }
907
908 #[test]
909 fn test_get_solution_cost_with_default_system() {
910 let system = system::System::default();
911 let load_stochastic_process = stochastic_process::factory("naive");
912 let inflow_stochastic_process = stochastic_process::factory("naive");
913 let mut subproblem = Subproblem::new(
914 &system,
915 "storage",
916 &load_stochastic_process,
917 &inflow_stochastic_process,
918 );
919 let inflow = [0.0];
920 let initial_storage = [23.333];
921 let load = [50.0];
922
923 subproblem.set_hydro_balance_rhs(&initial_storage);
924
925 subproblem.set_uncertainties(&load, &inflow);
926
927 if let Some(mut model) = subproblem.model {
928 model.solve();
929 assert_eq!(model.get_objective_value(), 191.67000000000002);
930 }
931 }
932}