Skip to content

Commit

Permalink
Initial implementation for parallel VPP output
Browse files Browse the repository at this point in the history
  • Loading branch information
aeslaughter committed Feb 18, 2020
1 parent 2a83b12 commit 6ca2eda
Show file tree
Hide file tree
Showing 24 changed files with 324 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -16,6 +16,7 @@
*.toc
*.snm
*.csv
*.csv.*
*.dylib
*.so
*.so.*
Expand Down
4 changes: 2 additions & 2 deletions framework/doc/content/syntax/VectorPostprocessors/index.md
Expand Up @@ -76,10 +76,10 @@ getScatterVectorPostprocessorValue('the_vpp_parameter_name', 'the_vector_name')
`getScatterVectorPostprocessorValue()` returns a `const ScatterVectorPostprocessorValue &`... which is a single scalar value that you don't index into. Each process receives the "correct" value and can just directly use it.
If the data in a VPP is naturally replicated on all processors a VectorPostprocessor should set `_is_broadcast = true` in its `validParams()` like so:
If the data in a VPP is naturally replicated on all processors a VectorPostprocessor should set `_auto_broadcast = false` in its `validParams()` like so:
```c++
params.set<bool>("_is_broadcast") = true;
params.set<MooseEnum>("_auto_broadcast") = "false";
```

This tells MOOSE that the data is already replicated and there is no need to broadcast it if another object is asking for it to be broadcast.
Expand Down
11 changes: 6 additions & 5 deletions framework/include/outputs/CSV.h
Expand Up @@ -75,7 +75,9 @@ class CSV : public TableOutput
* Generates a filename pattern for Vectorpostprocessors
* filebase + VPP name + time step + ".csv"
*/
std::string getVectorPostprocessorFileName(const std::string & vpp_name, bool include_time_step);
std::string getVectorPostprocessorFileName(const std::string & vpp_name,
bool include_time_step,
bool is_distributed);

private:
/// Flag for aligning data in .csv file
Expand Down Expand Up @@ -106,13 +108,12 @@ class CSV : public TableOutput
bool _create_latest_symlink;

/// Current list of VPP filenames for creating _LATEST/_FINAL symlinks
// The pair is composed of the complete filename (foo_variable_0001.csv) and the incomplete name
// (foo_variable) to which the _FINAL or _LATEST is to be applied.
std::vector<std::pair<std::string, std::string>> _latest_vpp_filenames;
// The pair is composed of the complete filename (foo_variable_0001.csv), the incomplete name
// (foo_variable) to which the _FINAL or _LATEST is to be applied, and the "is_distributed" flag
std::vector<std::tuple<std::string, std::string, bool>> _latest_vpp_filenames;

/**
* Returns the filename without the time/timestep information.
*/
std::string getVectorPostprocessorFilePrefix(const std::string & vpp_name);
};

3 changes: 2 additions & 1 deletion framework/include/problems/FEProblemBase.h
Expand Up @@ -917,7 +917,8 @@ class FEProblemBase : public SubProblem, public Restartable
VectorPostprocessorValue & declareVectorPostprocessorVector(const VectorPostprocessorName & name,
const std::string & vector_name,
bool contains_complete_history,
bool is_broadcast);
bool is_broadcast,
bool is_distributed);

/**
* Whether or not the specified VectorPostprocessor has declared any vectors
Expand Down
11 changes: 10 additions & 1 deletion framework/include/vectorpostprocessors/VectorPostprocessor.h
Expand Up @@ -12,6 +12,7 @@
// MOOSE includes
#include "MooseTypes.h"
#include "OutputInterface.h"
#include "MooseEnum.h"

// libMesh
#include "libmesh/parallel.h"
Expand Down Expand Up @@ -56,6 +57,11 @@ class VectorPostprocessor : public OutputInterface
*/
bool containsCompleteHistory() const { return _contains_complete_history; }

/**
* Return true if the VPP is operating in distributed mode.
*/
bool isDistributed() const { return _is_distributed; }

protected:
/**
* Register a new vector to fill up.
Expand All @@ -75,8 +81,11 @@ class VectorPostprocessor : public OutputInterface

const bool _contains_complete_history;

const MooseEnum & _parallel_type;

const bool _is_distributed;

const bool _is_broadcast;

std::map<std::string, VectorPostprocessorValue> _thread_local_vectors;
};

13 changes: 11 additions & 2 deletions framework/include/vectorpostprocessors/VectorPostprocessorData.h
Expand Up @@ -66,7 +66,8 @@ class VectorPostprocessorData : public Restartable, public libMesh::ParallelObje
VectorPostprocessorValue & declareVector(const std::string & vpp_name,
const std::string & vector_name,
bool contains_complete_history,
bool is_broadcast);
bool is_broadcast,
bool is_distributed);

/**
* Returns a true value if the VectorPostprocessor exists
Expand Down Expand Up @@ -126,6 +127,11 @@ class VectorPostprocessorData : public Restartable, public libMesh::ParallelObje
*/
bool containsCompleteHistory(const std::string & name) const;

