Skip to content

Commit

Permalink
Set DataFileName params on construction and add --show-data-files
Browse files Browse the repository at this point in the history
  • Loading branch information
loganharbour committed Dec 1, 2024
1 parent f1c9324 commit 0376dce
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 85 deletions.
44 changes: 21 additions & 23 deletions framework/doc/content/source/interfaces/DataFileInterface.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
# DataFileInterface

This class provides API for resolving paths to data files distributed alongside
This class provides an API for resolving paths to data files distributed alongside
MOOSE based apps and modules.

| Method | Description |
| - | - |
getDataFileName | Finds a data file given a `FileName` input parameter
getDataFileNameByName | Finds a data file given a relative path
getDataFileNameByPath | Finds a data file given a relative path

## `getDataFileName`
Files located in `<your_app>/data` can be registered as data paths for use in installed and in-tree
builds of applications. The MOOSE framework and MOOSE module data directories
of `moose/framework/data` and `moose/modules/*/data` are already registered. These
data directories (located at the root of an application) are installed automatically using the standard `make install`.

Files located in `moose/framework/data`, the `moose/modules/*/data`, or
`<your_app>/data` directories can be retrieved using the `getDataFileName(const
std::string & param)` function, where `param` is an input parameter of type
`DataFileName`
To make your data available for searching with this interface, register it with the following:

If the provided path is absolute, no searching will take place and the absolute
path will be used. Otherwise, `getDataFileName` will search (in this order)
- the `registerAppDataFilePath` macro in `Registry.h`, where an applications data in its root `data` directory is registered (ex: `registerAppDataFilePath("foo_bar")` for `FooBarApp`)
- the `registerNonAppDataFilePath` macro in `Registry.h`, where a general data directory is registered

- relative to the input file
- relative to all installed and registered data file directories (for an installed application)
- relative to all in-tree registered data file directories (for an in-tree build)
Once a data path is registered, it can be searched using this interface and via `DataFileName`
parameters. This search is consistent between both in-tree and installed builds of an application.

The "registered" data file directories are directories that are registered via:
When a parameter is specified as `DataFileName` type, the corresponding value that you get
via `getParam<DataFileName>` is the searched value (the user's input is used for the search).
You may also utilize the `getDataFileNameByPath()` method within this interface to manually
search for a relative path in the data without the use of a parameter (for hard-coded data). The search order for these path is the following:

- the `registerAppDataFilePath` macro in `Registry.h`, where an applications data in its root `data` directory is registered
- the `registerNonAppDataFilePath` macro in `Registry.h`, where a general data directory is registered

## `getDataFileNameByPath`
- if the path is absolute, use the absolute path
- relative to the input file (only for `DataFileName` parameters, not `getDataFileNameByPath()`)
- relative to all installed and registered data file directories (for an installed application)
- relative to all in-tree registered data file directories (for an in-tree build)

The `getDataFileNameByPath` can be used for hard coded data file names. e.g.
data files that are tied to a specific model and are not meant to be user
replaceable. This method will not search relative to the input file location and
will only find data files in source repositories and installed binary
distributions.
You can see the file paths that were found in the search for all `DataFileName` parameters
via the `--show-data-files` command line option.
14 changes: 4 additions & 10 deletions framework/include/interfaces/DataFileInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ class DataFileInterface
DataFileInterface(const ParallelParamObject & parent);

/**
* Returns the path of a data file for a given FileName type parameter, searching
* (in the following order)
* - relative to the input file directory
* - relative to the running binary (assuming the application is installed)
* - relative to all registered data file directories
* Deprecated method.
*
* The data file paths are now automatically set within the InputParameters
* object, so using getParam<DataFileName>("param_name") is now sufficient.
*/
std::string getDataFileName(const std::string & param) const;

Expand All @@ -49,10 +48,5 @@ class DataFileInterface
std::string getDataFileNameByPath(const std::string & path) const;

private:
/**
* Internal helper for getting a data file name.
*/
std::string getDataFileNameInternal(const std::string & path, const std::string * param) const;

const ParallelParamObject & _parent;
};
5 changes: 5 additions & 0 deletions framework/include/outputs/ConsoleUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ std::string outputSystemInformationHelper(System & system);
*/
std::string outputLegacyInformation(MooseApp & app);

/**
* Output the (param path = value) pairs for each DataFileName parameter
*/
std::string outputDataFileParams(MooseApp & app);

/**
* Helper function function for stringstream formatting
*/
Expand Down
8 changes: 8 additions & 0 deletions framework/include/utils/InputParameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "MultiMooseEnum.h"
#include "ExecFlagEnum.h"
#include "Conversion.h"
#include "DataFileUtils.h"

#include "libmesh/parameters.h"

Expand Down Expand Up @@ -1112,6 +1113,11 @@ class InputParameters : public Parameters
*/
bool isFinalized() const { return _finalized; }

/**
* @return The DataFileName path for the parameter \p name (if any).
*/
std::optional<Moose::DataFileUtils::Path> queryDataFileNamePath(const std::string & name) const;

