Skip to content
Snippets Groups Projects
Commit 618cfa27 authored by 数学の武士's avatar 数学の武士
Browse files

Initial commit

parents
No related merge requests found
cmake_minimum_required (VERSION 3.17.0)
project(IceThermo VERSION 1.0.0)
# C/C++ compilers
enable_language (CXX C)
# set C++ standart
if(NOT "${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 17)
endif()
# options
option(USE_JSON_OUTPUT "Link library with nlohmann::json" OFF)
option(COMPILE_TESTS "Compile tests" OFF)
option(COMPILE_EXAMPLES "Compile examples" OFF)
option(COMPILE_ITSLAV "Compile IceThermo intefaces for SLAV model" OFF)
option(COMPILE_ITINMCM "Compile IceThermo intefaces for INMCM model" OFF)
# add Fortran support if SLAV interfaces are compiled
if (COMPILE_ITSLAV)
MESSAGE(STATUS "SLAV interfaces compilation ENABLED")
enable_language (Fortran)
endif()
# add Fortran support if INMCM interfaces are compiled
if (COMPILE_ITINMCM)
MESSAGE(STATUS "INMCM interfaces compilation ENABLED")
enable_language (Fortran)
endif()
# add subdirectory with source code
add_subdirectory(source)
if (COMPILE_ITSLAV)
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
# make library
add_library(icethermo STATIC ${SOURCE} ${HEADER})
# include directories
target_include_directories(icethermo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_include_directories(icethermo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/source/headers")
target_include_directories(icethermo PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
if (COMPILE_ITINMCM)
target_include_directories(icethermo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/source/applications/itinmcm")
endif()
# link library with nlohmann::json
if (USE_JSON_OUTPUT)
target_compile_definitions(icethermo PUBLIC USE_JSON_OUTPUT)
find_package(nlohmann_json 3.2.0 REQUIRED)
target_link_libraries(icethermo PUBLIC nlohmann_json::nlohmann_json)
endif()
# compile tests
if(COMPILE_TESTS)
MESSAGE(STATUS "Test compiling ENABLED")
add_subdirectory(tests)
endif(COMPILE_TESTS)
# compile examples
if (COMPILE_EXAMPLES)
MESSAGE(STATUS "Examples compiling ENABLED")
add_subdirectory(examples)
endif()
#pragma once
#include <iostream>
#include <limits>
namespace icethermo
{
#define THERMO_ERR(message) {std::cerr << "Error: " << message << std::endl; exit(1);}
#define REAL_MIN_VAL(NumType) std::numeric_limits<NumType>::min()*1e10
#define ALLOWABLE_RELATIVE_1D_ERROR 1e-1
#define SNOW_THICKNESS_THRESHOLD 1e-3
#define NAN_TEMP_VALUE -1000000.0
#define NAN_THICK_VALUE -1000000.0
#define MAX_1D_SOLVER_ITS 30
#define MAX_RELAXATION_ITS 10
#define NONLIN_SOLVER_ACCUR 1e-3
}
#pragma once
#include <vector>
#include <map>
#include <string>
#include <utility>
#include <numeric>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <memory>
#ifdef USE_JSON_OUTPUT
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#endif
#include "defines.hpp"
#include "matvec.hpp"
namespace icethermo
{
template <typename NumType>
class Mesh
{
public:
// Constructors
Mesh(); // default constructor for empty mesh
Mesh(NumType thickness); // constructor with 10 uniform layers with given thicknes
Mesh(int n_uniform_layers, NumType thickness); // constructor with given number of uniform layers and given thickness
Mesh(const std::vector<NumType>& unit_segment_decomposition, NumType thickness); // constructor with manual partition for sigma layer grid and thickness
Mesh(const Mesh<NumType>& other); // copy constructor
~Mesh(); // destructor
// cells and nodes number getters
int GetCellsNum() const;
int GetNodesNum() const;
// Creators of single, cells and nodes data
std::shared_ptr<NumType> CreateSingleData(const std::string& varname, bool visible = true);
std::shared_ptr<std::vector<NumType>> CreateCellsData(const std::string& varname, bool visible = true);
std::shared_ptr<std::vector<NumType>> CreateNodesData(const std::string& varname, bool visible = true);
// Deleters of single, cells and nodes data
void DeleteSingleData(const std::string& varname);
void DeleteCellsData(const std::string& varname);
void DeleteNodesData(const std::string& varname);
// Getters of single, cells and nodes data
std::shared_ptr<NumType> GetSingleData(const std::string& varname);
std::shared_ptr<std::vector<NumType>> GetCellsData(const std::string& varname);
std::shared_ptr<std::vector<NumType>> GetNodesData(const std::string& varname);
// Getter for cell thicknesses and total thickness
std::shared_ptr<std::vector<NumType>> GetCellsThickness();
NumType GetTotalThickness() const;
// Muters and Unmuters
void MuteSingleData(const std::string& varname);
void MuteCellData(const std::string& varname);
void MuteNodeData(const std::string& varname);
void UnmuteSingleData(const std::string& varname);
void UnmuteCellData(const std::string& varname);
void UnmuteNodeData(const std::string& varname);
// Write mesh to File
void SaveTXT(const std::string& filename) const;
void SaveTXT(const std::string& filename, int postscript) const;
#ifdef USE_JSON_OUTPUT
void SaveJSON(const std::string& filename) const;
void SaveJSON(const std::string& filename, int postscript) const;
#endif
// Check existency of data
bool CheckCellsDataExistency(const std::string& varname) const;
bool CheckNodesDataExistency(const std::string& varname) const;
bool CheckSingleDataExistency(const std::string& varname) const;
private:
// vector of cell thicknesses
std::shared_ptr<std::vector<NumType>> cells_thickness;
// container for stand-alone variables
std::map<std::string, std::pair<std::shared_ptr<NumType>, bool>> single_data;
// container for cell data [name : {vector_of_values, is_visible}]
std::map<std::string, std::pair<std::shared_ptr<std::vector<NumType>>, bool>> cells_data;
// container for node data [name : {vector_of_values, is_visible}]
std::map<std::string, std::pair<std::shared_ptr<std::vector<NumType>>, bool>> nodes_data;
};
}
\ No newline at end of file
#include "mesh.hpp"
namespace icethermo
{
template<typename NumType>
Mesh<NumType>::Mesh()
{
};
template<typename NumType>
Mesh<NumType>::Mesh(int n_uniform_layers, NumType thickness)
{
if (n_uniform_layers <= 0)
{
THERMO_ERR("Number of layers in mesh should be greater than 1!");
}
std::vector<NumType> thicknesses(n_uniform_layers);
for (int i =0; i < n_uniform_layers; ++i)
{
thicknesses[i] = thickness/n_uniform_layers;
}
cells_thickness = std::make_shared<std::vector<NumType>>(std::move(thicknesses));
}
template<typename NumType>
Mesh<NumType>::Mesh(NumType thickness): Mesh(10, thickness)
{
}
template<typename NumType>
Mesh<NumType>::Mesh(const std::vector<NumType>& unit_segment_decomposition, NumType thickness)
{
NumType sum_decomp = sum_vec(unit_segment_decomposition);
if (std::abs(sum_decomp - 1.0) > 1e-5)
{
THERMO_ERR("Unit segment decomposition of length 1.0 should be given!");
}
std::vector<NumType> thicknesses = unit_segment_decomposition*thickness;
cells_thickness = std::make_shared<std::vector<NumType>>(thicknesses);
}
template<typename NumType>
Mesh<NumType>::Mesh(const Mesh<NumType>& other)
{
this->cells_thickness = std::make_shared<std::vector<NumType>>(*(other.cells_thickness));
for (auto item: other.single_data)
{
auto key = item.first;
auto value = item.second;
(this->single_data)[key] =
std::make_pair
(
std::make_shared<NumType>(*(value.first)),
value.second
);
}
for (auto item: other.cells_data)
{
auto key = item.first;
auto value = item.second;
(this->cells_data)[key] =
std::make_pair
(
std::make_shared<std::vector<NumType>>(*(value.first)),
value.second
);
}
for (auto item: other.nodes_data)
{
auto key = item.first;
auto value = item.second;
(this->nodes_data)[key] =
std::make_pair
(
std::make_shared<std::vector<NumType>>(*(value.first)),
value.second
);
}
}
template<typename NumType>
Mesh<NumType>::~Mesh()
{
//delete cells_thickness.get();
//std::cout << 111 << std::endl;
//for (auto item: this->single_data)
//{
// auto value = item.second;
// delete (value.first).get();
//}
//std::cout << 222 << std::endl;
//for (auto item: this->cells_data)
//{
// auto value = item.second;
// delete (value.first).get();
//}
//std::cout << 333 << std::endl;
//for (auto item: this->nodes_data)
//{
// auto value = item.second;
// delete (value.first).get();
//}
//std::cout << 444 << std::endl;
}
template<typename NumType>
int Mesh<NumType>::GetCellsNum() const
{
return cells_thickness->size();
}
template<typename NumType>
int Mesh<NumType>::GetNodesNum() const
{
return cells_thickness->size() + 1;
}
template<typename NumType>
std::shared_ptr<NumType> Mesh<NumType>::CreateSingleData(const std::string& varname, bool visible)
{
if (single_data.count(varname) != 0)
{
THERMO_ERR("Variable \'" + varname + "\' already exists, could not create single variable!");
}
NumType zero_val = 0;
single_data[varname] = {std::make_shared<NumType>(std::move(zero_val)), visible};
return single_data[varname].first;
}
template<typename NumType>
std::shared_ptr<std::vector<NumType>> Mesh<NumType>::CreateCellsData(const std::string& varname, bool visible)
{
if (cells_data.count(varname) != 0)
{
THERMO_ERR("Variable \'" + varname + "\' already exists, could not create cell variable!");
}
// make zero vector
std::vector<NumType> zero_vec(cells_thickness->size());
cells_data[varname] = {std::make_shared<std::vector<NumType>>(std::move(zero_vec)), visible};
return cells_data[varname].first;
}
template<typename NumType>
std::shared_ptr<std::vector<NumType>> Mesh<NumType>::CreateNodesData(const std::string& varname, bool visible)
{
if (nodes_data.count(varname) != 0)
{
THERMO_ERR("Variable \'" + varname + "\' already exists, could not create node variable!");
}
// make zero vector
std::vector<NumType> zero_vec(cells_thickness->size() + 1);
nodes_data[varname] = {std::make_shared<std::vector<NumType>>(std::move(zero_vec)), visible};
return nodes_data[varname].first;
}
template<typename NumType>
void Mesh<NumType>::DeleteSingleData(const std::string& varname)
{
if (single_data.count(varname) == 0)
{
return;
}
single_data[varname].first.reset();
single_data.erase(varname);
}
template<typename NumType>
void Mesh<NumType>::DeleteCellsData(const std::string& varname)
{
if (cells_data.count(varname) == 0)
{
return;
}
cells_data[varname].first.reset();
cells_data.erase(varname);
}
template<typename NumType>
void Mesh<NumType>::DeleteNodesData(const std::string& varname)
{
if (nodes_data.count(varname) == 0)
{
return;
}
nodes_data[varname].first.reset();
nodes_data.erase(varname);
}
template<typename NumType>
std::shared_ptr<NumType> Mesh<NumType>::GetSingleData(const std::string& varname)
{
if (single_data.count(varname) == 0)
{
THERMO_ERR("There is no single variable: \'" + varname + "\' - can't get!");
}
return single_data[varname].first;
}
template<typename NumType>
std::shared_ptr<std::vector<NumType>> Mesh<NumType>::GetCellsData(const std::string& varname)
{
if (cells_data.count(varname) == 0)
{
THERMO_ERR("There is no cell variable: \'" + varname + "\' - can't get!");
}
return cells_data[varname].first;
}
template<typename NumType>
std::shared_ptr<std::vector<NumType>> Mesh<NumType>::GetNodesData(const std::string& varname)
{
if (nodes_data.count(varname) == 0)
{
THERMO_ERR("There is no node variable: \'" + varname + "\' - can't get!");
}
return nodes_data[varname].first;
}
template<typename NumType>
std::shared_ptr<std::vector<NumType>> Mesh<NumType>::GetCellsThickness()
{
return cells_thickness;
}
template<typename NumType>
NumType Mesh<NumType>::GetTotalThickness() const
{
return sum_vec(*cells_thickness);
}
template<typename NumType>
void Mesh<NumType>::MuteSingleData(const std::string& varname)
{
if (single_data.count(varname) == 0)
{
return;
}
single_data[varname].second = false;
}
template<typename NumType>
void Mesh<NumType>::MuteCellData(const std::string& varname)
{
if (cells_data.count(varname) == 0)
{
return;
}
cells_data[varname].second = false;
}
template<typename NumType>
void Mesh<NumType>::MuteNodeData(const std::string& varname)
{
if (nodes_data.count(varname) == 0)
{
return;
}
nodes_data[varname].second = false;
}
template<typename NumType>
void Mesh<NumType>::UnmuteSingleData(const std::string& varname)
{
if (single_data.count(varname) == 0)
{
return;
}
single_data[varname].second = true;
}
template<typename NumType>
void Mesh<NumType>::UnmuteCellData(const std::string& varname)
{
if (cells_data.count(varname) == 0)
{
return;
}
cells_data[varname].second = true;
}
template<typename NumType>
void Mesh<NumType>::UnmuteNodeData(const std::string& varname)
{
if (nodes_data.count(varname) == 0)
{
return;
}
nodes_data[varname].second = true;
}
template<typename NumType>
void Mesh<NumType>::SaveTXT(const std::string& filename) const
{
std::string filename_txt = filename + ".txt";
std::fstream* ofs = new std::fstream;
ofs->open(filename_txt, std::ios::out);
if (!ofs->is_open())
{
THERMO_ERR("can't open file "+ filename_txt + " for logging!");
}
// cell thickness info
*ofs << "### cells_thickness_array ###\n";
for (int i = 0; i < cells_thickness->size(); i++)
{
if (i != cells_thickness->size() - 1)
{
*ofs << (*cells_thickness)[i] << " ";
}
else
{
*ofs << (*cells_thickness)[i];
}
}
*ofs << "\n";
// single data
*ofs << "#### Single data ###\n";
for (auto item: single_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
*ofs << key + "\n";
*ofs << *(val.first);
*ofs << "\n";
}
}
// cells data
*ofs << "#### Cells data ###\n";
for (auto item: cells_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
*ofs << key + "\n";
for (int i = 0; i < val.first->size(); i++)
{
if (i != val.first->size() - 1)
{
*ofs << (*val.first)[i] << " ";
}
else
{
*ofs << (*val.first)[i];
}
}
*ofs << "\n";
}
}
// nodes data
*ofs << "#### Nodes data ###\n";
for (auto item: nodes_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
*ofs << key + "\n";
for (int i = 0; i < val.first->size(); i++)
{
if (i != val.first->size() - 1)
{
*ofs << (*val.first)[i] << " ";
}
else
{
*ofs << (*val.first)[i];
}
}
*ofs << "\n";
}
}
ofs->close();
delete ofs;
std::cout << "Mesh saved to \'" + filename_txt + "\'\n";
}
template<typename NumType>
void Mesh<NumType>::SaveTXT(const std::string& filename, int postscript) const
{
std::string file = filename;
std::stringstream ss;
ss << std::setfill('0') << std::setw(5) << postscript;
file += ss.str();
SaveTXT(file);
}
#ifdef USE_JSON_OUTPUT
template<typename NumType>
void Mesh<NumType>::SaveJSON(const std::string& filename) const
{
// create empty json object
json j;
// cells thickness
j["cells_thickness_array"] = *cells_thickness;
// single data
for (auto item: single_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
j["single data"][key] = *(val.first);
}
}
// cells data
for (auto item: cells_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
j["cells data"][key] = *(val.first);
}
}
// nodes data
for (auto item: nodes_data)
{
auto key = item.first;
auto val = item.second;
if (val.second)
{
j["nodes data"][key] = *(val.first);
}
}
// write json object to file
std::string filename_json = filename + ".json";
std::fstream* ofs = new std::fstream;
ofs->open(filename_json, std::ios::out);
if (!ofs->is_open())
{
THERMO_ERR("can't open file "+ filename_json + " for logging!");
}
*ofs << std::setw(4) << j;
ofs->close();
delete ofs;
std::cout << "Mesh saved to \'" + filename_json + "\'\n";
}
#endif
#ifdef USE_JSON_OUTPUT
template<typename NumType>
void Mesh<NumType>::SaveJSON(const std::string& filename, int postscript) const
{
std::string file = filename;
std::stringstream ss;
ss << std::setfill('0') << std::setw(5) << postscript;
file += ss.str();
SaveJSON(file);
}
#endif
template<typename NumType>
bool Mesh<NumType>::CheckCellsDataExistency(const std::string& varname) const
{
if (cells_data.count(varname) == 0)
{
return false;
}
else
{
return true;
}
}
template<typename NumType>
bool Mesh<NumType>::CheckNodesDataExistency(const std::string& varname) const
{
if (nodes_data.count(varname) == 0)
{
return false;
}
else
{
return true;
}
}
template<typename NumType>
bool Mesh<NumType>::CheckSingleDataExistency(const std::string& varname) const
{
if (single_data.count(varname) == 0)
{
return false;
}
else
{
return true;
}
}
// explicit instantiation of classes
template class Mesh<float>;
template class Mesh<double>;
}
\ No newline at end of file
add_subdirectory(constants_tests)
add_subdirectory(secant_test)
add_subdirectory(thomas_tests)
add_subdirectory(concat_tests)
add_subdirectory(matrix_test)
add_subdirectory(mesh_tests)
add_subdirectory(solver_tests)
\ No newline at end of file
project(mesh_test)
set(SOURCE main.cpp)
add_executable(mesh_test ${SOURCE})
target_link_libraries(mesh_test icethermo)
\ No newline at end of file
#include "icethermo.hpp"
using namespace icethermo;
int main()
{
// ### examples of Mesh class ###
// constructor with given total thickness (default is 10 cells)
Mesh<float> mesh1(1.0f);
// how to create cells data (lhs is shared ptr to vector)
auto cells_temp = mesh1.CreateCellsData("cells_temperature");
auto cells_capacity = mesh1.CreateCellsData("cells_capacity", true);
auto cells_enthalpy = mesh1.CreateCellsData("cells_enthalpy", false);
// one can modify cell data
(*cells_temp)[0] = 1.0f; (*cells_temp)[1] = 2.0f; (*cells_temp)[2] = 3.0f;
// how to create nodes data (lhs is shared ptr to vector)
auto nodes_k = mesh1.CreateNodesData("nodes_k");
auto nodes_enthalpy = mesh1.CreateNodesData("nodes_enthalpy", false);
// one can modify nodes data
(*nodes_k)[0] = -5.0f; nodes_k->back() = -3.0f;
// how to create single data
auto temp_ib = mesh1.CreateSingleData("temp_ib");
auto temp_is = mesh1.CreateSingleData("temp_is");
// one can modify single data
(*temp_ib) = -1.0f; (*temp_is) = 2.0f;
// one can delete cells, nodes or single data
mesh1.DeleteCellsData("cells_enthalpy");
mesh1.DeleteNodesData("nodes_enthalpy");
mesh1.DeleteSingleData("temp_is");
// its is better to avoid this, but one can get another pointer to created data
auto another_cells_temp = mesh1.GetCellsData("cells_temperature");
auto another_nodes_k = mesh1.GetNodesData("nodes_k");
auto another_temp_ib= mesh1.GetSingleData("temp_ib");
(*another_cells_temp)[0] = -5.0f;
(*another_nodes_k)[0] *= 2.0f;
(*another_temp_ib) = -30.0f;
// one can get vector with cell thickness
std::cout << "current cell thickness array: " << (*mesh1.GetCellsThickness()) << std::endl;
// one can get total thickness
std::cout << "current total cell thickness: " << mesh1.GetTotalThickness() << std::endl;
// one could manually mute and unmute variables (muted variables will not be writed to the output)
mesh1.MuteCellData("cells_temperature");
mesh1.UnmuteCellData("cells_temperature");
mesh1.MuteNodeData("nodes_enthalpy");
mesh1.UnmuteNodeData("nodes_enthalpy");
// one can save mesh to .txt file
mesh1.SaveTXT("./mesh");
// one can save mesh to .txt file with postfix number (relevant for time series)
mesh1.SaveTXT("./mesh", 1488);
// one can save file to json
#ifdef USE_JSON_OUTPUT
mesh1.SaveJSON("./mesh");
#endif
// one can save mesh to .json file with postfix number (relevant for time series)
#ifdef USE_JSON_OUTPUT
mesh1.SaveJSON("./mesh", 2007);
#endif
// ### examples of another Mesh class constructor ###
// construct uniform mesh with given cells num and total thickness
Mesh<double> mesh2(15, 1.0);
mesh2.SaveTXT("./mesh2");
// construct arbitrary mesh with given unit segment partition and total thickness
Mesh<double> mesh3({0.5, 0.5}, 5.0);
mesh3.SaveTXT("./mesh3");
// test mesh for visualization
Mesh<double> mesh_vis(15, 4.0);
auto cells_thick = mesh_vis.CreateCellsData("cells_temp_array");
int N = mesh_vis.GetCellsNum();
for (int i = 0; i < N; ++i)
{
(*cells_thick)[i] = -5.0 + i*1.0/N * (-5.0);
}
auto down_temp = mesh_vis.CreateSingleData("down_temp");
auto up_temp = mesh_vis.CreateSingleData("up_temp");
*(down_temp) = -5.0; *(up_temp) = -10.0;
auto cells_dens = mesh_vis.CreateCellsData("cells_density_array");
for (auto& it: *(cells_dens))
{
it = Params<double>::Density(Dparam::FreshIce, 0.0, 0.0);
}
#ifdef USE_JSON_OUTPUT
mesh_vis.SaveJSON("./mesh_vis");
#endif
// wrong constructor (it should be unit segment partition 0.5 + 0.4 != 1.0)
Mesh<float> mesh4({0.5, 0.4}, 5.0);
mesh4.SaveTXT("./mesh4");
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment