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
  • Loading branch information
gautierbureau committed Sep 30, 2022
1 parent d9079c2 commit 1be8dde
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 40 deletions.
1 change: 1 addition & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
{ "name": "DYNAWO_DICTIONARIES", "value" : "dictionaries_mapping" },
{ "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" },
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") {
}
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
107 changes: 87 additions & 20 deletions sources/Launcher/DYNMarginCalculationLauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ MarginCalculationLauncher::launch() {
std::vector<double > maximumVariationPassing(events.size(), 0.);
if (result100.getSuccess()) {
findAllLevelsBetween(0., 100., 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 @@ -198,7 +198,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, 0.) << Trace::endline;
Expand Down Expand Up @@ -259,7 +259,7 @@ MarginCalculationLauncher::launch() {
toRun.push(task_t(0., 0., 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 @@ -318,7 +318,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 @@ -365,6 +365,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 @@ -417,7 +418,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 @@ -457,11 +458,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 @@ -476,20 +479,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 @@ -498,9 +507,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 @@ -511,9 +520,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);
// variation = event.second
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 @@ -523,24 +531,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 @@ -550,9 +584,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 @@ -155,26 +164,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
1 change: 1 addition & 0 deletions sources/Launcher/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_custom_target(${MODULE_NAME}-tests
"DYNAWO_DICTIONARIES=dictionaries_mapping"
"DYNAWO_ADEPT_INSTALL_DIR=${DYNAWO_HOME}"
"DYNAWO_INSTALL_OPENMODELICA=${DYNAWO_HOME}/OpenModelica"
"OPENMODELICAHOME=${DYNAWO_HOME}/OpenModelica"
"DYNAWO_XERCESC_INSTALL_DIR=${DYNAWO_HOME}"
"DYNAWO_SUITESPARSE_INSTALL_DIR=${DYNAWO_HOME}"
"DYNAWO_SUNDIALS_INSTALL_DIR=${DYNAWO_HOME}"
Expand Down
7 changes: 5 additions & 2 deletions util/envDynawoAlgorithms.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ export_var_env() {
local value=${var#*=}

if ! `expr $name : "DYNAWO_.*" > /dev/null`; then
error_exit "You must export variables with DYNAWO prefix for $name."
if [ "$name" != "OPENMODELICAHOME" ]; then
error_exit "You must export variables with DYNAWO prefix for $name."
fi
fi

if eval "[ \$$name ]"; then
Expand Down Expand Up @@ -287,6 +289,7 @@ set_environnement() {
export_var_env_force DYNAWO_CURVES_TO_HTML_DIR=$DYNAWO_HOME/sbin/curvesToHtml
export_var_env_force DYNAWO_INSTALL_DIR=$DYNAWO_HOME
export_var_env DYNAWO_INSTALL_OPENMODELICA=$DYNAWO_HOME/OpenModelica
export_var_env OPENMODELICAHOME=$DYNAWO_INSTALL_OPENMODELICA
export_var_env DYNAWO_DICTIONARIES=dictionaries_mapping

export_var_env DYNAWO_CMAKE_BUILD_OPTION=""
Expand Down Expand Up @@ -883,7 +886,7 @@ create_distrib_with_headers() {

if [ "$with_omc" = "yes" ]; then
ZIP_FILE=DynawoAlgorithms_omc_V$version.zip
else
else
ZIP_FILE=DynawoAlgorithms_headers_V$version.zip
fi

Expand Down

0 comments on commit 1be8dde

Please sign in to comment.