build(libcomposition): brought working build system into libcomposition

This commit is contained in:
2025-06-21 11:33:27 -04:00
parent 58de341056
commit db88e308de
24 changed files with 424 additions and 76 deletions

91
.gitignore vendored Normal file
View File

@@ -0,0 +1,91 @@
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
*.env
*.venv
env/
venv/
ENV/
ENV.bak/
*.egg-info/
dist/
build/
*.egg
# C and C++ (using Meson)
build/
*.o
*.a
*.so
*.d
*.dSYM/
*.exe
*.out
*.obj
*.dll
*.lib
*.pdb
*.exp
*.log
*.stackdump
# Fortran
*.mod
*.o
*.a
*.so
*.exe
*.out
# Doxygen
html/
latex/
xml/
man/
rtf/
tags
## Misc
*.swp
*._DS_Store
*.DS_Store
*.bak
*.tmp
*.log
*.cache
*.private
*.private/
subprojects/mfem/
subprojects/tetgen/
subprojects/yaml-cpp/
subprojects/quill/
subprojects/googletest-*/
subprojects/opat-core/
subprojects/pybind11*/
subprojects/packagecache/
subprojects/hypre/
subprojects/qhull/
subprojects/cppad/
subprojects/libconfig/
subprojects/libconstants/
subprojects/liblogging/
qhull.wrap
.vscode/
*.log
mpi-install-log.txt
output/
.boost_installed
4DSSE_logs/
.last_build_flags
.idea/
scratch/

View File

