extracting functions moved and task.cpp ready to be tested

This commit is contained in:
ElonOlsson
2022-12-09 15:23:43 -05:00
parent a6c603dd43
commit 2b1cc38440
8 changed files with 201 additions and 161 deletions
@@ -29,6 +29,7 @@ set(HEADER_FILES
util/fieldlinesstate.h
util/commons.h
util/kameleonfieldlinehelper.h
tasks/kameleonvolumetofieldlinestask.h
)
source_group("Header Files" FILES ${HEADER_FILES})
@@ -37,6 +38,7 @@ set(SOURCE_FILES
util/fieldlinesstate.cpp
util/commons.cpp
util/kameleonfieldlinehelper.cpp
tasks/kameleonvolumetofieldlinestask.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
@@ -261,10 +261,6 @@ namespace {
namespace openspace {
fls::Model stringToModel(std::string str);
std::unordered_map<std::string, std::vector<glm::vec3>>
extractSeedPointsFromFiles(std::filesystem::path);
std::vector<std::string>
extractMagnitudeVarsFromStrings(std::vector<std::string> extrVars);
documentation::Documentation RenderableFieldlinesSequence::Documentation() {
return codegen::doc<Parameters>("fieldlinessequence_renderablefieldlinessequence");
@@ -577,7 +573,7 @@ bool RenderableFieldlinesSequence::prepareForOsflsStreaming() {
_states.push_back(newState);
_nStates = _startTimes.size();
if (_nStates == 1) {
// loading dynamicaly is not nessesary if only having one set in the sequence
// loading dynamicaly is not nessesary if only having one set in the sequence
_loadingStatesDynamically = false;
}
_activeStateIndex = 0;
@@ -793,10 +789,10 @@ void RenderableFieldlinesSequence::addStateToSequence(FieldlinesState& state) {
}
bool RenderableFieldlinesSequence::getStatesFromCdfFiles() {
std::vector<std::string> extraMagVars = extractMagnitudeVarsFromStrings(_extraVars);
std::vector<std::string> extraMagVars = fls::extractMagnitudeVarsFromStrings(_extraVars);
std::unordered_map<std::string, std::vector<glm::vec3>> seedsPerFiles =
extractSeedPointsFromFiles(_seedPointDirectory);
fls::extractSeedPointsFromFiles(_seedPointDirectory);
if (seedsPerFiles.empty()) {
LERROR("No seed files found");
return false;
@@ -824,101 +820,6 @@ bool RenderableFieldlinesSequence::getStatesFromCdfFiles() {
return true;
}
std::unordered_map<std::string, std::vector<glm::vec3>>
extractSeedPointsFromFiles(std::filesystem::path filePath)
{
std::unordered_map<std::string, std::vector<glm::vec3>> outMap;
if (!std::filesystem::is_directory(filePath)) {
LERROR(fmt::format(
"The specified seed point directory: '{}' does not exist", filePath
));
return outMap;
}
namespace fs = std::filesystem;
for (const fs::directory_entry& spFile : fs::directory_iterator(filePath)) {
std::string seedFilePath = spFile.path().string();
if (!spFile.is_regular_file() ||
seedFilePath.substr(seedFilePath.find_last_of('.') + 1) != "txt")
{
continue;
}
std::ifstream seedFile(seedFilePath);
if (!seedFile.good()) {
LERROR(fmt::format("Could not open seed points file '{}'", seedFilePath));
outMap.clear();
return {};
}
LDEBUG(fmt::format("Reading seed points from file '{}'", seedFilePath));
std::string line;
std::vector<glm::vec3> outVec;
while (std::getline(seedFile, line)) {
std::stringstream ss(line);
glm::vec3 point;
ss >> point.x;
ss >> point.y;
ss >> point.z;
outVec.push_back(std::move(point));
}
if (outVec.empty()) {
LERROR(fmt::format("Found no seed points in: {}", seedFilePath));
outMap.clear();
return {};
}
size_t lastIndex = seedFilePath.find_last_of('.');
std::string name = seedFilePath.substr(0, lastIndex); // remove file extention
size_t dateAndTimeSeperator = name.find_last_of('_');
std::string time = name.substr(dateAndTimeSeperator + 1, name.length());
std::string date = name.substr(dateAndTimeSeperator - 8, 8); // 8 for yyyymmdd
std::string dateAndTime = date + time;
// add outVec as value and time stamp as int as key
outMap[dateAndTime] = outVec;
}
return outMap;
}
std::vector<std::string>
extractMagnitudeVarsFromStrings(std::vector<std::string> extrVars)
{
std::vector<std::string> extraMagVars;
for (int i = 0; i < static_cast<int>(extrVars.size()); i++) {
const std::string& str = extrVars[i];
// Check if string is in the format specified for magnitude variables
if (str.substr(0, 2) == "|(" && str.substr(str.size() - 2, 2) == ")|") {
std::istringstream ss(str.substr(2, str.size() - 4));
std::string magVar;
size_t counter = 0;
while (std::getline(ss, magVar, ',')) {
magVar.erase(
std::remove_if(
magVar.begin(),
magVar.end(),
::isspace
),
magVar.end()
);
extraMagVars.push_back(magVar);
counter++;
if (counter == 3) {
break;
}
}
if (counter != 3 && counter > 0) {
extraMagVars.erase(extraMagVars.end() - counter, extraMagVars.end());
}
extrVars.erase(extrVars.begin() + i);
i--;
}
}
return extraMagVars;
}
void RenderableFieldlinesSequence::deinitializeGL() {
glDeleteVertexArrays(1, &_vertexArrayObject);
_vertexArrayObject = 0;
@@ -1046,7 +947,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
const double currentTime = data.time.j2000Seconds();
const bool isInInterval = (currentTime >= _startTimes[0]) &&
(currentTime < _sequenceEndTime);
// Check if current time in OpenSpace is within sequence interval
if (isInInterval) {
const size_t nextIdx = _activeTriggerTimeIndex + 1;
@@ -108,7 +108,7 @@ private:
// line segments
bool _shouldUpdateMaskingBuffer = false;
// note Elon: rework the case of only one state
// hasBeenUpdated only gets sets once, first iteration of update function, to
// hasBeenUpdated only gets sets once, first iteration of update function, to
// guarantee the vertext position buffer to be initialized.
bool _hasBeenUpdated = false;
@@ -23,120 +23,155 @@
****************************************************************************************/
#include <modules/fieldlinessequence/tasks/kameleonvolumetofieldlinestask.h>
#include <modules/fieldlinessequence/rendering/renderablefieldlinessequence.h>
#include <modules/fieldlinessequence/util/fieldlinesstate.h>
#include <modules/fieldlinessequence/util/kameleonfieldlinehelper.h>
#include <modules/volume/rawvolumewriter.h>
#include <openspace/util/spicemanager.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/util/time.h>
#include <ghoul/fmt.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/dictionaryluaformatter.h>
#include <ghoul/misc/dictionary.h>
#include <optional>
namespace {
constexpr const char* KeyInput = "Input";
constexpr const char* KeyTimeKernel = "TimeKernel";
constexpr const char* KeyOutputFolder = "OutputFolder";
constexpr const char* KeySeedpoints = "Seedpoints";
constexpr const char* KeyTracingVar = "TracingVar";
constexpr const char* KeyExtraScalarVars = "ExtraScalarVars";
constexpr const char* KeyExtraMagnitudeVars = "ExtraMagnitudeVars";
} // namespace
namespace {
constexpr std::string_view _loggerCat = "KameleonVolumeToFieldlinesTask";
struct [[codegen::Dictionary(KameleonVolumeToFieldLinesTask)]] Parameters {
// The cdf file to extract data from
struct [[codegen::Dictionary(KameleonVolumeToFieldlinesTask)]] Parameters {
// The folder to the cdf files to extract data from
std::filesystem::path input;
// A text file with seedpoints with the format x1 y1 z1 x2 y2 z2 ...
// Seedpoints are expressed in the native coordinate system of the model.
std::filesystem::path seedpoints
std::filesystem::path seedpoints;
// If data sets parameter start_time differ from start of run,
// elapsed_time_in_seconds might be in relation to start of run.
// ManuelTimeOffset will be added to trigger time.
std::optional<double> manualTimeOffset;
// The name of the kameleon variable to use for tracing, like b, or u
std::string tracingVar;
// The folder to write the files to
std::filesystem::path outputFolder;
enum class ConversionType {
Json,
Osfls
};
// Output type. Either osfls (OpenSpace FieldLineSequence) or json
std::string outputType;
ConversionType outputType;
// A list of vector variables to extract along the fieldlines
std::optional<std::vector<std::string>> extraScalarVars;
std::optional<std::vector<std::string>> extraVars;
};
#include "kameleonvolumetofieldlinestask_codegen.cpp"
}
} // namespace
namespace openspace {
documentation::Documentation KameleonVolumeToFieldlinesTask::documentation() {
return codegen::doc<Parameters>("kameleon_volume_to_fieldlines_task")
return codegen::doc<Parameters>("kameleon_volume_to_fieldlines_task");
}
KameleonVolumeToFieldlinesTask::KameleonVolumeToFieldlinesTask(
const ghoul::Dictionary& dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
_inputPath = p.input.value();
_seedpointsPath = p.seepoints.value();
_outputFolder = p.outputFolder.value();
_outputType = p.outputType.value();
_tracingVar = p.tracingVar.value_or(_tractingVar);
_inputPath = p.input;
_seedpointsPath = p.seedpoints;
_manualTimeOffset = p.manualTimeOffset.value_or(_manualTimeOffset);
_outputFolder = p.outputFolder;
if (dictionary.hasKey(KeyExtraScalarVars)) {
ghoul::Dictionary list = dictionary.value<ghoul::Dictionary>(KeyExtraScalarVars);
for (size_t i = 0; i < list.size(); ++i) {
_extraScalarVars.push_back(list.value<std::string>(std::to_string(i)));
switch (p.outputType) {
case Parameters::ConversionType::Json:
break;
_outputType = conversionType::Json;
case Parameters::ConversionType::Osfls:
_outputType = conversionType::Osfls;
break;
default:
LERROR("outputType must be either json or osfls");
}
_tracingVar= p.tracingVar;
//_tracingVar = p.tracingVar.value_or(_tractingVar);
if (p.extraVars.has_value()) {
for (auto var : p.extraVars.value()) {
_extraVars.push_back(var);
}
}
if (dictionary.hasKey(KeyExtraMagnitudeVars)) {
ghoul::Dictionary list =
dictionary.value<ghoul::Dictionary>(KeyExtraMagnitudeVars);
for (size_t i = 0; i < list.size(); ++i) {
_extraMagnitudeVars.push_back(list.value<std::string>(std::to_string(i)));
if (!std::filesystem::is_directory(_inputPath)) {
LERROR(fmt::format(
"KameleonVolumeToFieldlineTask: {} is not a valid directory",
_inputPath
));
}
namespace fsm = std::filesystem;
for (const fsm::directory_entry& e : fsm::directory_iterator(_inputPath)){
if (e.is_regular_file()) {
std::string eStr = e.path().string();
_sourceFiles.push_back(eStr);
}
}
}
std::string KameleonVolumeToFieldlinesTask::description() {
return fmt::format(
"Extract fieldline data from cdf file {} and seedpoint file {}. "
"Write osfls file into the folder {}.",
"Write either osfls files or json files into the folder {}.",
_inputPath, _seedpointsPath, _outputFolder
);
}
void KameleonVolumeToFieldlinesTask::perform(
const Task::ProgressCallback& progressCallback)
const Task::ProgressCallback& progressCallback)
{
std::vector<std::string> extraMagVars =
fls::extractMagnitudeVarsFromStrings(_extraVars);
std::vector<glm::vec3> seedPoints;
bool readSeedpoints = fls::extractSeedPointsFromFile(_seedpointsPath, seedPoints);
std::unordered_map<std::string, std::vector<glm::vec3>> seedPoints =
fls::extractSeedPointsFromFiles(_seedpointsPath);
if (!readSeedpoints) {
if (seedPoints.empty()) {
LERROR("Falied to read seedpoints");
return;
}
for (const std::string& cdfPath : _sourceFiles) {
FieldlinesState newState;
bool isSuccessful = fls::convertCdfToFieldlinesState(
newState,
cdfPath,
seedPoints,
_manualTimeOffset,
_tracingVar,
_extraVars,
extraMagVars
);
FieldlinesState newState;
bool isSuccessful = fls::convertCdfToFieldlinesState(
newState,
_inputPath,
seedPoints,
_tracingVar,
_extraScalarVars,
_extraMagnitudeVars
);
if (isSuccessful) {
return newState.saveStateToOsfls(_outputFolder);
if (isSuccessful) {
if (_outputType == conversionType::Osfls) {
newState.saveStateToOsfls(absPath(_outputFolder).string());
}
else if (_outputType == conversionType::Json) {
std::string timeStr = std::string(Time(newState.triggerTime()).ISO8601());
timeStr.replace(13, 1, "-");
timeStr.replace(16, 1, "-");
timeStr.replace(19, 1, "-");
std::string fileName = timeStr + "json";
newState.saveStateToJson(_outputFolder.string() + fileName);
}
}
}
// Ideally, we would want to signal about progress earlier as well, but
// convertCdfToFieldlinesState does all the work encapsulated in one function call.
progressCallback(1.0f);
@@ -32,7 +32,6 @@
#include <string>
namespace openspace {
class KameleonVolumeToFieldlinesTask : public Task {
public:
KameleonVolumeToFieldlinesTask(const ghoul::Dictionary& dictionary);
@@ -42,12 +41,17 @@ namespace openspace {
static documentation::Documentation documentation();
private:
enum class conversionType {
Json,
Osfls
};
std::string _tracingVar;
std::vector<std::string> _extraScalarVars;
std::vector<std::string> _extraMagnitudeVars;
std::vector<std::string> _extraVars;
std::filesystem::path _inputPath;
//std::string _timeKernelPath;
std::vector<std::string> _sourceFiles;
double _manualTimeOffset = 0.0;
std::filesystem::path _seedpointsPath;
conversionType _outputType;
std::filesystem::path _outputFolder;
};
@@ -217,7 +217,7 @@ bool FieldlinesState::loadStateFromJson(const std::string& pathToJsonFile,
}
/**
* \param absPath must be the path to the file (incl. filename but excl. extension!)
* \param absPath must be the path to the folder to save to.
* Directory must exist! File is created (or overwritten if already existing).
* File is structured like this: (for version 0)
* 0. int - version number of binary state file! (in case something
@@ -30,6 +30,7 @@
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#include <memory>
#include <fstream>
#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
@@ -74,6 +75,100 @@ namespace openspace::fls {
#endif // OPENSPACE_MODULE_KAMELEON_ENABLED
// ------------------------------------------------------------------------------------ //
std::unordered_map<std::string, std::vector<glm::vec3>>
extractSeedPointsFromFiles(std::filesystem::path filePath) {
std::unordered_map<std::string, std::vector<glm::vec3>> outMap;
if (!std::filesystem::is_directory(filePath)) {
LERROR(fmt::format(
"The specified seed point directory: '{}' does not exist", filePath
));
return outMap;
}
namespace fs = std::filesystem;
for (const fs::directory_entry& spFile : fs::directory_iterator(filePath)) {
std::string seedFilePath = spFile.path().string();
if (!spFile.is_regular_file() ||
seedFilePath.substr(seedFilePath.find_last_of('.') + 1) != "txt")
{
continue;
}
std::ifstream seedFile(seedFilePath);
if (!seedFile.good()) {
LERROR(fmt::format("Could not open seed points file '{}'", seedFilePath));
outMap.clear();
return {};
}
LDEBUG(fmt::format("Reading seed points from file '{}'", seedFilePath));
std::string line;
std::vector<glm::vec3> outVec;
while (std::getline(seedFile, line)) {
std::stringstream ss(line);
glm::vec3 point;
ss >> point.x;
ss >> point.y;
ss >> point.z;
outVec.push_back(std::move(point));
}
if (outVec.empty()) {
LERROR(fmt::format("Found no seed points in: {}", seedFilePath));
outMap.clear();
return {};
}
size_t lastIndex = seedFilePath.find_last_of('.');
std::string name = seedFilePath.substr(0, lastIndex); // remove file extention
size_t dateAndTimeSeperator = name.find_last_of('_');
std::string time = name.substr(dateAndTimeSeperator + 1, name.length());
std::string date = name.substr(dateAndTimeSeperator - 8, 8); // 8 for yyyymmdd
std::string dateAndTime = date + time;
// add outVec as value and time stamp as int as key
outMap[dateAndTime] = outVec;
}
return outMap;
}
std::vector<std::string>
extractMagnitudeVarsFromStrings(std::vector<std::string> extrVars) {
std::vector<std::string> extraMagVars;
for (int i = 0; i < static_cast<int>(extrVars.size()); i++) {
const std::string& str = extrVars[i];
// Check if string is in the format specified for magnitude variables
if (str.substr(0, 2) == "|(" && str.substr(str.size() - 2, 2) == ")|") {
std::istringstream ss(str.substr(2, str.size() - 4));
std::string magVar;
size_t counter = 0;
while (std::getline(ss, magVar, ',')) {
magVar.erase(
std::remove_if(
magVar.begin(),
magVar.end(),
::isspace
),
magVar.end()
);
extraMagVars.push_back(magVar);
counter++;
if (counter == 3) {
break;
}
}
if (counter != 3 && counter > 0) {
extraMagVars.erase(extraMagVars.end() - counter, extraMagVars.end());
}
extrVars.erase(extrVars.begin() + i);
i--;
}
}
return extraMagVars;
}
/** Traces field lines from the provided cdf file using kameleon and stores the data in
* the provided FieldlinesState.
* Returns `false` if it fails to create a valid state. Requires the kameleon module to
@@ -35,7 +35,10 @@ namespace openspace {
class FieldlinesState;
namespace fls {
std::unordered_map<std::string, std::vector<glm::vec3>>
extractSeedPointsFromFiles(std::filesystem::path);
std::vector<std::string>
extractMagnitudeVarsFromStrings(std::vector<std::string> extrVars);
bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string& cdfPath,
const std::unordered_map<std::string, std::vector<glm::vec3>>& seedMap,
double manualTimeOffset, const std::string& tracingVar,