Files
OpenSpace/modules/volume/tasks/generaterawvolumetask.cpp
Alexander Bock 81fda6c8db Update Ghoul repository
Adapt to changes in Ghoul
2020-02-12 00:01:24 +01:00

239 lines
9.4 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2020 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/volume/tasks/generaterawvolumetask.h>
#include <modules/volume/rawvolume.h>
#include <modules/volume/rawvolumemetadata.h>
#include <modules/volume/rawvolumewriter.h>
#include <openspace/documentation/verifier.h>
#include <openspace/util/time.h>
#include <openspace/util/spicemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/lua/luastate.h>
#include <ghoul/lua/lua_helper.h>
#include <ghoul/misc/dictionaryluaformatter.h>
#include <ghoul/misc/defer.h>
#include <fstream>
namespace {
constexpr const char* KeyRawVolumeOutput = "RawVolumeOutput";
constexpr const char* KeyDictionaryOutput = "DictionaryOutput";
constexpr const char* KeyDimensions = "Dimensions";
constexpr const char* KeyTime = "Time";
constexpr const char* KeyValueFunction = "ValueFunction";
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
} // namespace
namespace openspace {
namespace volume {
GenerateRawVolumeTask::GenerateRawVolumeTask(const ghoul::Dictionary& dictionary)
{
openspace::documentation::testSpecificationAndThrow(
documentation(),
dictionary,
"GenerateRawVolumeTask"
);
_rawVolumeOutputPath = absPath(dictionary.value<std::string>(KeyRawVolumeOutput));
_dictionaryOutputPath = absPath(dictionary.value<std::string>(KeyDictionaryOutput));
_dimensions = glm::uvec3(dictionary.value<glm::vec3>(KeyDimensions));
_time = dictionary.value<std::string>(KeyTime);
_valueFunctionLua = dictionary.value<std::string>(KeyValueFunction);
_lowerDomainBound = dictionary.value<glm::vec3>(KeyLowerDomainBound);
_upperDomainBound = dictionary.value<glm::vec3>(KeyUpperDomainBound);
}
std::string GenerateRawVolumeTask::description() {
return "Generate a raw volume with dimenstions: (" +
std::to_string(_dimensions.x) + ", " +
std::to_string(_dimensions.y) + ", " +
std::to_string(_dimensions.z) + "). " +
"For each cell, set the value by evaluating the lua function: " +
"`" + _valueFunctionLua + "`, with three arguments (x, y, z) ranging from " +
"(" + std::to_string(_lowerDomainBound.x) + ", "
+ std::to_string(_lowerDomainBound.y) + ", " +
std::to_string(_lowerDomainBound.z) + ") to (" +
std::to_string(_upperDomainBound.x) + ", " +
std::to_string(_upperDomainBound.y) + ", " +
std::to_string(_upperDomainBound.z) + ")." +
"Write raw volume data into " + _rawVolumeOutputPath +
" and dictionary with metadata to " + _dictionaryOutputPath;
}
void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallback) {
// Spice kernel is required for time conversions.
// Todo: Make this dependency less hard coded.
SpiceManager::KernelHandle kernel =
SpiceManager::ref().loadKernel(absPath("${DATA}/assets/spice/naif0012.tls"));
defer {
SpiceManager::ref().unloadKernel(kernel);
};
volume::RawVolume<float> rawVolume(_dimensions);
progressCallback(0.1f);
ghoul::lua::LuaState state;
ghoul::lua::runScript(state, _valueFunctionLua);
ghoul::lua::verifyStackSize(state, 1);
int functionReference = luaL_ref(state, LUA_REGISTRYINDEX);
ghoul::lua::verifyStackSize(state, 0);
glm::vec3 domainSize = _upperDomainBound - _lowerDomainBound;
float minVal = std::numeric_limits<float>::max();
float maxVal = std::numeric_limits<float>::min();
rawVolume.forEachVoxel([&](glm::uvec3 cell, float) {
glm::vec3 coord = _lowerDomainBound +
glm::vec3(cell) / glm::vec3(_dimensions) * domainSize;
ghoul::lua::verifyStackSize(state, 0);
lua_rawgeti(state, LUA_REGISTRYINDEX, functionReference);
lua_pushnumber(state, coord.x);
lua_pushnumber(state, coord.y);
lua_pushnumber(state, coord.z);
ghoul::lua::verifyStackSize(state, 4);
if (lua_pcall(state, 3, 1, 0) != LUA_OK) {
return;
}
float value = static_cast<float>(luaL_checknumber(state, 1));
lua_pop(state, 1);
rawVolume.set(cell, value);
minVal = std::min(minVal, value);
maxVal = std::max(maxVal, value);
});
luaL_unref(state, LUA_REGISTRYINDEX, functionReference);
ghoul::filesystem::File file(_rawVolumeOutputPath);
const std::string directory = file.directoryName();
if (!FileSys.directoryExists(directory)) {
FileSys.createDirectory(directory, ghoul::filesystem::FileSystem::Recursive::Yes);
}
volume::RawVolumeWriter<float> writer(_rawVolumeOutputPath);
writer.write(rawVolume);
progressCallback(0.9f);
RawVolumeMetadata metadata;
metadata.time = Time::convertTime(_time);
metadata.dimensions = _dimensions;
metadata.hasDomainUnit = true;
metadata.domainUnit = "m";
metadata.hasValueUnit = true;
metadata.valueUnit = "K";
metadata.gridType = VolumeGridType::Cartesian;
metadata.hasDomainBounds = true;
metadata.lowerDomainBound = _lowerDomainBound;
metadata.upperDomainBound = _upperDomainBound;
metadata.hasValueRange = true;
metadata.minValue = minVal;
metadata.maxValue = maxVal;
ghoul::Dictionary outputDictionary = metadata.dictionary();
std::string metadataString = ghoul::formatLua(outputDictionary);
std::fstream f(_dictionaryOutputPath, std::ios::out);
f << "return " << metadataString;
f.close();
progressCallback(1.0f);
}
documentation::Documentation GenerateRawVolumeTask::documentation() {
using namespace documentation;
return {
"GenerateRawVolumeTask",
"generate_raw_volume_task",
{
{
"Type",
new StringEqualVerifier("GenerateRawVolumeTask"),
Optional::No,
"The type of this task",
},
{
KeyValueFunction,
new StringAnnotationVerifier("A lua expression that returns a function "
"taking three numbers as arguments (x, y, z) and returning a number."),
Optional::No,
"The lua function used to compute the cell values",
},
{
KeyRawVolumeOutput,
new StringAnnotationVerifier("A valid filepath"),
Optional::No,
"The raw volume file to export data to",
},
{
KeyDictionaryOutput,
new StringAnnotationVerifier("A valid filepath"),
Optional::No,
"The lua dictionary file to export metadata to",
},
{
KeyDimensions,
new DoubleVector3Verifier,
Optional::No,
"A vector representing the number of cells in each dimension",
},
{
KeyLowerDomainBound,
new DoubleVector3Verifier,
Optional::No,
"A vector representing the lower bound of the domain"
},
{
KeyUpperDomainBound,
new DoubleVector3Verifier,
Optional::No,
"A vector representing the upper bound of the domain"
}
}
};
}
} // namespace volume
} // namespace openspace