Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions metatomic-core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
# an easier to use, idiomatic Rust API.
cmake_minimum_required(VERSION 3.22)

if (POLICY CMP0135)
# Use download time as timestamp when extracting files from archives.
cmake_policy(SET CMP0135 NEW)
endif()

# Is metatomic the main project configured by the user? Or is this being used
# as a submodule/subdirectory?
if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR})
Expand Down Expand Up @@ -449,6 +454,17 @@ else()
target_link_libraries(metatomic::shared INTERFACE metatensor)
endif()

include(FetchContent)

# JSON library from https://github.com/nlohmann/json
FetchContent_Declare(nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d
)
FetchContent_MakeAvailable(nlohmann_json)

target_link_libraries(metatomic::shared INTERFACE nlohmann_json::nlohmann_json)
target_link_libraries(metatomic::static INTERFACE nlohmann_json::nlohmann_json)

if (BUILD_SHARED_LIBS)
add_library(metatomic ALIAS metatomic::shared)
Expand Down
14 changes: 12 additions & 2 deletions metatomic-core/cmake/metatomic-config.in.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.22)

include(CMakeFindDependencyMacro)
include(FindPackageHandleStandardArgs)
include(FetchContent)

if(metatomic_FOUND)
return()
Expand All @@ -15,6 +16,15 @@ enable_language(CXX)
set(REQUIRED_METATENSOR_VERSION @REQUIRED_METATENSOR_VERSION@)
find_package(metatensor ${REQUIRED_METATENSOR_VERSION} CONFIG REQUIRED)

if (NOT TARGET nlohmann_json::nlohmann_json)
# JSON library from https://github.com/nlohmann/json
FetchContent_Declare(nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d
)
FetchContent_MakeAvailable(nlohmann_json)
endif()

get_filename_component(METATOMIC_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/@PACKAGE_RELATIVE_PATH@" ABSOLUTE)

if (WIN32)
Expand Down Expand Up @@ -46,7 +56,7 @@ if (@METATOMIC_INSTALL_BOTH_STATIC_SHARED@ OR @BUILD_SHARED_LIBS@)
)

target_compile_features(metatomic::shared INTERFACE cxx_std_17)
target_link_libraries(metatomic::shared INTERFACE metatensor)
target_link_libraries(metatomic::shared INTERFACE metatensor nlohmann_json::nlohmann_json)

if (WIN32)
if (NOT EXISTS ${METATOMIC_IMPLIB_LOCATION})
Expand Down Expand Up @@ -75,7 +85,7 @@ if (@METATOMIC_INSTALL_BOTH_STATIC_SHARED@ OR NOT @BUILD_SHARED_LIBS@)
)

target_compile_features(metatomic::static INTERFACE cxx_std_17)
target_link_libraries(metatomic::static INTERFACE metatensor)
target_link_libraries(metatomic::static INTERFACE metatensor nlohmann_json::nlohmann_json)
endif()

# Export either the shared or static library as the metatomic target
Expand Down
1 change: 1 addition & 0 deletions metatomic-core/include/metatomic.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "metatomic/utils.hpp" // IWYU pragma: export
#include "metatomic/metadata.hpp" // IWYU pragma: export
#include "metatomic/system.hpp" // IWYU pragma: export
#include "metatomic/model.hpp" // IWYU pragma: export
#include "metatomic/plugin.hpp" // IWYU pragma: export
192 changes: 192 additions & 0 deletions metatomic-core/include/metatomic/metadata.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#pragma once

#include <cstdint>
#include <cstring>

#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include <nlohmann/json.hpp>

