Skip to content

Commit

Permalink
#261 Improve MC computation to have all procs available running jobs.
Browse files Browse the repository at this point in the history
Signed-off-by: Gautier Bureau <gautier.bureau@rte-france.com>
  • Loading branch information
gautierbureau committed Apr 13, 2023
1 parent 8dd0cb2 commit d4e08cc
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 47 deletions.
19 changes: 10 additions & 9 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,16 @@
{ "name": "DYNAWO_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_SCRIPTS_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo/sbin" },
{ "name": "DYNAWO_DICTIONARIES", "value" : "dictionaries_mapping" },
{ "name": "DYNAWO_ADEPT_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_INSTALL_OPENMODELICA", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo/OpenModelica" },
{ "name": "DYNAWO_XERCESC_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_SUITESPARSE_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_SUNDIALS_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_BOOST_HOME", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_LIBXML_HOME", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "DYNAWO_NICSLU_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo" },
{ "name": "LD_LIBRARY_PATH", "value" : "${env:LD_LIBRARY_PATH}:${workspaceFolder}/build-code/install/3rdParty/Debug/gperftools/lib:${workspaceFolder}/build-code/install/3rdParty/Debug/mpich/lib:${workspaceFolder}/build-code/install/dynawo-algorithms/Debug/lib:${workspaceFolder}/../dynawo/build-code/deploy/Debug/dynawo/lib" }
{ "name": "DYNAWO_ADEPT_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_INSTALL_OPENMODELICA", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/OpenModelica" },
{ "name": "OPENMODELICAHOME", "value" : "${workspaceFolder}/../dynawo/build-code/deploy/OpenModelica" },
{ "name": "DYNAWO_XERCESC_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_SUITESPARSE_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_SUNDIALS_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_BOOST_HOME", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_LIBXML_HOME", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "DYNAWO_NICSLU_INSTALL_DIR", "value" : "${workspaceFolder}/../dynawo/build-code/deploy" },
{ "name": "LD_LIBRARY_PATH", "value" : "${env:LD_LIBRARY_PATH}:${workspaceFolder}/build-code/install/3rdParty/gperftools/lib:${workspaceFolder}/build-code/install/3rdParty/mpich/lib:${workspaceFolder}/build-code/install/dynawo-algorithms/lib:${workspaceFolder}/../dynawo/build-code/deploy/lib" }
],
"externalConsole": false,
"MIMode": "gdb",
Expand Down
3 changes: 3 additions & 0 deletions sources/Common/DYNResultCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace DYNAlgorithms {
* @brief task status
*/
typedef enum {
NOT_TREATED, ///< simulation has not been launched or processed
CONVERGENCE_STATUS, ///< simulation reached its end with no error nor criterion not respected
DIVERGENCE_STATUS, ///< divergence occurs during the simulation (solver error)
EXECUTION_PROBLEM_STATUS, ///< something wrong happened during the simulation (solver error, data error, etc...)
Expand All @@ -29,6 +30,8 @@ typedef enum {

static inline std::string getStatusAsString(status_t status) {
switch (status) {
case NOT_TREATED:
return "NOT_TREATED";
case CONVERGENCE_STATUS:
return "CONVERGENCE";
case EXECUTION_PROBLEM_STATUS:
Expand Down
2 changes: 1 addition & 1 deletion sources/Common/DYNSimulationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace DYNAlgorithms {
SimulationResult::SimulationResult():
variation_(-1.),
success_(false),
status_(EXECUTION_PROBLEM_STATUS),
status_(NOT_TREATED),
timelineFileExtension_("xml"),
constraintsFileExtension_("xml"),
lostEquipmentsFileExtension_("xml") {
Expand Down
2 changes: 1 addition & 1 deletion sources/Common/test/TestBaseClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ TEST(TestBaseClasses, testSimulationResult) {
SimulationResult sr;
ASSERT_TRUE(sr.getScenarioId().empty());
ASSERT_FALSE(sr.getSuccess());
ASSERT_EQ(sr.getStatus(), EXECUTION_PROBLEM_STATUS);
ASSERT_EQ(sr.getStatus(), NOT_TREATED);
ASSERT_TRUE(sr.getFailingCriteria().empty());
sr.setScenarioId("MyId");
sr.setVariation(50.);
Expand Down
106 changes: 87 additions & 19 deletions sources/Launcher/DYNMarginCalculationLauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ MarginCalculationLauncher::launch() {
if (resultMaxVariation.getSuccess()) {
if (!DYN::doubleEquals(minVariation, maxVariation))
findAllLevelsBetween(minVariation, maxVariation, marginCalculation->getAccuracy(), allEvents, toRun);
findOrLaunchScenarios(baseJobsFile, events, toRun, results_[idx]);
findOrLaunchScenarios(baseJobsFile, events, toRun, maximumVariationPassing, results_[idx]);

// analyze results
unsigned int nbSuccess = 0;
Expand Down Expand Up @@ -242,7 +242,7 @@ MarginCalculationLauncher::launch() {
}
}
toRun.push(task_t(0., 0., eventsIds));
findOrLaunchScenarios(baseJobsFile, events, toRun, results_[idx]);
findOrLaunchScenarios(baseJobsFile, events, toRun, maximumVariationPassing, results_[idx]);
} else {
TraceInfo(logTag_) << "============================================================ " << Trace::endline;
TraceInfo(logTag_) << DYNAlgorithmsLog(LocalMarginValueLoadIncrease, minVariation) << Trace::endline;
Expand Down Expand Up @@ -303,7 +303,7 @@ MarginCalculationLauncher::launch() {
toRun.push(task_t(minVariation, minVariation, eventsIds));
LoadIncreaseResult liResultTmp;
liResultTmp.resize(events.size());
findOrLaunchScenarios(baseJobsFile, events, toRun, liResultTmp);
findOrLaunchScenarios(baseJobsFile, events, toRun, maximumVariationPassing, liResultTmp);
for (size_t i = 0; i < eventsIds.size(); ++i) {
results_[idx].getResult(i) = liResultTmp.getResult(eventsIds[i]);
}
Expand Down Expand Up @@ -360,7 +360,7 @@ MarginCalculationLauncher::computeGlobalMargin(const boost::shared_ptr<LoadIncre
}
}
findAllLevelsBetween(minVariation, maxVariation, tolerance, eventsIds, toRun);
findOrLaunchScenarios(baseJobsFile, events, toRun, results_[idx]);
findOrLaunchScenarios(baseJobsFile, events, toRun, maximumVariationPassing, results_[idx]);

// analyze results
unsigned int nbSuccess = 0;
Expand Down Expand Up @@ -407,6 +407,7 @@ MarginCalculationLauncher::findAllLevelsBetween(const double minVariation, const
toRun.push(task_t(minVariation, maxVariation, eventIdxs));
if (maxVariation - newVariation > tolerance)
minMaxStack.push(std::make_pair(newVariation, maxVariation));

while (toRun.size() < nbMaxToAdd && !minMaxStack.empty()) {
double min = minMaxStack.front().first;
double max = minMaxStack.front().second;
Expand Down Expand Up @@ -459,7 +460,7 @@ MarginCalculationLauncher::computeLocalMargin(const boost::shared_ptr<LoadIncrea
maxLoadVarForLoadIncrease = newVariation;
LoadIncreaseResult liResultTmp;
liResultTmp.resize(events.size());
findOrLaunchScenarios(baseJobsFile, events, toRunCopy, liResultTmp);
findOrLaunchScenarios(baseJobsFile, events, toRunCopy, results, liResultTmp);

// analyze results
task_t below(task.minVariation_, newVariation);
Expand Down Expand Up @@ -499,11 +500,13 @@ MarginCalculationLauncher::computeLocalMargin(const boost::shared_ptr<LoadIncrea
void MarginCalculationLauncher::findOrLaunchScenarios(const std::string& baseJobsFile,
const std::vector<boost::shared_ptr<Scenario> >& events,
std::queue< task_t >& toRun,
const std::vector<double >& maximumVariationPassing,
LoadIncreaseResult& result) {
if (toRun.empty()) return;
task_t task = toRun.front();
toRun.pop();
const std::vector<size_t>& eventsId = task.ids_;
std::vector<size_t> eventsIdNoFilter = task.ids_;
double newVariation = round((task.minVariation_ + task.maxVariation_)/2.);
if (mpi::context().nbProcs() == 1) {
std::string iidmFile = generateIDMFileNameForVariation(newVariation);
Expand All @@ -518,20 +521,26 @@ void MarginCalculationLauncher::findOrLaunchScenarios(const std::string& baseJob
}

auto found = scenarioStatus_.find(newVariation);
std::vector<size_t> eventsIdNotTreated;
if (found != scenarioStatus_.end()) {
TraceInfo(logTag_) << DYNAlgorithmsLog(ScenarioResultsFound, newVariation) << Trace::endline;
for (const auto& eventId : eventsId) {
auto resultId = SimulationResult::getUniqueScenarioId(events.at(eventId)->getId(), newVariation);
result.getResult(eventId) = importResult(resultId);
if (result.getResult(eventId).getStatus() == NOT_TREATED)
eventsIdNotTreated.push_back(eventId);
}
return;
if (eventsIdNotTreated.empty())
return;
else
task.ids_ = eventsIdNotTreated;
}

std::vector<std::pair<size_t, double> > events2Run;
prepareEvents2Run(task, toRun, events2Run);
std::vector<EventPair > events2Run;
prepareEvents2Run(task, eventsIdNoFilter, maximumVariationPassing, toRun, events2Run);

for (std::vector<std::pair<size_t, double> >::const_iterator itEvents = events2Run.begin(); itEvents != events2Run.end(); ++itEvents) {
double variation = itEvents->second;
for (std::vector<EventPair >::const_iterator itEvents = events2Run.begin(); itEvents != events2Run.end(); ++itEvents) {
double variation = itEvents->variation_;
std::string iidmFile = generateIDMFileNameForVariation(variation);
if (inputsByIIDM_.count(iidmFile) == 0) {
inputsByIIDM_[iidmFile].readInputs(workingDirectory_, baseJobsFile, iidmFile);
Expand All @@ -540,9 +549,9 @@ void MarginCalculationLauncher::findOrLaunchScenarios(const std::string& baseJob

std::vector<bool> successes;
mpi::forEach(0, events2Run.size(), [this, &events2Run, &events, &successes](unsigned int i){
double variation = events2Run[i].second;
double variation = events2Run[i].variation_;
std::string iidmFile = generateIDMFileNameForVariation(variation);
size_t eventIdx = events2Run[i].first;
size_t eventIdx = events2Run[i].index_;
SimulationResult resultScenario;
createScenarioWorkingDir(events.at(eventIdx)->getId(), variation);
launchScenario(inputsByIIDM_.at(iidmFile), events.at(eventIdx), variation, resultScenario);
Expand All @@ -553,8 +562,8 @@ void MarginCalculationLauncher::findOrLaunchScenarios(const std::string& baseJob
std::vector<bool> allSuccesses = synchronizeSuccesses(successes);
for (unsigned int i = 0; i < events2Run.size(); i++) {
auto& event = events2Run.at(i);
scenarioStatus_[event.second].resize(events.size());
scenarioStatus_.at(event.second).at(event.first).success = allSuccesses.at(i);
scenarioStatus_[event.variation_].resize(events.size());
scenarioStatus_.at(event.variation_).at(event.index_).success = allSuccesses.at(i);
}
assert(scenarioStatus_.count(newVariation) > 0);

Expand All @@ -564,24 +573,50 @@ void MarginCalculationLauncher::findOrLaunchScenarios(const std::string& baseJob
}

for (unsigned int i=0; i < events2Run.size(); i++) {
double variation = events2Run[i].second;
double variation = events2Run[i].variation_;
std::string iidmFile = generateIDMFileNameForVariation(variation);
inputsByIIDM_.erase(iidmFile); // remove iidm file used for scenario to save RAM
}
}

MarginCalculationLauncher::EventPair::EventPair(size_t index, double variation) : index_(index), variation_(variation) {
}

void MarginCalculationLauncher::addAvailableEvents(const double variation,
const std::vector<size_t>& eventsIdNoFilter,
const std::vector<double >& maximumVariationPassing,
std::vector<EventPair >& events2Run) {
if ((*loadIncreaseStatus_.find(variation)).second.success) {
auto found = scenarioStatus_.find(variation);
unsigned int eventIndex = 0;
while (events2Run.size() % mpi::context().nbProcs() != 0 && eventIndex < eventsIdNoFilter.size() &&
(variation > maximumVariationPassing[eventsIdNoFilter[eventIndex]] ||
DYN::doubleEquals(variation, maximumVariationPassing[eventsIdNoFilter[eventIndex]]))) {
EventPair event(eventsIdNoFilter[eventIndex], variation);
if (std::find(events2Run.begin(), events2Run.end(), event) == events2Run.end() && found == scenarioStatus_.end()) {
events2Run.push_back(event);
}
++eventIndex;
}
}
}

void
MarginCalculationLauncher::prepareEvents2Run(const task_t& requestedTask,
std::queue< task_t >& toRun,
std::vector<std::pair<size_t, double> >& events2Run) {
const std::vector<size_t>& eventsIdNoFilter,
const std::vector<double >& maximumVariationPassing,
std::queue< task_t >& toRun,
std::vector<EventPair >& events2Run) {
const std::vector<size_t>& eventsId = requestedTask.ids_;
double newVariation = round((requestedTask.minVariation_ + requestedTask.maxVariation_)/2.);

auto it = loadIncreaseStatus_.find(newVariation);
if (it != loadIncreaseStatus_.end() && it->second.success) {
for (size_t i = 0; i < eventsId.size(); ++i) {
events2Run.push_back(std::make_pair(eventsId[i], newVariation));
events2Run.push_back(EventPair(eventsId[i], newVariation));
}
}

while (events2Run.size() < mpi::context().nbProcs() && !toRun.empty()) {
task_t newTask = toRun.front();
toRun.pop();
Expand All @@ -591,9 +626,42 @@ MarginCalculationLauncher::prepareEvents2Run(const task_t& requestedTask,
if (it == loadIncreaseStatus_.end() || !it->second.success) continue;
if (scenarioStatus_.find(variation) != scenarioStatus_.end()) continue;
for (size_t i = 0, iEnd = newEventsId.size(); i < iEnd; ++i) {
events2Run.push_back(std::make_pair(newEventsId[i], variation));
events2Run.push_back(EventPair(newEventsId[i], variation));
}
}

std::list<double> variationsList;
for (const auto& loadIncrease : loadIncreaseStatus_) {
variationsList.push_back(loadIncrease.first);
}

// We try to add more scenarios to launch while number of events to run is not equal to a multiple of the number of procs
// We go through the available load increase with the same logic as they would be run through by the dichotomy,
// meaning 100 (back of the list) then 50 (front of the list) and 75 (middle of the list) for example.
std::list<double>::iterator itVariationsList = variationsList.begin();
while (itVariationsList != variationsList.end()) {
double variation = variationsList.back();
addAvailableEvents(variation, eventsIdNoFilter, maximumVariationPassing, events2Run);

variationsList.pop_back();

variation = *itVariationsList;
addAvailableEvents(variation, eventsIdNoFilter, maximumVariationPassing, events2Run);

std::list<double>::iterator middle = variationsList.begin();
std::advance(middle, std::distance(variationsList.begin(), variationsList.end())/2);
if (middle != variationsList.end()) {
variation = *middle;
addAvailableEvents(variation, eventsIdNoFilter, maximumVariationPassing, events2Run);

variationsList.erase(middle);
}

if (itVariationsList != variationsList.end() && !variationsList.empty())
itVariationsList = variationsList.erase(itVariationsList);
else
itVariationsList = variationsList.end();
}
}

void
Expand Down
61 changes: 45 additions & 16 deletions sources/Launcher/DYNMarginCalculationLauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,10 @@ class MarginCalculationLauncher : public RobustnessAnalysisLauncher {
*/
void launch();

private:
/**
* @brief create outputs file for each job
* @param mapData map associating a fileName and the data contained in the file
* @param zipIt true if we want to fill mapData to create a zip, false if we want to write the files on the disk
*/
void createOutputs(std::map<std::string, std::string>& mapData, bool zipIt) const;

/**
* @brief Description of a set of scenarios to run
*/
struct task_t{
* @brief Description of a set of scenarios to run
*/
struct task_t {
double minVariation_; ///< minimal variation that passes
double maxVariation_; ///< maximal variation that fails
std::vector<size_t> ids_; ///< indexes of the scenarios to run
Expand Down Expand Up @@ -89,6 +81,23 @@ class MarginCalculationLauncher : public RobustnessAnalysisLauncher {
}
};

struct EventPair {
EventPair(size_t index, double variation);

bool operator==(const EventPair& rhs) const { return this->index_ == rhs.index_ && DYN::doubleEquals(this->variation_, rhs.variation_);}

size_t index_;
double variation_;
};

private:
/**
* @brief create outputs file for each job
* @param mapData map associating a fileName and the data contained in the file
* @param zipIt true if we want to fill mapData to create a zip, false if we want to write the files on the disk
*/
void createOutputs(std::map<std::string, std::string>& mapData, bool zipIt) const;

/**
* @brief Research of the maximum variation value for which all the scenarios pass
* try to find the maximum load increase between 0 and 100%. Only simulate events that crashes at 100% of load increase
Expand Down Expand Up @@ -163,26 +172,46 @@ class MarginCalculationLauncher : public RobustnessAnalysisLauncher {
* @param baseJobsFile base jobs file
* @param events complete list of scenarios
* @param toRun scenarios that needs to be run
* @param maximumVariationPassing maximum variation passing found so far
* @param result result of the load increase
*
*/
void findOrLaunchScenarios(const std::string& baseJobsFile,
const std::vector<boost::shared_ptr<Scenario> >& events,
std::queue< task_t >& toRun,
LoadIncreaseResult& result);
const std::vector<boost::shared_ptr<Scenario> >& events,
std::queue< task_t >& toRun,
const std::vector<double >& maximumVariationPassing,
LoadIncreaseResult& result);

/**
* @brief Find if the scenarios associated to this variation were already done
* otherwise, launch as many load scenarios as possible in multi-threading, including the variation one
*
* @param variation load increase variation to launch
* @param eventsIdNoFilter events to run in case number of events to run is not a multiple of procs
* @param maximumVariationPassing maximum variation passing found so far
* @param events2Run will be filled with the scenario index and the level that can be run
*
*/
void addAvailableEvents(const double variation,
const std::vector<size_t>& eventsIdNoFilter,
const std::vector<double >& maximumVariationPassing,
std::vector<EventPair >& events2Run);

/**
* @brief Fill the vector with as many levels of variation you can run based on the number of available threads
*
* @param requestedTask the level of reference
* @param eventsIdNoFilter events to run in case number of events to run is not a multiple of procs
* @param maximumVariationPassing maximum variation passing found so far
* @param toRun scenarios that needs to be run
* @param events2Run will be filled with the scenario index and the level that can be run
*
*/
void prepareEvents2Run(const task_t& requestedTask,
std::queue< task_t >& toRun,
std::vector<std::pair<size_t, double> >& events2Run);
const std::vector<size_t>& eventsIdNoFilter,
const std::vector<double >& maximumVariationPassing,
std::queue< task_t >& toRun,
std::vector<EventPair >& events2Run);

/**
* @brief launch the calculation of one scenario
Expand Down
Loading

0 comments on commit d4e08cc

Please sign in to comment.