/**
* Returns a Boolean indicating whether the specified VPP vectors are distributed
*/
bool isDistributed(const std::string & name) const;

/**
* Get the map of vectors for a particular VectorPostprocessor
* @param vpp_name The name of the VectorPostprocessor
Expand All @@ -151,6 +157,7 @@ class VectorPostprocessorData : public Restartable, public libMesh::ParallelObje
bool get_current = true,
bool contains_complete_history = false,
bool is_broadcast = false,
bool is_distributed = false,
bool needs_broadcast = false,
bool needs_scatter = false);
/**
Expand All @@ -177,6 +184,9 @@ class VectorPostprocessorData : public Restartable, public libMesh::ParallelObje

/// Boolean indicating whether any old vectors have been requested.
bool _needs_old;

/// Flag if data is distributed
bool _is_distributed;
};

/// The VPP data store in a map: VPP Name to vector storage
Expand All @@ -185,4 +195,3 @@ class VectorPostprocessorData : public Restartable, public libMesh::ParallelObje
std::set<std::string> _requested_items;
std::set<std::string> _supplied_items;
};

56 changes: 40 additions & 16 deletions framework/src/outputs/CSV.C
Expand Up @@ -120,7 +120,9 @@ CSV::outputVectorPostprocessors()
}

std::string
CSV::getVectorPostprocessorFileName(const std::string & vpp_name, bool include_time_step)
CSV::getVectorPostprocessorFileName(const std::string & vpp_name,
bool include_time_step,
bool is_distributed)
{
std::ostringstream file_name;
file_name << _file_base;
Expand All @@ -132,8 +134,12 @@ CSV::getVectorPostprocessorFileName(const std::string & vpp_name, bool include_t
if (include_time_step)
file_name << '_' << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
<< std::right << timeStep();

file_name << ".csv";

if (is_distributed)
file_name << "." << processor_id();

return file_name.str();
}

Expand All @@ -154,7 +160,7 @@ CSV::output(const ExecFlagType & type)
const auto & vpp_data = _problem_ptr->getVectorPostprocessorData();

// Output each VectorPostprocessor's data to a file
if (_write_vector_table && processor_id() == 0)
if (_write_vector_table)
{

// The VPP table will not write the same data twice, so to get the symlinks correct
Expand All @@ -172,28 +178,46 @@ CSV::output(const ExecFlagType & type)
it.second.sortColumns();

auto include_time_suffix = !vpp_data.containsCompleteHistory(vpp_name);
std::string fname = getVectorPostprocessorFileName(vpp_name, include_time_suffix);
std::string fprefix = getVectorPostprocessorFilePrefix(vpp_name);
_latest_vpp_filenames.emplace_back(fname, fprefix);
it.second.printCSV(fname, 1, _align);
auto is_distributed = vpp_data.isDistributed(vpp_name);

if (_create_latest_symlink)
if (is_distributed || processor_id() == 0)
{
std::string out_latest = fprefix + "_LATEST.csv";
MooseUtils::createSymlink(fname, out_latest);
}
std::string fname =
getVectorPostprocessorFileName(vpp_name, include_time_suffix, is_distributed);
std::string fprefix = getVectorPostprocessorFilePrefix(vpp_name);

_latest_vpp_filenames.emplace_back(fname, fprefix, is_distributed);

it.second.printCSV(fname, 1, _align);

if (_time_data)
_vector_postprocessor_time_tables[vpp_name].printCSV(fprefix + "_time.csv");
if (_create_latest_symlink)
{
std::ostringstream out_latest;
out_latest << fprefix << "_LATEST.csv";
if (is_distributed)
out_latest << "." << processor_id();
MooseUtils::createSymlink(fname, out_latest.str());
}

if (_time_data)
_vector_postprocessor_time_tables[vpp_name].printCSV(fprefix + "_time.csv");
}
}
}

if (type == EXEC_FINAL && _create_final_symlink && processor_id() == 0)
if (type == EXEC_FINAL && _create_final_symlink)
{
for (const auto & name_pair : _latest_vpp_filenames)
for (const auto & name_tuple : _latest_vpp_filenames)
{
std::string out_final = name_pair.second + "_FINAL.csv";
MooseUtils::createSymlink(name_pair.first, out_final);
std::ostringstream out_final;
out_final << std::get<1>(name_tuple) << "_FINAL.csv";
if (std::get<2>(name_tuple))
{
out_final << "." << processor_id();
MooseUtils::createSymlink(std::get<0>(name_tuple), out_final.str());
}
else if (processor_id() == 0)
MooseUtils::createSymlink(std::get<0>(name_tuple), out_final.str());
}
}

Expand Down
6 changes: 4 additions & 2 deletions framework/src/problems/FEProblemBase.C
Expand Up @@ -3337,9 +3337,11 @@ VectorPostprocessorValue &
FEProblemBase::declareVectorPostprocessorVector(const VectorPostprocessorName & name,
const std::string & vector_name,
bool contains_complete_history,
bool is_broadcast)
bool is_broadcast,
bool is_distributed)
{
return _vpps_data.declareVector(name, vector_name, contains_complete_history, is_broadcast);
return _vpps_data.declareVector(
name, vector_name, contains_complete_history, is_broadcast, is_distributed);
}

const std::vector<std::pair<std::string, VectorPostprocessorData::VectorPostprocessorState>> &
Expand Down
2 changes: 1 addition & 1 deletion framework/src/vectorpostprocessors/CSVReader.C
Expand Up @@ -45,7 +45,7 @@ CSVReader::validParams()

// The value from this VPP is naturally already on every processor
// TODO: Make this not the case! See #11415
params.set<bool>("_is_broadcast") = true;
params.set<bool>("_auto_broadcast") = false;

return params;
}
Expand Down
Expand Up @@ -35,7 +35,7 @@ ElementVariablesDifferenceMax::validParams()

// The value from this VPP is naturally already on every processor
// TODO: Make this not the case! See #11415
params.set<bool>("_is_broadcast") = true;
params.set<bool>("_auto_broadcast") = false;

return params;
}
Expand Down
2 changes: 1 addition & 1 deletion framework/src/vectorpostprocessors/SamplerBase.C
Expand Up @@ -30,7 +30,7 @@ SamplerBase::validParams()

// The value from this VPP is naturally already on every processor
// TODO: Make this not the case! See #11415
params.set<bool>("_is_broadcast") = true;
params.set<bool>("_auto_broadcast") = false;

return params;
}
Expand Down
Expand Up @@ -26,7 +26,7 @@ VectorOfPostprocessors::validParams()

// The value from this VPP is naturally already on every processor
// TODO: Make this not the case! See #11415
params.set<bool>("_is_broadcast") = true;
params.set<bool>("_auto_broadcast") = false;

return params;
}
Expand Down
23 changes: 19 additions & 4 deletions framework/src/vectorpostprocessors/VectorPostprocessor.C
Expand Up @@ -30,8 +30,21 @@ VectorPostprocessor::validParams()
"only a single file is output and updated with each invocation");

// VPPs can set this to true if their resulting vectors are naturally replicated in parallel
// setting this to true will keep MOOSE from unnecesarily broadcasting those vectors
params.addPrivateParam<bool>("_is_broadcast", false);
// setting this to false will keep MOOSE from unnecessarily broadcasting those vectors
params.addPrivateParam<bool>("_auto_broadcast", true);

// VPPs can operate in "distributed" mode, which disables automatic the automatic broadcasting
// and results in an individual file per processor if CSV output is enabled
MooseEnum parallel_type("DISTRIBUTED REPLICATED", "REPLICATED");
params.addParam<MooseEnum>(
"parallel_type",
parallel_type,
"Set how the data is represented within the VectorPostprocessor (VPP); 'distributed' "
"indicates that data within the VPP is distributed and no auto communication is required, "
"this setting will result in parallel output within the CSV output; 'replicated' indicates "
"that the data within the VPP is correct on processor 0, the data will automatically be "
"broadcast to all processors unless the '_auto_broadcast' param is set to false within the "
"validParams function.");

params.addParamNamesToGroup("outputs", "Advanced");
params.registerBase("VectorPostprocessor");
Expand All @@ -44,7 +57,9 @@ VectorPostprocessor::VectorPostprocessor(const InputParameters & parameters)
_vpp_fe_problem(parameters.getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
_vpp_tid(parameters.isParamValid("_tid") ? parameters.get<THREAD_ID>("_tid") : 0),
_contains_complete_history(parameters.get<bool>("contains_complete_history")),
_is_broadcast(parameters.get<bool>("_is_broadcast"))
_parallel_type(parameters.get<MooseEnum>("parallel_type")),
_is_distributed(_parallel_type == "DISTRIBUTED"),
_is_broadcast(_is_distributed || !parameters.get<bool>("_auto_broadcast"))
{
}

Expand All @@ -61,5 +76,5 @@ VectorPostprocessor::declareVector(const std::string & vector_name)
return _thread_local_vectors.emplace(vector_name, VectorPostprocessorValue()).first->second;
else
return _vpp_fe_problem->declareVectorPostprocessorVector(
_vpp_name, vector_name, _contains_complete_history, _is_broadcast);
_vpp_name, vector_name, _contains_complete_history, _is_broadcast, _is_distributed);
}

0 comments on commit 6ca2eda

Please sign in to comment.