From afd91fc4af28ef9d3cba45cb55b0db0a5ee7ccf3 Mon Sep 17 00:00:00 2001 From: Oskar Carlbaum Date: Sun, 22 Oct 2017 14:55:59 +0200 Subject: [PATCH] Move all kameleon dependency to separate files named 'kameleonfieldlinehelper' --- modules/fieldlinessequence/CMakeLists.txt | 2 + .../rendering/renderablefieldlinessequence.h | 53 ++- .../renderablefieldlinessequencesetup.cpp | 45 +-- .../util/fieldlinesstate.cpp | 249 +------------ .../fieldlinessequence/util/fieldlinesstate.h | 38 +- .../util/kameleonfieldlinehelper.cpp | 342 ++++++++++++++++++ .../util/kameleonfieldlinehelper.h | 48 +++ 7 files changed, 454 insertions(+), 323 deletions(-) create mode 100644 modules/fieldlinessequence/util/kameleonfieldlinehelper.cpp create mode 100644 modules/fieldlinessequence/util/kameleonfieldlinehelper.h diff --git a/modules/fieldlinessequence/CMakeLists.txt b/modules/fieldlinessequence/CMakeLists.txt index 195e9d93d7..c9b49768f0 100644 --- a/modules/fieldlinessequence/CMakeLists.txt +++ b/modules/fieldlinessequence/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablefieldlinessequence.h ${CMAKE_CURRENT_SOURCE_DIR}/util/fieldlinesstate.h ${CMAKE_CURRENT_SOURCE_DIR}/util/commons.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/kameleonfieldlinehelper.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -36,6 +37,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablefieldlinessequencesetup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/util/fieldlinesstate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/util/commons.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/kameleonfieldlinehelper.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h index ef4b4870bf..54f666b660 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h @@ -136,38 +136,33 @@ private: properties::TriggerProperty _pJumpToStartBtn; // Button which executes a time jump to start of sequence // --------------------- FUNCTIONS USED DURING INITIALIZATION --------------------- // - void addStateToSequence(FieldlinesState& STATE); - void computeSequenceEndTime(); - void definePropertyCallbackFunctions(); - bool extractJsonInfoFromDictionary(fls::Model& model); - bool extractMandatoryInfoFromDictionary(SourceFileType& sourceFileType); - void extractOptionalInfoFromDictionary(std::string& outputFolderPath); - void extractOsflsInfoFromDictionary(); - void extractTriggerTimesFromFileNames(); - bool loadJsonStatesIntoRAM(const std::string& outputFolder); - void loadOsflsStatesIntoRAM(const std::string& outputFolder); - void setModelDependentConstants(); - void setupProperties(); - bool prepareForOsflsStreaming(); -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED - // --- Initialization functions which require the kameleon module to be loaded! --- // - bool extractCdfInfoFromDictionary(std::string& seedFilePath, - std::string& tracingVar, - std::vector& extraVars); - bool extractSeedPointsFromFile(const std::string& path, - std::vector& outVec); - void extractMagnitudeVarsFromStrings(std::vector& extraVars, - std::vector& extraMagVars); - bool getStatesFromCdfFiles(const std::string& outputFolder); -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + void addStateToSequence(FieldlinesState& STATE); + void computeSequenceEndTime(); + void definePropertyCallbackFunctions(); + bool extractCdfInfoFromDictionary(std::string& seedFilePath, std::string& tracingVar, + std::vector& extraVars); + bool extractJsonInfoFromDictionary(fls::Model& model); + void extractMagnitudeVarsFromStrings(std::vector& extraVars, + std::vector& extraMagVars); + bool extractMandatoryInfoFromDictionary(SourceFileType& sourceFileType); + void extractOptionalInfoFromDictionary(std::string& outputFolderPath); + void extractOsflsInfoFromDictionary(); + bool extractSeedPointsFromFile(const std::string& path, std::vector& outVec); + void extractTriggerTimesFromFileNames(); + bool loadJsonStatesIntoRAM(const std::string& outputFolder); + void loadOsflsStatesIntoRAM(const std::string& outputFolder); + bool getStatesFromCdfFiles(const std::string& outputFolder); + void setModelDependentConstants(); + void setupProperties(); + bool prepareForOsflsStreaming(); // ------------------------- FUNCTIONS USED DURING RUNTIME ------------------------ // inline bool isWithinSequenceInterval(const double currentTime) const; - void readNewState(const std::string& filePath); - void updateActiveTriggerTimeIndex(const double currentTime); - void updateVertexPositionBuffer(); - void updateVertexColorBuffer(); - void updateVertexMaskingBuffer(); + void readNewState(const std::string& filePath); + void updateActiveTriggerTimeIndex(const double currentTime); + void updateVertexPositionBuffer(); + void updateVertexColorBuffer(); + void updateVertexMaskingBuffer(); }; } // namespace openspace diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp index c529394613..538186e5e0 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp @@ -24,10 +24,7 @@ #include -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED - #include - #include -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED +#include #include #include @@ -224,11 +221,9 @@ void RenderableFieldlinesSequence::initialize() { // EXTRACT SOURCE FILE TYPE SPECIFIC INFOMRATION FROM DICTIONARY & GET STATES FROM SOURCE switch (sourceFileType) { case SourceFileType::Cdf: -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED if (!getStatesFromCdfFiles(outputFolderPath)) { return; } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED break; case SourceFileType::Json: if (!loadJsonStatesIntoRAM(outputFolderPath)) { @@ -313,10 +308,6 @@ bool RenderableFieldlinesSequence::extractMandatoryInfoFromDictionary( // Verify that the input type is correct if (inputFileTypeString == ValueInputFileTypeCdf) { sourceFileType = SourceFileType::Cdf; -#ifndef OPENSPACE_MODULE_KAMELEON_ENABLED - LERROR(_name << ": CDF file inputs requires the 'Kameleon' module to be enabled!"); - return false; -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED } else if (inputFileTypeString == ValueInputFileTypeJson) { sourceFileType = SourceFileType::Json; } else if (inputFileTypeString == ValueInputFileTypeOsfls) { @@ -705,7 +696,6 @@ void RenderableFieldlinesSequence::addStateToSequence(FieldlinesState& state) { _nStates++; } -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED bool RenderableFieldlinesSequence::getStatesFromCdfFiles(const std::string& outputFolder) { std::string seedFilePath; @@ -724,30 +714,13 @@ bool RenderableFieldlinesSequence::getStatesFromCdfFiles(const std::string& outp extractMagnitudeVarsFromStrings(extraVars, extraMagVars); // Load states into RAM! - for (std::string filePath : _sourceFiles) { - // Create Kameleon object and open CDF file! - std::unique_ptr kameleon = - kameleonHelper::createKameleonObject(filePath); + for (std::string cdfPath : _sourceFiles) { FieldlinesState newState; - newState.setTriggerTime(kameleonHelper::getTime(kameleon.get())); - - if (newState.addLinesFromKameleon(kameleon.get(), seedPoints, tracingVar)) { - // The line points are in their RAW format (unscaled & maybe spherical) - // Before we scale to meters (and maybe cartesian) we must extract - // the extraQuantites, as the iterpolator needs the unaltered positions - newState.addExtraQuantities(kameleon.get(), extraVars, extraMagVars); - switch (newState.model()) { - case fls::Batsrus: - newState.scalePositions(fls::ReToMeter); - break; - case fls::Enlil : - newState.convertLatLonToCartesian(fls::AuToMeter); - break; - default: - break; - } + bool isSuccessful = fls::convertCdfToFieldlinesState(newState, cdfPath, + seedPoints, tracingVar, extraVars, extraMagVars); + if (isSuccessful) { addStateToSequence(newState); if (!outputFolder.empty()) { newState.saveStateToOsfls(outputFolder); @@ -756,9 +729,7 @@ bool RenderableFieldlinesSequence::getStatesFromCdfFiles(const std::string& outp } return true; } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED /* * Returns false if it fails to extract mandatory information! */ @@ -798,9 +769,7 @@ bool RenderableFieldlinesSequence::extractCdfInfoFromDictionary( return true; } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED bool RenderableFieldlinesSequence::extractSeedPointsFromFile( const std::string& path, std::vector& outVec) { @@ -829,14 +798,11 @@ bool RenderableFieldlinesSequence::extractSeedPointsFromFile( return true; } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED void RenderableFieldlinesSequence::extractMagnitudeVarsFromStrings( std::vector& extraVars, std::vector& extraMagVars) { - for (int i = 0; i < extraVars.size(); i++) { const std::string str = extraVars[i]; // Check if string is in the format specified for magnitude variables @@ -861,6 +827,5 @@ void RenderableFieldlinesSequence::extractMagnitudeVarsFromStrings( } } } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED } // namespace openspace diff --git a/modules/fieldlinessequence/util/fieldlinesstate.cpp b/modules/fieldlinessequence/util/fieldlinesstate.cpp index f40f28a7bf..3d61f1c384 100644 --- a/modules/fieldlinessequence/util/fieldlinesstate.cpp +++ b/modules/fieldlinessequence/util/fieldlinesstate.cpp @@ -32,241 +32,14 @@ #include -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED - #include - #include - #include -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED - namespace { std::string _loggerCat = "FieldlinesState"; const int CurrentVersion = 0; - - const std::string TAsPOverRho = "T = p/rho"; - const std::string JParallelB = "Current: mag(J||B)"; - const float ToKelvin = 72429735.6984f; // <-- [nPa]/[amu/cm^3] * ToKelvin => Temperature in Kelvin - using json = nlohmann::json; } namespace openspace { -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED -/** - * Traces and adds line vertices to state. (Also sets the simulation model variable: _model!) - * Vertices may need to be scaled to meters & converted from spherical into cartesian coordinates. - * Note that extraQuantities will NOT be set! - */ -bool FieldlinesState::addLinesFromKameleon(ccmc::Kameleon* kameleon, - const std::vector& seedPoints, - const std::string tracingVar) { - - _model = fls::stringToModel(kameleon->getModelName()); - - float innerBoundaryLimit; - - switch (_model) { - case fls::Model::Batsrus : - innerBoundaryLimit = 2.5f; // TODO specify in Lua? - break; - case fls::Model::Enlil : - innerBoundaryLimit = 0.11f; // TODO specify in Lua? - break; - default: - LERROR("OpenSpace's fieldlines sequence currently only supports CDFs from" << - "the BATSRUS and ENLIL models!" ); - return false; - } - - // --------------------------- LOAD TRACING VARIABLE ---------------------------- // - if (!kameleon->loadVariable(tracingVar)) { - LERROR("FAILED TO LOAD TRACING VARIABLE: " << tracingVar); - return false; - } - - LINFO("TRACING FIELD LINES!"); - // - LOOP THROUGH THE SEED POINTS, TRACE LINES AND CONVERT TO THE DESIRED FORMAT - // - size_t lineStart = 0; - for (glm::vec3 seed : seedPoints) { - //--------------------------------------------------------------------------// - // We have to create a new tracer (or actually a new interpolator) for each // - // new line, otherwise some issues occur // - //--------------------------------------------------------------------------// - std::unique_ptr interpolator = - std::make_unique(kameleon->model); - ccmc::Tracer tracer(kameleon, interpolator.get()); - tracer.setInnerBoundary(innerBoundaryLimit); // TODO specify in Lua? - ccmc::Fieldline ccmcFieldline = tracer.bidirectionalTrace(tracingVar, - seed.x, - seed.y, - seed.z); - const std::vector& positions = ccmcFieldline.getPositions(); - - _lineStart.push_back(lineStart); - const size_t nLinePoints = positions.size(); - _lineCount.push_back(static_cast(nLinePoints)); - lineStart += static_cast(nLinePoints); - - for (const ccmc::Point3f& p : positions) { - _vertexPositions.emplace_back( - glm::vec3(p.component1, p.component2, p.component3)); - } - } - - return _vertexPositions.size() > 0; -} -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED - -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED -void FieldlinesState::loadExtrasIntoKameleon(ccmc::Kameleon* kameleon, - std::vector& xtraScalarVars, - std::vector& xtraMagVars) { - // Load the existing SCALAR variables into kameleon. - // Remove non-existing variables from vector - for (int i = 0; i < xtraScalarVars.size(); i++) { - std::string& str = xtraScalarVars[i]; - bool isSuccesful = kameleon->doesVariableExist(str) && kameleon->loadVariable(str); - if (!isSuccesful && - (_model == fls::Model::Batsrus && (str == TAsPOverRho || str == "T" ))) { - LDEBUG("BATSRUS doesn't contain variable T for temperature. Trying to " - << "calculate it using the ideal gas law: T = pressure/density"); - const std::string p = "p", r = "rho"; - isSuccesful = kameleon->doesVariableExist(p) && kameleon->loadVariable(p) - && kameleon->doesVariableExist(r) && kameleon->loadVariable(r); - str = TAsPOverRho; - } - if (!isSuccesful) { - LWARNING("FAILED TO LOAD EXTRA VARIABLE: '" << str << "'. Ignoring it!"); - xtraScalarVars.erase(xtraScalarVars.begin() + i); - --i; - } else { - _extraQuantityNames.push_back(str); - } - } - - // Load the existing magnitude variables (should be provided in multiple of 3) - // into kameleon. Remove non-existing variables from vector - if (xtraMagVars.size() % 3 == 0) { - for (int i = 0; i < static_cast(xtraMagVars.size()); i += 3) { - std::string s1 = xtraMagVars[i]; - std::string s2 = xtraMagVars[i+1]; - std::string s3 = xtraMagVars[i+2]; - bool isSuccesful = kameleon->doesVariableExist(s1) && - kameleon->doesVariableExist(s2) && - kameleon->doesVariableExist(s3) && - kameleon->loadVariable(s1) && - kameleon->loadVariable(s2) && - kameleon->loadVariable(s3); - std::string name = "Magnitude of (" + s1 + ", "+ s2 + ", "+ s3 + ")"; - if (isSuccesful && _model == fls::Model::Batsrus && s1 == "jx" && s2 == "jy" - && s3 == "jz") { - // CCMC isn't really interested in the magnitude of current, but by the - // magnitude of the part of the current's vector that is parallel to the - // magnetic field => ensure that the magnetic variables are loaded - isSuccesful = kameleon->doesVariableExist("bx") && - kameleon->doesVariableExist("by") && - kameleon->doesVariableExist("bz") && - kameleon->loadVariable("bx") && - kameleon->loadVariable("by") && - kameleon->loadVariable("bz"); - name = JParallelB; - } - if (!isSuccesful) { - LWARNING("FAILED TO LOAD AT LEAST ONE OF THE MAGNITUDE VARIABLES: " - << s1 << ", " << s2 << " & " << s3 - << ". Removing ability to store corresponding magnitude!"); - xtraMagVars.erase(xtraMagVars.begin() + i, xtraMagVars.begin() + i + 3); - i -= 3; - } else { - _extraQuantityNames.push_back(name); - } - } - } else { - // WRONG NUMBER OF MAGNITUDE VARIABLES.. REMOVE ALL! - xtraMagVars.clear(); - LWARNING("Wrong number of variables provided for storing magnitudes. " - << "Expects multiple of 3 but " << xtraMagVars.size() - << " are provided"); - } -} -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED - -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED -/** - * Loops through _vertexPositions and extracts corresponding 'extraQuantities' att each - * position from the kameleon object using a ccmc::interpolator. - * Note that the positions MUST be unaltered (NOT scaled NOR converted to different - * coordinate system)! - * - * @param kameleon raw pointer to an already opened Kameleon object - * @param xtraScalarVars vector of strings. Strings should be names of a scalar quantities - * to load into _extraQuantites; such as: "T" for temperature or "rho" for density. - * @param xtraMagVars vector of strings. Size must be multiple of 3. Strings should be - * names of the components needed to calculate magnitude. E.g. {"ux", "uy", "uz"} will - * calculate: sqrt(ux*ux + uy*uy + uz*uz). Magnitude will be stored in _extraQuantities - */ -void FieldlinesState::addExtraQuantities(ccmc::Kameleon* kameleon, - std::vector& xtraScalarVars, - std::vector& xtraMagVars) { - - loadExtrasIntoKameleon(kameleon, xtraScalarVars, xtraMagVars); - - const size_t nXtraScalars = xtraScalarVars.size(); - const size_t nXtraMagnitudes = xtraMagVars.size() / 3; - - _extraQuantities.resize(nXtraScalars + nXtraMagnitudes); - - std::unique_ptr interpolator = - std::make_unique(kameleon->model); - - // ------ Extract all the extraQuantities from kameleon and store in state! ------ // - for (const glm::vec3& p : _vertexPositions) { - // Load the scalars! - for (size_t i = 0; i < nXtraScalars; i++) { - float val; - if (xtraScalarVars[i] == TAsPOverRho) { - val = interpolator->interpolate("p", p.x, p.y, p.z); - val *= ToKelvin; - val /= interpolator->interpolate("rho", p.x, p.y, p.z); - } else { - val = interpolator->interpolate(xtraScalarVars[i], p.x, p.y, p.z); - - // When measuring density in ENLIL CCMC multiply by the radius^2 - if (xtraScalarVars[i] == "rho" && _model == fls::Model::Enlil) { - val *= std::pow(p.x * fls::AuToMeter, 2.0f); - } - } - _extraQuantities[i].push_back(val); - } - // Calculate and store the magnitudes! - for (size_t i = 0; i < nXtraMagnitudes; ++i) { - const size_t idx = i*3; - - const float x = interpolator->interpolate(xtraMagVars[idx] , p.x, p.y, p.z); - const float y = interpolator->interpolate(xtraMagVars[idx+1], p.x, p.y, p.z); - const float z = interpolator->interpolate(xtraMagVars[idx+2], p.x, p.y, p.z); - float val; - // When looking at the current's magnitude in Batsrus, CCMC staff are - // only interested in the magnitude parallel to the magnetic field - if (_extraQuantityNames[nXtraScalars + i] == JParallelB) { - const glm::vec3 normMagnetic = glm::normalize(glm::vec3( - interpolator->interpolate("bx", p.x, p.y, p.z), - interpolator->interpolate("by", p.x, p.y, p.z), - interpolator->interpolate("bz", p.x, p.y, p.z))); - // Magnitude of the part of the current vector that's parallel to - // the magnetic field vector! - val = glm::dot(glm::vec3(x,y,z), normMagnetic); - - } else { - val = std::sqrt(x*x + y*y + z*z); - } - _extraQuantities[i + nXtraScalars].push_back(val); - } - } -} -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED - -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED /** * Converts all glm::vec3 in _vertexPositions from spherical (radius, latitude, longitude) * coordinates into cartesian coordinates. The longitude and latitude coordinates are @@ -283,15 +56,12 @@ void FieldlinesState::convertLatLonToCartesian(const float scale /* = 1.f */) { p = glm::vec3(rCosLat * cos(lon), rCosLat* sin(lon), r * sin(lat)); } } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED void FieldlinesState::scalePositions(const float scale) { for (glm::vec3& p : _vertexPositions) { p *= scale; } } -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED bool FieldlinesState::loadStateFromOsfls(const std::string& pathToOsflsFile) { std::ifstream ifs(pathToOsflsFile, std::ifstream::binary); @@ -588,9 +358,28 @@ const std::vector& FieldlinesState::extraQuantity(const size_t index, isSuccessful = true; return _extraQuantities[index]; } + LERROR("Provided Index was out of scope!"); isSuccessful = false; // return empty vector which goes out of scope hence unusable! return std::vector(); } +/** Moves the points in @param line over to _vertexPositions and updates _lineStart & _lineCount accordingly. + */ +void FieldlinesState::addLine(std::vector& line) { + const size_t nNewPoints = line.size(); + const size_t nOldPoints = _vertexPositions.size(); + _lineStart.push_back(static_cast(nOldPoints)); + _lineCount.push_back(static_cast(nNewPoints)); + _vertexPositions.reserve(nOldPoints + nNewPoints); + _vertexPositions.insert(_vertexPositions.end(), std::make_move_iterator(line.begin()), + std::make_move_iterator(line.end())); + line.clear(); +} + +void FieldlinesState::setExtraQuantityNames(std::vector& names) { + _extraQuantityNames = std::move(names); + names.clear(); + _extraQuantities.resize(_extraQuantityNames.size()); +} } // namespace openspace diff --git a/modules/fieldlinessequence/util/fieldlinesstate.h b/modules/fieldlinessequence/util/fieldlinesstate.h index 71184395c4..35b1fb9db3 100644 --- a/modules/fieldlinessequence/util/fieldlinesstate.h +++ b/modules/fieldlinessequence/util/fieldlinesstate.h @@ -43,39 +43,35 @@ namespace openspace { class FieldlinesState { public: + void convertLatLonToCartesian(const float scale = 1.f); + void scalePositions(const float scale); -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED - bool addLinesFromKameleon(ccmc::Kameleon* kameleon, - const std::vector& seedPoints, - const std::string tracingVar); - void addExtraQuantities(ccmc::Kameleon* kameleon, - std::vector& xtraScalarVars, - std::vector& xtraMagVars); - void convertLatLonToCartesian(const float scale = 1.f); - void scalePositions(const float scale); -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + bool loadStateFromOsfls(const std::string& pathToOsflsFile); + void saveStateToOsfls(const std::string& pathToOsflsFile); - bool loadStateFromOsfls(const std::string& pathToOsflsFile); - void saveStateToOsfls(const std::string& pathToOsflsFile); - - bool loadStateFromJson(const std::string& pathToJsonFile, - const fls::Model model, const float coordToMeters); - void saveStateToJson(const std::string& pathToJsonFile); + bool loadStateFromJson(const std::string& pathToJsonFile, + const fls::Model model, const float coordToMeters); + void saveStateToJson(const std::string& pathToJsonFile); // ----------------------------------- GETTERS ----------------------------------- // const std::vector>& extraQuantities() const { return _extraQuantities; } const std::vector& extraQuantityNames() const { return _extraQuantityNames; } const std::vector& lineCount() const { return _lineCount; } const std::vector& lineStart() const { return _lineStart; } - size_t nExtraQuantities() const { return _extraQuantities.size(); } fls::Model model() const { return _model; } + size_t nExtraQuantities() const { return _extraQuantities.size(); } double triggerTime() const { return _triggerTime; } const std::vector& vertexPositions() const { return _vertexPositions; } // Special getter. Returns extraQuantities[INDEX]. const std::vector& extraQuantity(const size_t INDEX, bool& isSuccesful) const; - void setTriggerTime(const double T) { _triggerTime = T; } + void setModel(const fls::Model m) { _model = m; } + void setTriggerTime(const double t) { _triggerTime = t; } + void setExtraQuantityNames(std::vector& names); + + void addLine(std::vector& line); + void appendToExtra(size_t idx, float val) { _extraQuantities[idx].push_back(val); } private: bool _isMorphable = false; @@ -87,12 +83,6 @@ private: std::vector _lineCount; std::vector _lineStart; std::vector _vertexPositions; - -#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED - void loadExtrasIntoKameleon(ccmc::Kameleon* kameleon, - std::vector& xtraScalarVars, - std::vector& xtraMagVars); -#endif // OPENSPACE_MODULE_KAMELEON_ENABLED }; } // namespace openspace diff --git a/modules/fieldlinessequence/util/kameleonfieldlinehelper.cpp b/modules/fieldlinessequence/util/kameleonfieldlinehelper.cpp new file mode 100644 index 0000000000..283207ec1c --- /dev/null +++ b/modules/fieldlinessequence/util/kameleonfieldlinehelper.cpp @@ -0,0 +1,342 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 + +#include +#include + +#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED + #include + #include + #include +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + +#include + +#include + +namespace { + std::string _loggerCat = "FieldlinesSequence[ Kameleon ]"; + + const std::string TAsPOverRho = "T = p/rho"; + const std::string JParallelB = "Current: mag(J||B)"; + const float ToKelvin = 72429735.6984f; // <-- [nPa]/[amu/cm^3] * ToKelvin => Temperature in Kelvin +} + +namespace openspace { +namespace fls { + +// -------------------- DECLARE FUNCTIONS USED (ONLY) IN THIS FILE -------------------- // +#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED + bool addLinesToState(ccmc::Kameleon* kameleon, const std::vector& seeds, + const std::string tracingVar, FieldlinesState& state); + void addExtraQuantities(ccmc::Kameleon* kameleon, + std::vector& extraScalarVars, + std::vector& extraMagVars, + FieldlinesState& state); + void prepareStateAndKameleonForExtras(ccmc::Kameleon* kameleon, + std::vector& extraScalarVars, + std::vector& extraMagVars, + FieldlinesState& state); +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED +// ----------------------------------------------------------------------------------- // + +/** 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 be activated! + * @param state, FieldlineState which should hold the extracted data + * @param cdfPath, std::string of the absolute path to a .cdf file + * @param seedPoints, vector of seed points from which to trace field lines + * @param tracingVar, which quantity to trace lines from. Typically "b" for magnetic field lines and "u" for velocity flow lines + * @param extraVars, extra scalar quantities to be stored in the FieldlinesState; e.g. "T" for temperature, "rho" for density or "P" for pressure + * @param extraMagVars, variables which should be used for extracting magnitudes, must be a multiple of 3; e.g. "ux", "uy" & "uz" to get the magnitude of the velocity vector at each line vertex + */ +bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string cdfPath, + const std::vector& seedPoints, + const std::string tracingVar, + std::vector& extraVars, + std::vector& extraMagVars) { + +#ifndef OPENSPACE_MODULE_KAMELEON_ENABLED + + LERROR("CDF inputs provided but Kameleon module is deactivated!"); + return false; + +#else // OPENSPACE_MODULE_KAMELEON_ENABLED + + // Create Kameleon object and open CDF file! + std::unique_ptr kameleon = + kameleonHelper::createKameleonObject(cdfPath); + + state.setModel(fls::stringToModel(kameleon->getModelName())); + state.setTriggerTime(kameleonHelper::getTime(kameleon.get())); + + if (addLinesToState(kameleon.get(), seedPoints, tracingVar, state)) { + // The line points are in their RAW format (unscaled & maybe spherical) + // Before we scale to meters (and maybe cartesian) we must extract + // the extraQuantites, as the iterpolator needs the unaltered positions + addExtraQuantities(kameleon.get(), extraVars, extraMagVars, state); + switch (state.model()) { + case fls::Batsrus: + state.scalePositions(fls::ReToMeter); + break; + case fls::Enlil : + state.convertLatLonToCartesian(fls::AuToMeter); + break; + default: + break; + } + + return true; + } + + return false; +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED +} + +#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED +/** + * Traces and adds line vertices to state. + * Vertices are not scaled to meters nor converted from spherical into cartesian coordinates. + * Note that extraQuantities will NOT be set! + */ +bool addLinesToState(ccmc::Kameleon* kameleon, const std::vector& seedPoints, + const std::string tracingVar, FieldlinesState& state) { + + float innerBoundaryLimit; + + switch (state.model()) { + case fls::Model::Batsrus : + innerBoundaryLimit = 2.5f; // TODO specify in Lua? + break; + case fls::Model::Enlil : + innerBoundaryLimit = 0.11f; // TODO specify in Lua? + break; + default: + LERROR("OpenSpace's fieldlines sequence currently only supports CDFs from the" + << " BATSRUS and ENLIL models!"); + return false; + } + + // ---------------------------- LOAD TRACING VARIABLE ---------------------------- // + if (!kameleon->loadVariable(tracingVar)) { + LERROR("FAILED TO LOAD TRACING VARIABLE: " + tracingVar); + return false; + } + + bool isSuccesful = false; + LINFO("TRACING FIELD LINES!"); + // LOOP THROUGH THE SEED POINTS, TRACE LINES, CONVERT POINTS TO glm::vec3 AND STORE // + for (glm::vec3 seed : seedPoints) { + //--------------------------------------------------------------------------// + // We have to create a new tracer (or actually a new interpolator) for each // + // new line, otherwise some issues occur // + //--------------------------------------------------------------------------// + std::unique_ptr interpolator = + std::make_unique(kameleon->model); + ccmc::Tracer tracer(kameleon, interpolator.get()); + tracer.setInnerBoundary(innerBoundaryLimit); // TODO specify in Lua? + ccmc::Fieldline ccmcFieldline = tracer.bidirectionalTrace(tracingVar, seed.x, + seed.y, + seed.z); + const std::vector& positions = ccmcFieldline.getPositions(); + + const size_t nLinePoints = positions.size(); + + std::vector vertices; + vertices.reserve(nLinePoints); + for (const ccmc::Point3f& p : positions) { + vertices.emplace_back(p.component1, p.component2, p.component3); + } + state.addLine(vertices); + isSuccesful = (nLinePoints > 0) ? true : isSuccesful; + } + + return isSuccesful; +} +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + +/** + * Loops through state's _vertexPositions and extracts corresponding 'extraQuantities' + * from the kameleon object using a ccmc::interpolator. + * Note that the positions MUST be unaltered (NOT scaled NOR converted to different + * coordinate system)! + * + * @param kameleon raw pointer to an already opened Kameleon object + * @param extraScalarVars vector of strings. Strings should be names of a scalar quantities + * to load into _extraQuantites; such as: "T" for temperature or "rho" for density. + * @param extraMagVars vector of strings. Size must be multiple of 3. Strings should be + * names of the components needed to calculate magnitude. E.g. {"ux", "uy", "uz"} will + * calculate: sqrt(ux*ux + uy*uy + uz*uz). Magnitude will be stored in _extraQuantities + * @param state, The FieldlinesState which the extra quantities should be added to. + */ +#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED +void addExtraQuantities(ccmc::Kameleon* kameleon, + std::vector& extraScalarVars, + std::vector& extraMagVars, FieldlinesState& state) { + + prepareStateAndKameleonForExtras(kameleon, extraScalarVars, extraMagVars, state); + + const size_t nXtraScalars = extraScalarVars.size(); + const size_t nXtraMagnitudes = extraMagVars.size() / 3; + + std::unique_ptr interpolator = + std::make_unique(kameleon->model); + + // ------ Extract all the extraQuantities from kameleon and store in state! ------ // + for (const glm::vec3 p : state.vertexPositions()) { + // Load the scalars! + for (size_t i = 0; i < nXtraScalars; i++) { + float val; + if (extraScalarVars[i] == TAsPOverRho) { + val = interpolator->interpolate("p", p.x, p.y, p.z); + val *= ToKelvin; + val /= interpolator->interpolate("rho", p.x, p.y, p.z); + } else { + val = interpolator->interpolate(extraScalarVars[i], p.x, p.y, p.z); + + // When measuring density in ENLIL CCMC multiply by the radius^2 + if (extraScalarVars[i] == "rho" && state.model() == fls::Model::Enlil) { + val *= std::pow(p.x * fls::AuToMeter, 2.0f); + } + } + state.appendToExtra(i, val); + } + // Calculate and store the magnitudes! + for (size_t i = 0; i < nXtraMagnitudes; ++i) { + const size_t idx = i*3; + + const float x = interpolator->interpolate(extraMagVars[idx] , p.x, p.y, p.z); + const float y = interpolator->interpolate(extraMagVars[idx+1], p.x, p.y, p.z); + const float z = interpolator->interpolate(extraMagVars[idx+2], p.x, p.y, p.z); + float val; + // When looking at the current's magnitude in Batsrus, CCMC staff are + // only interested in the magnitude parallel to the magnetic field + if (state.extraQuantityNames()[nXtraScalars + i] == JParallelB) { + const glm::vec3 normMagnetic = glm::normalize(glm::vec3( + interpolator->interpolate("bx", p.x, p.y, p.z), + interpolator->interpolate("by", p.x, p.y, p.z), + interpolator->interpolate("bz", p.x, p.y, p.z))); + // Magnitude of the part of the current vector that's parallel to + // the magnetic field vector! + val = glm::dot(glm::vec3(x,y,z), normMagnetic); + + } else { + val = std::sqrt(x*x + y*y + z*z); + } + state.appendToExtra(i + nXtraScalars, val); + } + } +} +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + +/** Validate the provided extra quantity variables -> load the data from the validated + * quantities into the kameleon object & add the quantity names into the state's + * _extraQuantityNames vector. + * + * @param kameleon, raw pointer to an already opened kameleon object + * @param extraScalarVars, names of scalar quantities to add to state; e.g "rho" for density + * @param extraMagVars, names of the variables used for calculating magnitudes. Must be multiple of 3. + */ +#ifdef OPENSPACE_MODULE_KAMELEON_ENABLED +void prepareStateAndKameleonForExtras(ccmc::Kameleon* kameleon, + std::vector& extraScalarVars, + std::vector& extraMagVars, + FieldlinesState& state) { + std::vector extraQuantityNames; + fls::Model model = fls::stringToModel(kameleon->getModelName()); + + // Load the existing SCALAR variables into kameleon. + // Remove non-existing variables from vector + for (int i = 0; i < extraScalarVars.size(); i++) { + std::string& str = extraScalarVars[i]; + bool isSuccesful = kameleon->doesVariableExist(str) && kameleon->loadVariable(str); + if (!isSuccesful && + (model == fls::Model::Batsrus && (str == TAsPOverRho || str == "T" ))) { + LDEBUG("BATSRUS doesn't contain variable T for temperature. Trying to " + << "calculate it using the ideal gas law: T = pressure/density"); + const std::string p = "p", r = "rho"; + isSuccesful = kameleon->doesVariableExist(p) && kameleon->loadVariable(p) + && kameleon->doesVariableExist(r) && kameleon->loadVariable(r); + str = TAsPOverRho; + } + if (!isSuccesful) { + LWARNING("FAILED TO LOAD EXTRA VARIABLE: '" << str << "'. Ignoring it!"); + extraScalarVars.erase(extraScalarVars.begin() + i); + --i; + } else { + extraQuantityNames.push_back(str); + } + } + + // Load the existing magnitude variables (should be provided in multiple of 3) + // into kameleon. Remove non-existing variables from vector + if (extraMagVars.size() % 3 == 0) { + for (int i = 0; i < static_cast(extraMagVars.size()); i += 3) { + std::string s1 = extraMagVars[i]; + std::string s2 = extraMagVars[i+1]; + std::string s3 = extraMagVars[i+2]; + bool isSuccesful = kameleon->doesVariableExist(s1) && + kameleon->doesVariableExist(s2) && + kameleon->doesVariableExist(s3) && + kameleon->loadVariable(s1) && + kameleon->loadVariable(s2) && + kameleon->loadVariable(s3); + std::string name = "Magnitude of (" + s1 + ", "+ s2 + ", "+ s3 + ")"; + if (isSuccesful && model == fls::Model::Batsrus && s1 == "jx" && s2 == "jy" + && s3 == "jz") { + // CCMC isn't really interested in the magnitude of current, but by the + // magnitude of the part of the current's vector that is parallel to the + // magnetic field => ensure that the magnetic variables are loaded + isSuccesful = kameleon->doesVariableExist("bx") && + kameleon->doesVariableExist("by") && + kameleon->doesVariableExist("bz") && + kameleon->loadVariable("bx") && + kameleon->loadVariable("by") && + kameleon->loadVariable("bz"); + name = JParallelB; + } + if (!isSuccesful) { + LWARNING("FAILED TO LOAD AT LEAST ONE OF THE MAGNITUDE VARIABLES: " + << s1 << ", " << s2 << " & " << s3 + << ". Removing ability to store corresponding magnitude!"); + extraMagVars.erase(extraMagVars.begin() + i, extraMagVars.begin() + i + 3); + i -= 3; + } else { + extraQuantityNames.push_back(name); + } + } + } else { + // WRONG NUMBER OF MAGNITUDE VARIABLES.. REMOVE ALL! + extraMagVars.clear(); + LWARNING("Wrong number of variables provided for storing magnitudes. " + << "Expects multiple of 3 but " << extraMagVars.size() + << " are provided"); + } + state.setExtraQuantityNames(extraQuantityNames); +} +#endif // OPENSPACE_MODULE_KAMELEON_ENABLED + +} // namespace fls +} // namespace openspace diff --git a/modules/fieldlinessequence/util/kameleonfieldlinehelper.h b/modules/fieldlinessequence/util/kameleonfieldlinehelper.h new file mode 100644 index 0000000000..f6f898a5ed --- /dev/null +++ b/modules/fieldlinessequence/util/kameleonfieldlinehelper.h @@ -0,0 +1,48 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_FIELDLINESSEQUENCE___KAMELEONFIELDLINEHELPER___H__ +#define __OPENSPACE_MODULE_FIELDLINESSEQUENCE___KAMELEONFIELDLINEHELPER___H__ + +#include + +#include +#include + +namespace openspace { + +class FieldlinesState; + +namespace fls { + +bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string cdfPath, + const std::vector& seedPoints, + const std::string tracingVar, + std::vector& extraVars, + std::vector& extraMagVars); + +} // namespace fls +} // namespace openspace + +#endif // __OPENSPACE_MODULE_FIELDLINESSEQUENCE___KAMELEONFIELDLINEHELPER___H__ \ No newline at end of file