Program Listing for File JSONGraphWriter.cpp
↰ Return to documentation for file (src/flamegpu/io/JSONGraphWriter.cpp)
#include "flamegpu/io/JSONGraphWriter.h"
#include <fstream>
#include <cstdio>
#include <utility>
#include <string>
#include <memory>
#include <nlohmann/json.hpp>
#include "flamegpu/exception/FLAMEGPUException.h"
#include "flamegpu/simulation/detail/CUDAEnvironmentDirectedGraphBuffers.cuh"
namespace flamegpu {
namespace io {
namespace {
void writeAnyVertex(nlohmann::ordered_json& j, const std::pair<std::string, Variable> &var, const unsigned int index, const std::shared_ptr<const detail::CUDAEnvironmentDirectedGraphBuffers>& directed_graph, cudaStream_t stream) {
size_type foo = 0;
// Output value
if (var.second.elements == 1) {
if (var.second.type == std::type_index(typeid(float))) {
j = directed_graph->getVertexPropertyBuffer<float>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(double))) {
j = directed_graph->getVertexPropertyBuffer<double>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int64_t))) {
j = directed_graph->getVertexPropertyBuffer<int64_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint64_t))) {
j = directed_graph->getVertexPropertyBuffer<uint64_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int32_t))) {
j = directed_graph->getVertexPropertyBuffer<int32_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint32_t))) {
j = directed_graph->getVertexPropertyBuffer<uint32_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int16_t))) {
j = directed_graph->getVertexPropertyBuffer<int16_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint16_t))) {
j = directed_graph->getVertexPropertyBuffer<uint16_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int8_t))) {
j = static_cast<int32_t>(directed_graph->getVertexPropertyBuffer<int8_t>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(uint8_t))) {
j = static_cast<uint32_t>(directed_graph->getVertexPropertyBuffer<uint8_t>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(char))) {
j = static_cast<int32_t>(directed_graph->getVertexPropertyBuffer<char>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else {
THROW exception::JSONError("Attempting to export value of unsupported type '%s', "
"in JsonGraphWriter::writeAny()\n", var.second.type.name());
}
return;
}
// Loop through elements, to construct array
j = {};
for (unsigned int el = 0; el < var.second.elements; ++el) {
if (var.second.type == std::type_index(typeid(float))) {
j.push_back(directed_graph->getVertexPropertyBuffer<float>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(double))) {
j.push_back(directed_graph->getVertexPropertyBuffer<double>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int64_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<int64_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint64_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<uint64_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int32_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<int32_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint32_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<uint32_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int16_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<int16_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint16_t))) {
j.push_back(directed_graph->getVertexPropertyBuffer<uint16_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int8_t))) {
j.push_back(static_cast<int32_t>(directed_graph->getVertexPropertyBuffer<int8_t>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(uint8_t))) {
j.push_back(static_cast<uint32_t>(directed_graph->getVertexPropertyBuffer<uint8_t>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(char))) {
j.push_back(static_cast<int32_t>(directed_graph->getVertexPropertyBuffer<char>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else {
THROW exception::JSONError("Attempting to export value of unsupported type '%s', "
"in JsonGraphWriter::writeAny()\n", var.second.type.name());
}
}
}
void writeAnyEdge(nlohmann::ordered_json& j, const std::pair<std::string, Variable> &var, const unsigned int index, const std::shared_ptr<const detail::CUDAEnvironmentDirectedGraphBuffers>& directed_graph, cudaStream_t stream) {
size_type foo = 0;
// Output value
if (var.second.elements == 1) {
if (var.second.type == std::type_index(typeid(float))) {
j = directed_graph->getEdgePropertyBuffer<float>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(double))) {
j = directed_graph->getEdgePropertyBuffer<double>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int64_t))) {
j = directed_graph->getEdgePropertyBuffer<int64_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint64_t))) {
j = directed_graph->getEdgePropertyBuffer<uint64_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int32_t))) {
j = directed_graph->getEdgePropertyBuffer<int32_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint32_t))) {
j = directed_graph->getEdgePropertyBuffer<uint32_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int16_t))) {
j = directed_graph->getEdgePropertyBuffer<int16_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(uint16_t))) {
j = directed_graph->getEdgePropertyBuffer<uint16_t>(var.first, foo, stream)[var.second.elements * index];
} else if (var.second.type == std::type_index(typeid(int8_t))) {
j = static_cast<int32_t>(directed_graph->getEdgePropertyBuffer<int8_t>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(uint8_t))) {
j = static_cast<uint32_t>(directed_graph->getEdgePropertyBuffer<uint8_t>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(char))) {
j = static_cast<int32_t>(directed_graph->getEdgePropertyBuffer<char>(var.first, foo, stream)[var.second.elements * index]); // Char outputs weird if being used as an integer
} else {
THROW exception::JSONError("Attempting to export value of unsupported type '%s', "
"in JsonGraphWriter::writeAny()\n", var.second.type.name());
}
return;
}
// Loop through elements, to construct array
j = {};
for (unsigned int el = 0; el < var.second.elements; ++el) {
if (var.second.type == std::type_index(typeid(float))) {
j.push_back(directed_graph->getEdgePropertyBuffer<float>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(double))) {
j.push_back(directed_graph->getEdgePropertyBuffer<double>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int64_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<int64_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint64_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<uint64_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int32_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<int32_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint32_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<uint32_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int16_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<int16_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(uint16_t))) {
j.push_back(directed_graph->getEdgePropertyBuffer<uint16_t>(var.first, foo, stream)[var.second.elements * index + el]);
} else if (var.second.type == std::type_index(typeid(int8_t))) {
j.push_back(static_cast<int32_t>(directed_graph->getEdgePropertyBuffer<int8_t>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(uint8_t))) {
j.push_back(static_cast<uint32_t>(directed_graph->getEdgePropertyBuffer<uint8_t>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else if (var.second.type == std::type_index(typeid(char))) {
j.push_back(static_cast<int32_t>(directed_graph->getEdgePropertyBuffer<char>(var.first, foo, stream)[var.second.elements * index + el])); // Char outputs weird if being used as an integer
} else {
THROW exception::JSONError("Attempting to export value of unsupported type '%s', "
"in JsonGraphWriter::writeAny()\n", var.second.type.name());
}
}
}
void toAdjancencyLike(nlohmann::ordered_json &j, const std::shared_ptr<const detail::CUDAEnvironmentDirectedGraphBuffers>& directed_graph, cudaStream_t stream) {
const EnvironmentDirectedGraphData &data = directed_graph->getDescription();
// Vertices
if (directed_graph->getVertexCount()) {
j["nodes"] = {};
for (unsigned int i = 0; i < directed_graph->getVertexCount(); ++i) {
nlohmann::ordered_json j_v;
// Reserved members first
size_type foo = 0;
j_v["id"] = std::to_string(directed_graph->getVertexPropertyBuffer<id_t>(ID_VARIABLE_NAME, foo, stream)[i]);
// Custom members after
for (const auto &v : data.vertexProperties) {
if (v.first[0] != '_') {
writeAnyVertex(j_v[v.first], v, i, directed_graph, stream);
if (i == 0 && v.first == "id" && v.first != ID_VARIABLE_NAME) {
fprintf(stderr, "Warning: Graph vertices contain both 'id' and '%s' properties, export may be invalid.\n", ID_VARIABLE_NAME);
}
}
}
j["nodes"].push_back(j_v);
}
}
// Edges
if (directed_graph->getEdgeCount()) {
j["links"] = {};
for (unsigned int i = 0; i < directed_graph->getEdgeCount(); ++i) {
nlohmann::ordered_json j_e;
// Reserved members first
size_type foo = 0;
const id_t *src_dest_buffer = directed_graph->getEdgePropertyBuffer<id_t>(GRAPH_SOURCE_DEST_VARIABLE_NAME, foo, stream);
j_e["source"] = std::to_string(src_dest_buffer[i * 2 + 1]);
j_e["target"] = std::to_string(src_dest_buffer[i * 2 + 0]);
// Custom members after
for (const auto& e : data.edgeProperties) {
if (e.first[0] != '_') {
writeAnyEdge(j_e[e.first], e, i, directed_graph, stream);
if (i == 0 && e.first == "source") {
fprintf(stderr, "Warning: Graph edges contain both 'source' and '%s' properties, export may be invalid.\n", GRAPH_SOURCE_DEST_VARIABLE_NAME);
} else if (i == 0 && e.first == "target") {
fprintf(stderr, "Warning: Graph edges contain both 'target' and '%s' properties, export may be invalid.\n", GRAPH_SOURCE_DEST_VARIABLE_NAME);
}
}
}
j["links"].push_back(j_e);
}
}
}
} // namespace
void JSONGraphWriter::saveAdjacencyLike(const std::string& filepath,
const std::shared_ptr<const detail::CUDAEnvironmentDirectedGraphBuffers>& directed_graph, cudaStream_t stream, bool pretty_print) {
// Init writer
nlohmann::ordered_json j;
toAdjancencyLike(j, directed_graph, stream);
// Perform output
std::ofstream out(filepath, std::ios::trunc | std::ios::binary);
if (!out.is_open()) {
THROW exception::InvalidFilePath("Unable to open file '%s' for writing, in JSONGraphWriter::saveAdjacencyLike()\n", filepath.c_str());
}
if (pretty_print) {
out << std::setw(4);
}
out << j;
out.close();
}
} // namespace io
} // namespace flamegpu