private:
// Private constructor so that InputParameters can only be created in certain places.
InputParameters();
Expand Down Expand Up @@ -1152,6 +1158,8 @@ class InputParameters : public Parameters
std::string _custom_type;
/// The data pertaining to a command line parameter (empty if not a command line param)
std::optional<CommandLineMetadata> _cl_data;
/// The searched path information pertaining to a DataFileName parameter
std::optional<Moose::DataFileUtils::Path> _data_file_name_path;
/// The names of the parameters organized into groups
std::string _group;
/// The map of functions used for range checked parameters
Expand Down
5 changes: 5 additions & 0 deletions framework/src/base/MooseApp.C
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ MooseApp::validParams()
"To generate profiling report only on comma-separated list of MPI ranks.");
#endif

params.addCommandLineParam<bool>("show_data_files",
"--show-data-files",
false,
"Show found paths for all DataFileName parameters");

params.addPrivateParam<std::string>("_app_name"); // the name passed to AppFactory::create
params.addPrivateParam<std::string>("_type");
params.addPrivateParam<int>("_argc");
Expand Down
54 changes: 22 additions & 32 deletions framework/src/interfaces/DataFileInterface.C
Original file line number Diff line number Diff line change
Expand Up @@ -12,64 +12,54 @@
#include "ParallelParamObject.h"
#include "DataFileUtils.h"

#include <optional>

DataFileInterface::DataFileInterface(const ParallelParamObject & parent) : _parent(parent) {}

std::string
DataFileInterface::getDataFileName(const std::string & param) const
{
// The path from the parameters, which has not been modified because it is a DataFileName
const auto & path = _parent.template getParam<DataFileParameterType>(param);
if (path.empty())
_parent.paramInfo(param, "Data file name is empty");

return getDataFileNameInternal(path, &param);
_parent.mooseDeprecated("getDataFileName() is deprecated. The file path is now directly set "
"within the InputParameters.\nUse getParam<DataFileName>(\"",
param,
"\") instead.");
return _parent.parameters().get<DataFileName>(param);
}

std::string
DataFileInterface::getDataFileNameByPath(const std::string & path) const
{
return getDataFileNameInternal(path, nullptr);
}

std::string
DataFileInterface::getDataFileNameInternal(const std::string & path,
const std::string * param) const
{
const std::string base =
param ? _parent.parameters().getFileBase(*param) : _parent.parameters().getFileBase();
// Throw on error so that if getPath() fails, we can throw an error
// with the context of _parent.mooseError()
const auto throw_on_error_before = Moose::_throw_on_error;
Moose::_throw_on_error = true;
std::optional<std::string> error;

Moose::DataFileUtils::Path found_path;
try
{
found_path = Moose::DataFileUtils::getPath(path, base);
found_path = Moose::DataFileUtils::getPath(path);
}
catch (MooseException & e)
{
if (param)
_parent.paramError(*param, e.what());
else
_parent.mooseError(e.what());
error = e.what();
}

if (found_path.context == Moose::DataFileUtils::Context::RELATIVE)
{
mooseAssert(!found_path.data_name, "Should not be set");
mooseAssert(param, "Should only hit when param is set");
_parent.paramInfo(*param, "Data file '", path, "' found relative to the input file.");
}
else if (found_path.context == Moose::DataFileUtils::Context::DATA)
Moose::_throw_on_error = throw_on_error_before;
if (error)
_parent.mooseError(*error);

if (found_path.context == Moose::DataFileUtils::Context::DATA)
{
mooseAssert(found_path.data_name, "Should be set");
const std::string msg =
"Using data file '" + found_path.path + "' from " + *found_path.data_name + " data";
if (param)
_parent.paramInfo(*param, msg);
else
_parent.mooseInfo(msg);
_parent.mooseInfo(msg);
}
else
{
mooseAssert(found_path.context == Moose::DataFileUtils::Context::ABSOLUTE, "Missing branch");
mooseAssert(found_path.context == Moose::DataFileUtils::Context::ABSOLUTE,
"Missing branch and relative should not be hit");
mooseAssert(!found_path.data_name, "Should not be set");
}

Expand Down
3 changes: 3 additions & 0 deletions framework/src/outputs/Console.C
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,9 @@ Console::outputSystemInformation()
if (_system_info_flags.isValueSet("execution"))
_console << ConsoleUtils::outputExecutionInformation(_app, *_problem_ptr);

if (_app.getParam<bool>("show_data_files"))
_console << ConsoleUtils::outputDataFileParams(_app);

if (_system_info_flags.isValueSet("output"))
_console << ConsoleUtils::outputOutputInformation(_app);

Expand Down
24 changes: 24 additions & 0 deletions framework/src/outputs/ConsoleUtils.C
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "OutputWarehouse.h"
#include "SystemInfo.h"
#include "Checkpoint.h"
#include "InputParameterWarehouse.h"

#include "libmesh/string_to_enum.h"

Expand Down Expand Up @@ -431,6 +432,29 @@ outputLegacyInformation(MooseApp & app)
return oss.str();
}

std::string
outputDataFileParams(MooseApp & app)
{
std::map<std::string, std::string> values; // for A-Z sort
for (const auto & object_name_params_pair : app.getInputParameterWarehouse().getInputParameters())
{
const auto & params = object_name_params_pair.second;
for (const auto & name_value_pair : *params)
{
const auto & name = name_value_pair.first;
if (const auto path = params->queryDataFileNamePath(name))
if (params->getHitNode(name))
values.emplace(params->paramFullpath(name), path->path);
}
}

std::stringstream oss;
oss << "Data File Parameters:\n";
for (const auto & [param, value] : values)
oss << " " << param << " = " << value << "\n";
return oss.str() + '\n';
}

void
insertNewline(std::stringstream & oss, std::streampos & begin, std::streampos & curr)
{
Expand Down
4 changes: 2 additions & 2 deletions framework/src/utils/DataFileUtils.C
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ getPath(const std::string & path,
// Found none
else
{
oss << "Unable to find the data file '" << path << "' anywhere.";
oss << "Unable to find the data file '" << path << "' anywhere.\n\n";
if (not_found.size())
{
oss << " Paths searched:\n";
oss << "Paths searched:\n";
for (const auto & [name, data_path] : not_found)
oss << " " << name << ": " << data_path << "\n";
}
Expand Down
34 changes: 34 additions & 0 deletions framework/src/utils/InputParameters.C
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,34 @@ InputParameters::finalize(const std::string & parsing_syntax)
set_if_filename(MeshFileName);
set_if_filename(MatrixFileName);
#undef set_if_filename
// Set paths for data files
else if (auto data_file_name =
dynamic_cast<Parameters::Parameter<DataFileName> *>(param_value.get()))
{
Moose::DataFileUtils::Path found_path;
std::optional<std::string> error;

// Catch this so that we can add additional error context if it fails (the param path)
const auto throw_on_error_before = Moose::_throw_on_error;
Moose::_throw_on_error = true;
try
{
found_path = Moose::DataFileUtils::getPath(data_file_name->get(), getFileBase(param_name));
}
catch (std::exception & e)
{
error = errorPrefix(param_name) + " " + e.what();
}
Moose::_throw_on_error = throw_on_error_before;

if (error)
mooseError(*error);

// Set the value to the absolute searched path
data_file_name->set() = found_path.path;
// And store the path in metadata so that we can dump it later
at(param_name)._data_file_name_path = found_path;
}
}

_finalized = true;
Expand Down Expand Up @@ -1688,6 +1716,12 @@ InputParameters::paramAliases(const std::string & param_name) const
return aliases;
}

std::optional<Moose::DataFileUtils::Path>
InputParameters::queryDataFileNamePath(const std::string & name) const
{
return at(checkForRename(name))._data_file_name_path;
}

void
InputParameters::callMooseErrorHelper(const MooseBase & moose_base, const std::string & error)
{
Expand Down
30 changes: 24 additions & 6 deletions test/src/userobjects/DataFileNameTest.C
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,40 @@

#include "DataFileNameTest.h"

#include "ExecutablePath.h"

#include <filesystem>

registerMooseObject("MooseTestApp", DataFileNameTest);

InputParameters
DataFileNameTest::validParams()
{
InputParameters params = GeneralUserObject::validParams();
params.addRequiredParam<DataFileName>("data_file", "Data file to look up");
params.addParam<DataFileName>("data_file",
"Data file to look up that is loaded from the params)");
params.addParam<std::string>("data_file_by_path", "Data file to look up by path (not param)");
params.addParam<DataFileName>("data_file_deprecated",
"Data file to look up that is loaded from the deprecated method");
return params;
}

DataFileNameTest::DataFileNameTest(const InputParameters & parameters)
: GeneralUserObject(parameters)
{
// a data file name supplied through an input parameter
mooseInfo(getDataFileName("data_file"));

// a hard coded data file name
mooseInfo(getDataFileNameByPath("README.md"));
const auto print_path = [&](const std::string & name, const std::string & path)
{
_console << name
<< "_relative=" << std::filesystem::relative(path, std::filesystem::current_path())
<< std::endl;
_console << name << "_relative_to_binary="
<< std::filesystem::relative(path, Moose::getExecutablePath()) << std::endl;
};
if (isParamSetByUser("data_file"))
print_path("data_file", getParam<DataFileName>("data_file"));
if (isParamSetByUser("data_file_by_path"))
print_path("data_file_by_path",
getDataFileNameByPath(getParam<std::string>("data_file_by_path")));
if (isParamSetByUser("data_file_deprecated"))
print_path("data_file_deprecated", getDataFileName("data_file_deprecated"));
}
1 change: 0 additions & 1 deletion test/tests/misc/data_file_name/test.i
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
[UserObjects]
[data_file]
type = DataFileNameTest
data_file = README.md
[]
[]

Expand Down
Loading

0 comments on commit 0376dce

Please sign in to comment.