namespace metatomic {

/// Options for the calculation of a pair list.
class PairListOptions final {
public:
PairListOptions() = default;

PairListOptions(double cutoff_value, bool full_list_value, bool strict_value, std::vector<std::string> requestors_list = {}):
cutoff(cutoff_value),
full_list(full_list_value),
strict(strict_value),
requestors(std::move(requestors_list))
{}

double cutoff = 0.0;
bool full_list = false;
bool strict = false;
std::vector<std::string> requestors;

std::string to_json() const;
static PairListOptions from_json(const std::string& json);
};

/// Metadata about a specific exported model.
class ModelMetadata final {
public:
ModelMetadata() = default;

ModelMetadata(
std::string model_name,
std::string model_description,
std::vector<std::string> model_authors,
std::map<std::string, std::vector<std::string>> model_references = {},
std::map<std::string, std::string> extra_metadata = {}
):
name(std::move(model_name)),
description(std::move(model_description)),
authors(std::move(model_authors)),
references(std::move(model_references)),
extra(std::move(extra_metadata))
{}

std::string name;
std::string description;
std::vector<std::string> authors;
std::map<std::string, std::vector<std::string>> references;
std::map<std::string, std::string> extra;

std::string to_json() const;
static ModelMetadata from_json(const std::string& json);
};

/// Description of a quantity used as model input or output.
class Quantity final {
public:
Quantity() = default;

Quantity(
std::string quantity_name,
std::string quantity_unit,
std::vector<std::string> quantity_gradients,
std::string quantity_sample_kind
):
name(std::move(quantity_name)),
unit(std::move(quantity_unit)),
gradients(std::move(quantity_gradients)),
sample_kind(std::move(quantity_sample_kind))
{}

std::string name;
std::string unit;
std::vector<std::string> gradients;
std::string sample_kind;

std::string to_json() const;
static Quantity from_json(const std::string& json);
};

namespace details {
inline std::string double_to_hex(double value) {
uint64_t bits = 0;
static_assert(sizeof(bits) == sizeof(value), "unexpected double size");
std::memcpy(&bits, &value, sizeof(bits));

auto stream = std::ostringstream();
stream << "0x" << std::hex << bits;
return stream.str();
}

inline double hex_to_double(const std::string& value) {
auto bits = uint64_t(0);
auto stream = std::istringstream(value);
if (value.rfind("0x", 0) == 0 || value.rfind("0X", 0) == 0) {
stream.seekg(2);
}
stream >> std::hex >> bits;

auto result = 0.0;
static_assert(sizeof(bits) == sizeof(result), "unexpected double size");
std::memcpy(&result, &bits, sizeof(result));
return result;
}

} // namespace details

inline std::string PairListOptions::to_json() const {
return nlohmann::json{
{"type", "metatomic_pair_options"},
{"cutoff", details::double_to_hex(cutoff)},
{"full_list", full_list},
{"strict", strict},
{"requestors", requestors},
}.dump();
}

inline PairListOptions PairListOptions::from_json(const std::string& string) {
auto json = nlohmann::json::parse(string);
auto options = PairListOptions();

auto cutoff = std::string("0x0");
if (json.contains("cutoff")) {
cutoff = json.at("cutoff").get<std::string>();
}

options.cutoff = details::hex_to_double(cutoff);
options.full_list = json.value("full_list", false);
options.strict = json.value("strict", false);
options.requestors = json.value("requestors", std::vector<std::string>{});

return options;
}

inline std::string ModelMetadata::to_json() const {
return nlohmann::json{
{"type", "metatomic_model_metadata"},
{"name", name},
{"description", description},
{"authors", authors},
{"references", references},
{"extra", extra},
}.dump();
}

inline ModelMetadata ModelMetadata::from_json(const std::string& string) {
auto json = nlohmann::json::parse(string);
auto metadata = ModelMetadata();

metadata.name = json.value("name", "");
metadata.description = json.value("description", "");
metadata.authors = json.value("authors", std::vector<std::string>{});
metadata.references = json.value("references", std::map<std::string, std::vector<std::string>>{});
metadata.extra = json.value("extra", std::map<std::string, std::string>{});

return metadata;
}

inline std::string Quantity::to_json() const {
return nlohmann::json{
{"type", "metatomic_quantity"},
{"name", name},
{"unit", unit},
{"gradients", gradients},
{"sample_kind", sample_kind},
}.dump();
}

inline Quantity Quantity::from_json(const std::string& string) {
auto json = nlohmann::json::parse(string);
auto quantity = Quantity();

quantity.name = json.value("name", "");
quantity.unit = json.value("unit", "");
quantity.gradients = json.value("gradients", std::vector<std::string>{});
quantity.sample_kind = json.value("sample_kind", "");

return quantity;
}

} // namespace metatomic
Loading