#include "filtreavalcplexultime.h" #include #include #include #include #include using std::ofstream; // #define WRITE_CPLEX_FILE FiltreAvalCplexUltime::FiltreAvalCplexUltime() : FiltreAval(), m_cplex( "filtreAval", CPlexModel::Minimisation, CPlexModel::Linear, #ifndef VERBOSE_CPLEX_INTERNAL true, #else false, #endif #ifndef VERBOSE_SOLUTION_STATUS true, #else false, #endif #ifdef WRITE_CPLEX_FILE true, true #else false, false #endif ) { // std::cout << "**** FiltreAvalCplexUltime::FiltreAvalCplexUltime()" << std::endl ; m_type2_prod_min.resize(I()); m_type2_prod_max.resize(I()); } // structure partagée par les différents threads struct CIterThreadScenario { scenario_t m_s ; // dernier scenario pris en charge FiltreAvalCplexUltime * m_fa ; // filtre aval contenant la solution à compléter euros m_cout ; // coût cumulé des solutions pthread_mutex_t lock_it ; // mutex pour bloquer m_s et m_cout CIterThreadScenario( FiltreAvalCplexUltime * fa ) { m_fa = fa ; pthread_mutex_init(&lock_it, NULL); } }; // fonction "start" d'un thread void * threaded_solution_scenario( void * iter_scenarios ) { CIterThreadScenario * its = (CIterThreadScenario *) iter_scenarios ; // itérateur sur les scenarios à traiter CPlexMutable cplex_model( "filtreAval", CPlexModel::Minimisation, CPlexModel::Linear, #ifndef VERBOSE_CPLEX_INTERNAL true, #else false, #endif #ifndef VERBOSE_SOLUTION_STATUS true, #else false, #endif #ifdef WRITE_CPLEX_FILE true, true #else false, false #endif ); /* initialisation du modèle cplex avec les parties indépendantes du scénario */ its->m_fa->setproblemdata( cplex_model ) ; /* parcours des scénarii et calcul des solutions */ while (true) { scenario_t s = S() ; // recherche du prochain scenario à traiter pthread_mutex_lock( & its->lock_it ); if ( its->m_s != S() ) { s = its->m_s ; ++ its->m_s ; } pthread_mutex_unlock( & its->lock_it ); // fin du thread s'il n'y a plus de graphes à traiter if (s==S()) break ; // calcul de la solution du scenario à traiter euros _cout ; try { _cout = its->m_fa->calcule_solution( s, cplex_model ); } catch (CPlexFailed e) { _cout = (euros) INFINI ; } // ajout du coût à la solution globale pthread_mutex_lock( & its->lock_it ); its->m_cout += _cout ; pthread_mutex_unlock( & its->lock_it ); } return NULL ; } // création de colonnes sur plusieurs threads void FiltreAvalCplexUltime::calcule_solutions_scenarios_multithread() { // std::cout << "**** FiltreAvalCplexUltime::calcule_solutions_scenarios_multithread()" << std::endl ; // nombre de cpus int ncpus = sysconf(_SC_NPROCESSORS_CONF); // autant de threads que de cpus vector threads(ncpus); // lancement des différents threads CIterThreadScenario threaded_scenario(this) ; for (vector::iterator th=threads.begin(); th!=threads.end(); th++) { pthread_create( &(*th), NULL, threaded_solution_scenario, (void *) &threaded_scenario ); } // attente de la fin des threads lancés for (vector::iterator th=threads.begin(); th!=threads.end(); th++) { pthread_join( *th, NULL ); } if ((euros) INFINI <= threaded_scenario.m_cout) throw string("Au moins un scénario n'a pas trouvé de solution."); } euros FiltreAvalCplexUltime::calcule_solution( scenario_t s, CPlexMutable & cplex ) { // std::cout << "**** FiltreAvalCplexUltime::calcule_solution( scenario_t s, CPlexMutable & cplex )" << std::endl ; vector deCplex; setproblemdata(s, cplex); cplex.resolution(); reponse[s].costPourScenario = (euros) 0; // coût des recharges for (powerplants2_t i=(powerplants2_t)0; iremplis_stock(reponse[s].prod_nucleaire[i], recharges[i]); } for (powerplants2_t i=(powerplants2_t)0; im_arcs.size()-1]; } return reponse[s].costPourScenario ; } void FiltreAvalCplexUltime::setPlans( const vector & x ) { // std::cout << "**** FiltreAvalCplexUltime::setPlans( const vector & x )" << std::endl ; //Récupération des colonnes sélectionnées for( size_t i =0 ; im_i] = CPlan::getPlan(x[i]); } // vérification : on doit avoir un plan par centrale nucléaire for (size_t i=0; iremplis_min_max(m_type2_prod_min[i],m_type2_prod_max[i]); } euros FiltreAvalCplexUltime::calcule_solution_phase_1( std::vector x, std::vector > & _recharges, double temps_max, bool multithread ) { // std::cout << "**** FiltreAvalCplexUltime::calcule_solution_phase_1" << std::endl ; euros _cout = (euros) INFINI ; setPlans( x ) ; // création du modèle et appel à cplex pour le calcul des recharges // base de temps : la semaine #ifdef VERBOSE_TEMPS std::cout << "FiltreAvalCplexUltime::calcule_solution : définition du problème des recharges" << std::endl ; #endif setproblemdata_recharges(); // std::cout << "FiltreAvalCplexUltime::calcule_solution : écriture sur disque pour DEBUG" << std::endl ; // m_cplex.write_pb(); // m_cplex.write_names(); #ifdef VERBOSE_TEMPS std::cout << "FiltreAvalCplexUltime::calcule_solution : résolution du problème des recharges" << std::endl ; #endif if (temps_max > 0) m_cplex.setOption( CPlexModel::Time, temps_max ); _cout = (euros) m_cplex.resolution(); #ifdef VERBOSE_TEMPS std::cout << "FiltreAvalCplexUltime::calcule_solution : problème des recharges résolu" << std::endl ; if (m_cplex.getInfeasible()) std::cout << "\t\t\tINFAISABLE" < deCplex; // récupération des recharges for (powerplants2_t i=(powerplants2_t)0; icalcule_solutions_scenarios_multithread() ; } else { // création du modèle, partie indépendante des scénarios // base de temps : unité du problème initial setproblemdata(m_cplex); // Boucle sur les scénarios et récupération de la solution for (scenario_t s = (scenario_t) 0 ; s < S() ; ++s) { #ifdef VERBOSE_TEMPS clock_t temps3 = clock() ; #endif calcule_solution( s, m_cplex ); #ifdef VERBOSE_TEMPS clock_t temps4 = clock() ; std::cout << "clock(scenario_" << s << ")\t" << (temps4 - temps3) / (double) CLOCKS_PER_SEC << std::endl ; #endif } } // calcul du coût moyen de la solution valeurObjectif = (euros)0 ; for (scenario_t s = (scenario_t) 0 ; s < S() ; ++s) valeurObjectif += reponse[s].costPourScenario ; valeurObjectif /= S(); return valeurObjectif ; } /** * * Calcul d'une solution. La première phase du filtre est lancée plusieurs fois * s'il y a le temps et s'il y a plusieurs jeux de colonnes à essayer * */ euros FiltreAvalCplexUltime::calcule_solution(std::vector > x, double max_time_passes_1, bool multithread) { // std::cout << "**** FiltreAvalCplexUltime::calcule_solution(std::vector > x, double max_time_passes_1, bool multithread)" << std::endl ; time_t debut = time(NULL) ; time_t maintenant = debut ; time_t temps_recharges = maintenant ; time_t max_duree_recharges = 0 ; time_t duree_ecoulee = 0 ; size_t sol_id = 0 , meilleure_sol_id = 0 ; bool _infeasible = true ; euros _cout_min = (euros) INFINI ; euros _cout ; vector< vector > _recharges( I(), vector(K()) ) ; while ( (_infeasible or (duree_ecoulee + max_duree_recharges < max_time_passes_1)) and sol_id x, double prev_recharges, bool multithread) { // std::cout << "**** FiltreAvalCplexUltime::calcule_solution(std::vector x, double prev_recharges, bool multithread)" << std::endl ; clock_t temps1 = clock() ; time_t maintenant = time(NULL) ; time_t temps_recharges = maintenant, temps_scenario = maintenant ; euros _cout1 = calcule_solution_phase_1( x, recharges, prev_recharges, multithread ) ; /* libération mémoire */ m_cplex.reinit(); temps_recharges = time(NULL) ; clock_t temps2 = clock() ; #ifdef VERBOSE_TEMPS std::cout << "time(recharges)\t" << temps_recharges - CInstance::params().getTimeStart() << "\t" << temps_recharges - maintenant << std::endl; std::cout << "clock(recharges)" << "\t" << (temps2 - temps1) / (double) CLOCKS_PER_SEC << std::endl ; #endif maintenant = temps_recharges ; /* calcul des solutions par scénario */ temps1 = clock() ; calcule_solution_phase_2(multithread) ; temps2 = clock() ; temps_scenario = time(NULL) ; #ifdef VERBOSE_TEMPS std::cout << "time(scenarios)\t" << temps_scenario - CInstance::params().getTimeStart() << "\t" << temps_scenario - maintenant << std::endl; std::cout << "clock(scenarios)" << "\t" << (temps2 - temps1) / (double) CLOCKS_PER_SEC << std::endl ; #endif return valeurObjectif; } FiltreAvalCplexUltime::~FiltreAvalCplexUltime() { // std::cout << "**** FiltreAvalCplexUltime::~FiltreAvalCplexUltime()" << std::endl ; } void FiltreAvalCplexUltime::setproblemdata_recharges() { // std::cout << "**** FiltreAvalCplexUltime::setproblemdata_recharges()" << std::endl ; // matrices de production min et max par centrale et par semaine vector > _type2_prod_min_h; vector > _type2_prod_max_h; vector production_nucleaire_maximale; vector > demande_si_type2_max; vector > modulation_a_garantir; vector nb_moduls ; _type2_prod_min_h.resize( I(), vector(H()) ); _type2_prod_max_h.resize( I(), vector(H()) ); // calcul préalable des bornes de production par pas de temps puis par semaine, pour chaque centrale for (powerplants2_t i=(powerplants2_t)0; iremplis_min_max(m_type2_prod_min[i],m_type2_prod_max[i]); for (week_t h=(week_t) 0; h(T()) ); for (scenario_t s; s(T()) ); nb_moduls.resize( S(), 0 ) ; int nb_moduls_total = 0; for (scenario_t s; s=(kWh)0) { _emin += EMIN(j,t,s); _emax += EMAX(j,t,s); } } m_cplex.addToObj( h, _emin.v, _emax.v, CPlexModel::Continuous, C(j,s,h).v / S() ); } // timesteps à modulation imposée int tt = H() ; for (timestep_t t; t=(kWh)0) { _emin += m_type2_prod_min[i][t]; _emax += m_type2_prod_max[i][t]; } } m_cplex.addToObj( h, _emin.v, _emax.v, CPlexModel::Continuous, 0 ); } // timesteps à modulation imposée int tt = H() ; for (timestep_t t; tm_arcs.size(); a++) { const CPlan::CArc & arc = m_plans[i]->m_arcs[a]; campaign_t k = arc.m_depart->m_campaign ; if (arc.m_depart->m_type == TYPE_OUTAGE) { m_cplex.addToObj( k, RMIN(i,k).v, RMAX(i,k).v, CPlexModel::Continuous, C(i,k).v ); } } } // 3 - fuel au début et à la fin de chaque arc, et après recharge // std::cout << " 3 - fuel au début et à la fin de chaque arc, et après recharge" << std::endl; for (scenario_t s=(scenario_t)0; sm_arcs.size() = " << m_plans[i]->m_arcs.size() << std::endl ; m_cplex.addZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s, m_plans[i]->m_arcs.size()); m_cplex.setZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s); for (size_t a=0;am_arcs.size();a++) m_cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); m_cplex.addZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s, m_plans[i]->m_arcs.size()); m_cplex.setZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s); for (size_t a=0;am_arcs.size();a++) m_cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); m_cplex.addZoneHorizontale( string("fuel fin , centrale ")+i+" scenario "+s, m_plans[i]->m_arcs.size()); m_cplex.setZoneHorizontale( string("fuel fin , centrale ")+i+" scenario "+s); for (size_t a=0;am_arcs.size()-1;a++) m_cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); // std::cout << " C(i,K_Tp1).v = " << C(i,K_Tp1).v << std::endl ; m_cplex.addToObj( m_plans[i]->m_arcs.size()-1, 0, INFINI, CPlexModel::Continuous, - C(i,K_Tp1).v / S() ); } } /** contraintes */ /// A - production = demande // std::cout << " A - production = demande" << std::endl; for (scenario_t s=(scenario_t)0; sm_arcs.size() ; m_cplex.addZoneVerticale( string("fd=ff ")+s+" "+i, nb_arcs-1 ); m_cplex.setZoneVerticale( string("fd=ff ")+s+" "+i); m_cplex.setZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s); for (size_t a=1; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; switch ( arc.m_depart->m_type ) { case TYPE_OUTAGE : m_cplex.setZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a, ((coeff_t)1-(coeff_t)1/Q(i,k)).v); m_cplex.setZoneHorizontale( string("recharges ")+i); m_cplex.addToZ(a, k, 1); m_cplex.setZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a, -1); m_cplex.addToRHS(a, CPlexModel::Equals, (BO(i,(campaign_t)(k-1)) * ((Q(i,k)-(coeff_t)1)/Q(i,k)) - BO(i,k)).v); break; default : m_cplex.setZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a, 1); m_cplex.setZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a,-1); m_cplex.addToRHS(a, CPlexModel::Equals, 0); break; } } for (size_t a=0; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; if ( arc.m_depart->m_type == TYPE_OUTAGE ) { // fuel après refuel < SMAX m_cplex.addZoneVerticale( string("farm_type != TYPE_BO and arc.m_fin->m_date!=0 ) { // fuel fin > BO m_cplex.addZoneVerticale( string("ff>BO")+s+" "+i+" "+a, 1 ); m_cplex.setZoneVerticale( string("ff>BO")+s+" "+i+" "+a); m_cplex.setZoneHorizontale( string("fuel fin , centrale ")+i+" scenario "+s); m_cplex.addToZ(0, a, 1); m_cplex.addToRHS(0, CPlexModel::GreaterThan, sup(BO(i,k)).v); } if ( arc.m_depart->m_type == TYPE_BO or arc.m_depart->m_date == (week_t)0 ) { // fuel debut fixé m_cplex.addZoneVerticale( string("fuel début fixe, scenario ")+s+" centrale "+i+" arc "+a, 1 ); m_cplex.setZoneVerticale( string("fuel début fixe, scenario ")+s+" centrale "+i+" arc "+a); m_cplex.setZoneHorizontale( string("fuel début, centrale ")+i+" scenario "+s); m_cplex.addToZ(0, a, 1); m_cplex.addToRHS(0, CPlexModel::Equals, arc.m_depart->m_fuel.v); } } // fuel après - fuel fin - production = 0 m_cplex.addZoneVerticale( string("fa_-_ff_-_p_=_0_")+s+"_"+i, nb_arcs ); for (size_t a=0; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; // fuel après - fuel fin - production = 0 m_cplex.setZoneVerticale( string("fa_-_ff_-_p_=_0_")+s+"_"+i ); m_cplex.setZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a, 1); m_cplex.setZoneHorizontale( string("fuel fin , centrale ")+i+" scenario "+s); m_cplex.addToZ(a, a,-1); m_cplex.setZoneHorizontale( string("pnc")+i+"s"+s); kWh prod_max = (kWh) 0; for ( week_t h=arc.m_depart->m_date_campaign; hm_date; ++h) { m_cplex.addToZ(a,h,-1); prod_max += EMAX(i,h); } // timesteps à modulation imposée int tt = H() ; for (timestep_t t; tm_date); ++t) { if (modulation_a_garantir[s][t]<(kWh)0) { if (t>=week2timestep(arc.m_depart->m_date_campaign)) m_cplex.addToZ(a,tt,-1); tt++; } } m_cplex.addToRHS(a, CPlexModel::Equals, 0); // modulation if (arc.m_depart->m_type != TYPE_BO) { m_cplex.addZoneVerticale( string("fa_m_ff_greater_pmax_m_mmax")+s+" "+i+" "+a, 1 ); m_cplex.setZoneVerticale( string("fa_m_ff_greater_pmax_m_mmax")+s+" "+i+" "+a ); m_cplex.setZoneHorizontale( string("fuel après, centrale ")+i+" scenario "+s); m_cplex.addToZ(0, a, 1); m_cplex.setZoneHorizontale( string("fuel fin , centrale ")+i+" scenario "+s); m_cplex.addToZ(0, a,-1); m_cplex.addToRHS(0, CPlexModel::GreaterThan, (prod_max-MMAX(i,k)).v); } } } } // std::cout << "--- FiltreAvalCplexUltime::setproblemdata_recharges terminé" << std::endl; } void FiltreAvalCplexUltime::setproblemdata(scenario_t s, CPlexMutable & cplex) { // std::cout << "**** FiltreAvalCplexUltime::setproblemdata(scenario_t s, CPlexMutable & cplex)" << std::endl ; for (powerplants1_t j=(powerplants1_t)0; jremplis_min_max(m_type2_prod_min[i],m_type2_prod_max[i]); /** définition des zones horizontales */ // zones horizontales = variables // 1 - production par pas de temps pour chaque scénario for (powerplants1_t j=(powerplants1_t)0; jm_arcs.size()); cplex.setZoneHorizontale( string("fuel début, centrale ")+i); for (size_t a=0;am_arcs.size();a++) cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); cplex.addZoneHorizontale( string("fuel après, centrale ")+i, m_plans[i]->m_arcs.size()); cplex.setZoneHorizontale( string("fuel après, centrale ")+i); for (size_t a=0;am_arcs.size();a++) cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); cplex.addZoneHorizontale( string("fuel fin , centrale ")+i, m_plans[i]->m_arcs.size()); cplex.setZoneHorizontale( string("fuel fin , centrale ")+i); for (size_t a=0;am_arcs.size()-1;a++) cplex.addToObj(a,0,INFINI,CPlexModel::Continuous,0); cplex.addToObj( m_plans[i]->m_arcs.size()-1, 0, INFINI, CPlexModel::Continuous, - C(i,K_Tp1).v ); } /** contraintes */ /// A - production = demande cplex.addZoneVerticale( string("production=demande"), T() ) ; cplex.setZoneVerticale( string("production=demande")); // partie gauche : production thermique et nucléaire for (powerplants1_t j=(powerplants1_t)0; jm_arcs.size() ; cplex.addZoneVerticale( string("fd=ff ")+i, nb_arcs-1 ); cplex.setZoneVerticale( string("fd=ff ")+i); cplex.setZoneHorizontale( string("fuel début, centrale ")+i); for (size_t a=1; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; switch ( arc.m_depart->m_type ) { case TYPE_OUTAGE : cplex.setZoneHorizontale( string("fuel début, centrale ")+i ); cplex.addToZ(a, a, ((coeff_t)1-(coeff_t)1/Q(i,k)).v); cplex.setZoneHorizontale( string("recharges ")+i); cplex.addToZ(a, k, 1); cplex.setZoneHorizontale( string("fuel après, centrale ")+i); cplex.addToZ(a, a, -1); cplex.addToRHS(a, CPlexModel::Equals, (BO(i,(campaign_t)(k-1)) * ((Q(i,k)-(coeff_t)1)/Q(i,k)) - BO(i,k)).v); break; default : cplex.setZoneHorizontale( string("fuel début, centrale ")+i); cplex.addToZ(a, a, 1); cplex.setZoneHorizontale( string("fuel après, centrale ")+i); cplex.addToZ(a, a,-1); cplex.addToRHS(a, CPlexModel::Equals, 0); break; } } for (size_t a=0; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; if ( arc.m_depart->m_type == TYPE_OUTAGE ) { // fuel après refuel < SMAX cplex.addZoneVerticale( string("farm_type != TYPE_BO and arc.m_fin->m_date!=0 ) { // fuel fin > BO cplex.addZoneVerticale( string("ff>BO")+" "+i+" "+a, 1 ); cplex.setZoneVerticale( string("ff>BO")+" "+i+" "+a); cplex.setZoneHorizontale( string("fuel fin , centrale ")+i); cplex.addToZ(0, a, 1); cplex.addToRHS(0, CPlexModel::GreaterThan, sup(BO(i,k)).v); } if ( arc.m_depart->m_type == TYPE_BO or arc.m_depart->m_date == (week_t)0 ) { // fuel debut fixé cplex.addZoneVerticale( string("fuel début fixe,")+" centrale "+i+" arc "+a, 1 ); cplex.setZoneVerticale( string("fuel début fixe,")+" centrale "+i+" arc "+a); cplex.setZoneHorizontale( string("fuel début, centrale ")+i); cplex.addToZ(0, a, 1); cplex.addToRHS(0, CPlexModel::Equals, arc.m_depart->m_fuel.v); } } // fuel après - fuel fin - production = 0 cplex.addZoneVerticale( string("fa_-_ff_-_p_=_0_")+"_"+i, nb_arcs ); for (size_t a=0; am_arcs[a]; campaign_t k = arc.m_depart->m_campaign; // fuel après - fuel fin - production = 0 cplex.setZoneVerticale( string("fa_-_ff_-_p_=_0_")+"_"+i ); cplex.setZoneHorizontale( string("fuel après, centrale ")+i); cplex.addToZ(a, a, 1); cplex.setZoneHorizontale( string("fuel fin , centrale ")+i); cplex.addToZ(a, a,-1); cplex.setZoneHorizontale( string("production nucléaire centrale ")+i); kWh prod_max = (kWh) 0; for ( timestep_t t=week2timestep(arc.m_depart->m_date_campaign); tm_date); ++t) { cplex.addToZ(a,t,-1); prod_max += EMAX(i,t); } cplex.addToRHS(a, CPlexModel::Equals, 0); // modulation if (arc.m_depart->m_type != TYPE_BO) { cplex.addZoneVerticale( string("fa_m_ff_greater_pmax_m_mmax")+" "+i+" "+a, 1 ); cplex.setZoneVerticale( string("fa_m_ff_greater_pmax_m_mmax")+" "+i+" "+a ); cplex.setZoneHorizontale( string("fuel après, centrale ")+i); cplex.addToZ(0, a, 1); cplex.setZoneHorizontale( string("fuel fin , centrale ")+i); cplex.addToZ(0, a,-1); cplex.addToRHS(0, CPlexModel::GreaterThan, (prod_max-MMAX(i,k)).v); } } } }