@@ -5,7 +5,7 @@
#include <iostream>
#include "atomicSpecies.h"
namespace serif::atomic {
namespace fourdst::atomic {
struct Species {
std::string m_name; //< Name of the species
std::string m_el; //< Element symbol
@@ -101,9 +101,9 @@ namespace serif::atomic {
namespace std {
template<>
struct hash<serif::atomic::Species> {
size_t operator()(const serif::atomic::Species& s) const noexcept {
struct hash<fourdst::atomic::Species> {
size_t operator()(const fourdst::atomic::Species& s) const noexcept {
return std::hash<std::string>()(s.m_name);
}
};
} // namespace std
} // namespace std

View File

@@ -4,7 +4,7 @@
#include <string>
#include "atomicSpecies.h"
namespace serif::atomic {
namespace fourdst::atomic {
static const Species n_1("n-1", "n", 1, 1, 0, 1, 0.0, "B-", 782.347, 1.0086649159, 0.00047);
static const Species H_1("H-1", "H", -1, 0, 1, 1, 0.0, "B-", std::numeric_limits<double>::quiet_NaN(), 1.007825031898, 1.4e-05);
static const Species H_2("H-2", "H", 0, 1, 1, 2, 1112.2831, "B-", std::numeric_limits<double>::quiet_NaN(), 2.014101777844, 1.5e-05);

View File

@@ -0,0 +1 @@
subdir('atomic')

View File

@@ -0,0 +1,2 @@
config_p = subproject('libconfig')
config_dep = config_p.get_variable('config_dep')

View File

@@ -0,0 +1,2 @@
const_p = subproject('libconstants')
const_dep = const_p.get_variable('const_dep')

View File

@@ -0,0 +1,6 @@
logging_p = subproject('liblogging')
logging_dep = logging_p.get_variable('logging_dep')
quill_dep = logging_p.get_variable('quill_dep')
log_dep = [logging_dep, quill_dep]

View File

@@ -0,0 +1,3 @@
subdir('libconstants')
subdir('liblogging')
subdir('libconfig')

View File

@@ -1,24 +1,5 @@
cmake = import('cmake')
subdir('mfem')
subdir('yaml-cpp')
subdir('quill')
subdir('boost')
subdir('opatIO')
subdir('mpi')
subdir('hypre')
subdir('pybind')
subdir('fourdst')
subdir('cppad')
# Set the config file error handling options
configErr = get_option('config_error_handling')
# build up any -D flags we need
commonCppArgs = []
if configErr == 'warn'
commonCppArgs += ['-DCONFIG_WARN']
elif configErr == 'harsh'
commonCppArgs += ['-DCONFIG_HARSH']
endif
add_project_arguments(commonCppArgs, language: 'cpp')

42
meson.build Normal file
View File

@@ -0,0 +1,42 @@
# ***********************************************************************
#
# Copyright (C) 2025 -- The 4D-STAR Collaboration
# File Author: Emily Boudreaux
# Last Modified: June 21, 2025
#
# libcomposition is free software; you can use it and/or modify
# it under the terms and restrictions the GNU General Library Public
# License version 3 (GPLv3) as published by the Free Software Foundation.
#
# libcomposition is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this software; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# *********************************************************************** #
project('libcomposition', 'cpp', version: 'v1.0.0', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
# Add default visibility for all C++ targets
add_project_arguments('-fvisibility=default', language: 'cpp')
cpp = meson.get_compiler('cpp')
subdir('build-config')
subdir('assets/static')
subdir('src')
subdir('tests')
pkg = import('pkgconfig')
pkg.generate(
name: 'libcomposition',
description: 'Composition module for SERiF and related projects',
version: meson.project_version(),
libraries: [libcomposition],
subdirs: ['libcomposition'],
filebase: 'libcomposition',
install_dir: join_paths(get_option('libdir'), 'pkgconfig')
)

23
readme.md Normal file
View File

@@ -0,0 +1,23 @@
# libcomposition
libcomposition is the chemistry tracking tool used by SERiF and related products.
This has been broken out of the main serif project to allow for more modularity
## Building
In order to build libconstants you need `meson>=1.5.0`. This can be installed with `pip`
```bash
pip install "meson>=1.5.0"
```
Then from the root libcomposition directory it is as simple as
```bash
meson setup build --buildtype=release
meson compile -C build
meson test -C build
```
this will auto generate a pkg-config file for you so that linking other libraries to libcomposition is easy.

View File

@@ -8,10 +8,10 @@ composition_headers = files(
)
dependencies = [
probe_dep,
quill_dep,
species_weight_dep,
const_dep,
config_dep,
log_dep
]
# Define the libcomposition library so it can be linked against by other parts of the build system
@@ -30,4 +30,4 @@ composition_dep = declare_dependency(
)
# Make headers accessible
install_headers(composition_headers, subdir : 'SERiF/composition')
install_headers(composition_headers, subdir : 'libcomposition/composition')

View File

@@ -33,13 +33,13 @@
#include "atomicSpecies.h"
#include "species.h"
namespace serif::composition {
namespace fourdst::composition {
CompositionEntry::CompositionEntry() : m_symbol("H-1"), m_isotope(serif::atomic::species.at("H-1")),
CompositionEntry::CompositionEntry() : m_symbol("H-1"), m_isotope(fourdst::atomic::species.at("H-1")),
m_initialized(false) {
}
CompositionEntry::CompositionEntry(const std::string& symbol, const bool massFracMode) : m_symbol(symbol), m_isotope(serif::atomic::species.at(symbol)), m_massFracMode(massFracMode) {
CompositionEntry::CompositionEntry(const std::string& symbol, const bool massFracMode) : m_symbol(symbol), m_isotope(fourdst::atomic::species.at(symbol)), m_massFracMode(massFracMode) {
setSpecies(symbol);
}
@@ -56,11 +56,11 @@ namespace serif::composition {
if (m_initialized) {
throw std::runtime_error("Composition entry is already initialized.");
}
if (serif::atomic::species.count(symbol) == 0) {
if (fourdst::atomic::species.count(symbol) == 0) {
throw std::runtime_error("Invalid symbol.");
}
m_symbol = symbol;
m_isotope = serif::atomic::species.at(symbol);
m_isotope = fourdst::atomic::species.at(symbol);
m_initialized = true;
}
@@ -101,7 +101,7 @@ namespace serif::composition {
return m_relAbundance;
}
serif::atomic::Species CompositionEntry::isotope() const {
fourdst::atomic::Species CompositionEntry::isotope() const {
return m_isotope;
}
@@ -258,7 +258,7 @@ namespace serif::composition {
}
bool Composition::isValidSymbol(const std::string& symbol) {
return serif::atomic::species.contains(symbol);
return fourdst::atomic::species.contains(symbol);
}
double Composition::setMassFraction(const std::string& symbol, const double& mass_fraction) {
@@ -652,7 +652,7 @@ namespace serif::composition {
return m_compositions.count(symbol) > 0;
}
bool Composition::contains(const serif::atomic::Species &isotope) const {
bool Composition::contains(const fourdst::atomic::Species &isotope) const {
// Check if the isotope's symbol is in the composition
if (!m_finalized) {
LOG_ERROR(m_logger, "Composition has not been finalized.");
@@ -696,4 +696,4 @@ namespace serif::composition {
return os;
}
} // namespace serif::composition
} // namespace fourdst::composition

View File

@@ -27,12 +27,12 @@
#include <utility>
#include "probe.h"
#include "config.h"
#include "logging.h"
#include "atomicSpecies.h"
namespace serif::composition {
namespace fourdst::composition {
struct CanonicalComposition {
double X = 0.0; ///< Mass fraction of Hydrogen.
double Y = 0.0; ///< Mass fraction of Helium.
@@ -63,7 +63,7 @@ namespace serif::composition {
*/
struct CompositionEntry {
std::string m_symbol; ///< The chemical symbol of the species.
serif::atomic::Species m_isotope; ///< The isotope of the species.
fourdst::atomic::Species m_isotope; ///< The isotope of the species.
bool m_massFracMode = true; ///< The mode of the composition entry. True if mass fraction, false if number fraction.
double m_massFraction = 0.0; ///< The mass fraction of the species.
@@ -142,7 +142,7 @@ namespace serif::composition {
* @brief Gets the isotope of the species.
* @return The isotope of the species.
*/
serif::atomic::Species isotope() const;
fourdst::atomic::Species isotope() const;
/**
* @brief Gets the mode of the composition entry.
@@ -215,8 +215,8 @@ namespace serif::composition {
*/
class Composition {
private:
serif::config::Config& m_config = serif::config::Config::getInstance();
serif::probe::LogManager& m_logManager = serif::probe::LogManager::getInstance();
fourdst::config::Config& m_config = fourdst::config::Config::getInstance();
fourdst::logging::LogManager& m_logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* m_logger = m_logManager.getLogger("log");
bool m_finalized = false; ///< True if the composition is finalized.
@@ -473,7 +473,7 @@ namespace serif::composition {
*/
bool hasSymbol(const std::string& symbol) const;
bool contains(const serif::atomic::Species& isotope) const;
bool contains(const fourdst::atomic::Species& isotope) const;
/**
* @brief Sets the composition mode.
@@ -508,4 +508,4 @@ namespace serif::composition {
Composition operator+(const Composition& other) const;
};
}; // namespace serif::composition
}; // namespace fourdst::composition

1
src/meson.build Normal file
View File

@@ -0,0 +1 @@
subdir('composition')

View File

@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/4D-STAR/libconfig.git
revision = v1.0.0
depth = 1
[provide]
libconfig = config_dep

View File

@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/4D-STAR/libconstants.git
revision = v1.1
depth = 1
[provide]
libconstants = const_dep

View File

@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/4D-STAR/liblogging.git
revision = v1.0.1
depth = 1
[provide]
liblogging = logging_dep

2
subprojects/quill.wrap Normal file
View File

@@ -0,0 +1,2 @@
[wrap-redirect]
filename = liblogging/subprojects/quill.wrap

View File

@@ -0,0 +1,2 @@
[wrap-redirect]
filename = libconfig/subprojects/yaml-cpp.wrap

View File

@@ -19,20 +19,20 @@ class compositionTest : public ::testing::Test {};
* @brief Test the constructor of the composition class.
*/
TEST_F(compositionTest, isotopeMasses) {
EXPECT_NO_THROW(serif::atomic::species.at("H-1"));
EXPECT_DOUBLE_EQ(serif::atomic::species.at("H-1").mass(), 1.007825031898);
EXPECT_DOUBLE_EQ(serif::atomic::species.at("He-3").mass(), 3.0160293219700001);
EXPECT_DOUBLE_EQ(serif::atomic::species.at("He-4").mass(),4.0026032541300003);
EXPECT_NO_THROW(fourdst::atomic::species.at("H-1"));
EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("H-1").mass(), 1.007825031898);
EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("He-3").mass(), 3.0160293219700001);
EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("He-4").mass(),4.0026032541300003);
}
TEST_F(compositionTest, constructor) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
EXPECT_NO_THROW(serif::composition::Composition comp);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
EXPECT_NO_THROW(fourdst::composition::Composition comp);
}
TEST_F(compositionTest, registerSymbol) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
EXPECT_NO_THROW(comp.registerSymbol("H-1"));
EXPECT_NO_THROW(comp.registerSymbol("He-4"));
EXPECT_THROW(comp.registerSymbol("H-19"), std::runtime_error);
@@ -46,8 +46,8 @@ TEST_F(compositionTest, registerSymbol) {
}
TEST_F(compositionTest, setGetComposition) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -72,8 +72,8 @@ TEST_F(compositionTest, setGetComposition) {
}
TEST_F(compositionTest, setGetNumberFraction) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1", false);
comp.registerSymbol("He-4", false);
@@ -89,8 +89,8 @@ TEST_F(compositionTest, setGetNumberFraction) {
}
TEST_F(compositionTest, subset) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.6);
@@ -98,14 +98,14 @@ TEST_F(compositionTest, subset) {
EXPECT_NO_THROW(comp.finalize());
std::vector<std::string> symbols = {"H-1"};
serif::composition::Composition subsetComp = comp.subset(symbols, "norm");
fourdst::composition::Composition subsetComp = comp.subset(symbols, "norm");
EXPECT_TRUE(subsetComp.finalize());
EXPECT_DOUBLE_EQ(subsetComp.getMassFraction("H-1"), 1.0);
}
TEST_F(compositionTest, finalizeWithNormalization) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.3);
@@ -116,8 +116,8 @@ TEST_F(compositionTest, finalizeWithNormalization) {
}
TEST_F(compositionTest, finalizeWithoutNormalization) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.5);
@@ -128,8 +128,8 @@ TEST_F(compositionTest, finalizeWithoutNormalization) {
}
TEST_F(compositionTest, getComposition) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.6);
@@ -143,8 +143,8 @@ TEST_F(compositionTest, getComposition) {
}
TEST_F(compositionTest, setCompositionMode) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.6);
@@ -165,8 +165,8 @@ TEST_F(compositionTest, setCompositionMode) {
}
TEST_F(compositionTest, hasSymbol) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
comp.setMassFraction("H-1", 0.6);
@@ -180,28 +180,28 @@ TEST_F(compositionTest, hasSymbol) {
}
TEST_F(compositionTest, mix) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp1;
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::composition::Composition comp1;
comp1.registerSymbol("H-1");
comp1.registerSymbol("He-4");
comp1.setMassFraction("H-1", 0.6);
comp1.setMassFraction("He-4", 0.4);
EXPECT_NO_THROW(comp1.finalize());
serif::composition::Composition comp2;
fourdst::composition::Composition comp2;
comp2.registerSymbol("H-1");
comp2.registerSymbol("He-4");
comp2.setMassFraction("H-1", 0.4);
comp2.setMassFraction("He-4", 0.6);
EXPECT_NO_THROW(comp2.finalize());
serif::composition::Composition mixedComp = comp1 + comp2;
fourdst::composition::Composition mixedComp = comp1 + comp2;
EXPECT_TRUE(mixedComp.finalize());
EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("H-1"), 0.5);
EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("He-4"), 0.5);
serif::composition::Composition mixedComp2 = comp1.mix(comp2, 0.25);
fourdst::composition::Composition mixedComp2 = comp1.mix(comp2, 0.25);
EXPECT_TRUE(mixedComp2.finalize());
EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("H-1"), 0.45);
EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("He-4"), 0.55);
}
}

7
tests/meson.build Normal file
View File

@@ -0,0 +1,7 @@
# Google Test dependency
gtest_dep = dependency('gtest', main: true, required : true)
gtest_main = dependency('gtest_main', required: true)
gtest_nomain_dep = dependency('gtest', main: false, required : true)
# Subdirectories for unit and integration tests
subdir('composition')

View File

@@ -0,0 +1,151 @@
import pandas as pd
# Define fixed-width column specifications based on the format:
# a1 (width 1), i3 (width 3), i5 (width 5), i5 (width 5), i5 (width 5),
# 1x (skip 1), a3 (width 3), a4 (width 4), 1x (skip 1),
# f14.6 (width 14), f12.6 (width 12), f13.5 (width 13),
# 1x (skip 1), f10.5 (width 10), 1x (skip 1),
# a2 (width 2), f13.5 (width 13), f11.5 (width 11),
# 1x (skip 1), i3 (width 3), 1x (skip 1),
# f13.6 (width 13), f12.6 (width 12)
# Compute cumulative positions (0-indexed):
colSpecs = [
(0, 1), # control
(1, 4), # NZ
(4, 9), # N
(9, 14), # Z
(14, 19), # A
# skip 1 char at position 19; next field starts at 20
(20, 23), # el
(23, 27), # o
# skip 1 char at position 27; next field starts at 28
(28, 42), # massExcess (f14.6)
(42, 54), # massExcessUnc (f12.6)
(54, 67), # bindingEnergy (f13.5)
# skip 1 char at position 67; next field starts at 68
(68, 78), # bindingEnergyUnc (f10.5)
# skip 1 char at position 78; next field starts at 79
(79, 81), # betaCode (a2)
(81, 94), # betaDecayEnergy (f13.5)
(94, 105), # betaDecayEnergyUnc (f11.5)
# skip 1 char at position 105; next field starts at 106
(106, 109),# atomicMassInt (i3)
# skip 1 char at position 109; next field starts at 110
(110, 123),# atomicMassFrac (f13.6)
(123, 135) # atomicMassUnc (f12.6)
]
# Define column names (using camelCase for variables)
columnNames = [
"control",
"nz",
"n",
"z",
"a",
"el",
"o",
"massExcess",
"massExcessUnc",
"bindingEnergy",
"bindingEnergyUnc",
"betaCode",
"betaDecayEnergy",
"betaDecayEnergyUnc",
"atomicMassInt",
"atomicMassFrac",
"atomicMassUnc"
]
def combine_atomic_mass(row):
"""
Combine the integer and fractional parts of the atomic mass.
For example, if atomicMassInt is '1' and atomicMassFrac is '008664.91590',
this function returns float('1008664.91590').
"""
intPart = str(row["atomicMassInt"]).strip()
fracPart = str(row["atomicMassFrac"]).strip()
try:
combined = int(intPart) + float(fracPart)/1e6
return combined
except ValueError:
return None
def mkInstanceName(row):
"""
Make a c++ instance name from the element and atomic number.
"""
speciesName = f"{row['el'].strip()}-{row['a']}"
return speciesName.replace("-", "_")
def formatSpecies(row):
"""
Format c++ instantiation of Species struct from row data.
"""
name = f"{row['el'].strip()}-{row['a']}"
instanceName = name.replace("-", "_")
nz = int(row['nz'])
n = int(row['n'])
z = int(row['z'])
a = int(row['a'])
bindingEnergy = float(row['bindingEnergy'])
atomicMass = float(row['atomicMass'])
atomicMassUnc = float(row['atomicMassUnc'])
NaN = "std::numeric_limits<double>::quiet_NaN()"
try:
betaDecayEnergy = float(row['betaDecayEnergy'].replace("#", "").replace("*", ""))
except ValueError:
betaDecayEnergy = NaN
instantiation = f"static const Species {instanceName}(\"{name}\", \"{row['el']}\", {nz}, {n}, {z}, {a}, {bindingEnergy}, \"{row['betaCode']}\", {betaDecayEnergy}, {atomicMass}, {atomicMassUnc});"
return instantiation, instanceName
def formatSpeciesDefines(row):
instanceName = f"SERIF_SPECIES_{formatSpecies(row)[1]}"
define = f"""#ifndef {instanceName.upper()}
#define {instanceName.upper()}
#endif // {instanceName.upper()}"""
return define
def formatHeader(dataFrame):
"""
Format c++ header file from DataFrame.
"""
header = f"""#pragma once
#include <unordered_map>
#include <string_view>
#include <string>
#include "atomicSpecies.h"
namespace fourdst::atomic {{
{'\n '.join([formatSpecies(row)[0] for index, row in dataFrame.iterrows()])}
static const std::unordered_map<std::string, Species> species = {{
{'\n '.join([f'{{"{row["el"].strip()}-{row["a"]}", {mkInstanceName(row)}}},' for index, row in dataFrame.iterrows()])}
}};
}}; // namespace fourdst::atomic
{'\n'.join([formatSpeciesDefines(row) for index, row in dataFrame.iterrows()])}
"""
return header
if __name__ == "__main__":
import argparse
import os
parser = argparse.ArgumentParser(description="Convert mass data to c++ header file.")
parser.add_argument("input", help="Input file path.")
parser.add_argument("-o", "--output", help="Output file path.", default="../../assets/static/atomic/include/species.h")
args = parser.parse_args()
if not os.path.exists(args.input):
raise FileNotFoundError(f"File not found: {args.input}")
# Read the file (adjust the skiprows value if your header differs)
dataFrame = pd.read_fwf(args.input, colspecs=colSpecs, names=columnNames, skiprows=36)
# Combine the two atomic mass fields into one float column
dataFrame["atomicMass"] = dataFrame.apply(combine_atomic_mass, axis=1)
dataFrame.drop(columns=["atomicMassInt", "atomicMassFrac"], inplace=True)
# Format the header
header = formatHeader(dataFrame)
with open(args.output, "w") as f:
f.write(header)

13
utils/atomic/readme.md Normal file
View File

@@ -0,0 +1,13 @@
# Information
Simple python utility for turning the file assets/atomic/weights.dat into a c++ header which can be included to provide easy access to all atomic weights inside 4DSSE
## Requirments
In order to use this utility you will need
- Python
- Pandas
## Usage
```bash
python convertWeightsToHeader.py <path/to/weights.dat> -o atomicWeights.h
```