Skip to content

Commit

Permalink
Got rid of gsl dependencies.
Browse files Browse the repository at this point in the history
  • Loading branch information
ejpaul committed Jan 22, 2025
1 parent 30524bf commit 38b86ec
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 88 deletions.
64 changes: 36 additions & 28 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_COMPILER_WORKS 1)
project(simsoptpp)
#set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Expand All @@ -15,10 +14,16 @@ message(status "Python header dirs are ${Python_INCLUDE_DIRS}")
message(status "Python library dirs are ${Python_LIBRARY_DIRS}")
message(status "Python version is ${Python_VERSION}")

# Find pybind11
execute_process(COMMAND python -m pybind11 --cmakedir
OUTPUT_VARIABLE pybind11_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
message("Result of python -m pybind11 --cmakedir: ${pybind11_DIR}")
find_package(pybind11 REQUIRED PATHS pybind11_DIR)

find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# Update submodules as needed
# Update submodules as needed
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Submodule update")
Expand All @@ -32,15 +37,15 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
endif()

# For XSIMD usage
IF(DEFINED ENV{NO_XSIMD})
set(NO_XSIMD ON)
ENDIF()
if(DEFINED ENV{NO_XSIMD})
set(NO_XSIMD ON)
endif()
set(_HAS_AUTO_PTR_ETC 1)
configure_file(config.h.in config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})

include(CheckCXXCompilerFlag)
IF(DEFINED ENV{CI})
if(DEFINED ENV{CI})
message(STATUS "CI environment detected. Set compilation flags targetting Westmere microarch.")
set(CMAKE_CXX_FLAGS "-O3 -march=znver3")
elseif(DEFINED ENV{CONDA_BUILD})
Expand All @@ -52,21 +57,18 @@ else()
unset(COMPILER_SUPPORTS_MARCH_NATIVE CACHE)
CHECK_CXX_COMPILER_FLAG(-march=native COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE)
set(CMAKE_CXX_FLAGS "-O3 -march=native -mfma -ffp-contract=fast")
elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "arm64")
set(CMAKE_CXX_FLAGS "-O3 -mcpu=apple-a14 -mfma -ffp-contract=fast")
set(CMAKE_CXX_FLAGS "-O3 -march=native -ffp-contract=fast")
elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "arm64")
set(CMAKE_CXX_FLAGS "-O3 -mcpu=apple-a14 -ffp-contract=fast")
else()
set(CMAKE_CXX_FLAGS "-O3 -ffp-contract=fast")
set(CMAKE_CXX_FLAGS "-O3 -ffp-contract=fast")
endif()
endif()
# Ensure all code used from Eigen does not have LGPL license:
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_MPL2_ONLY")
message(STATUS "CMAKE_CXX_FLAGS are ${CMAKE_CXX_FLAGS}")

if(DEFINED ENV{CONDA_PREFIX})
include_directories($ENV{CONDA_PREFIX}/include)
link_directories("$ENV{CONDA_PREFIX}/lib")
message(STATUS "Conda prefix is $ENV{CONDA_PREFIX}")
include_directories($ENV{CONDA_PREFIX}/include)
link_directories("$ENV{CONDA_PREFIX}/lib")
message(STATUS "Conda prefix is $ENV{CONDA_PREFIX}")
endif()

find_package(OpenMP)
Expand All @@ -80,8 +82,8 @@ else()
include(ExternalProject)

# Download boost from git and build the headers
set( boost_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/boost )
set( boost_target boost)
set(boost_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/boost)
set(boost_target boost)

ExternalProject_Add(
${boost_target}
Expand All @@ -96,7 +98,8 @@ else()
libs/utility libs/typeof libs/array libs/units libs/integer libs/fusion
libs/range libs/iterator libs/concept_check libs/detail libs/function_types
libs/lexical_cast libs/container libs/move libs/smart_ptr libs/multi_array
libs/functional libs/function libs/type_index libs/container_hash libs/bind
libs/functional libs/function libs/type_index libs/container_hash libs/bind
libs/format libs/optional
CONFIGURE_COMMAND ./bootstrap.sh --prefix=<PREFIX>
BUILD_COMMAND ./b2 headers --prefix=${boost_DIR}
BUILD_IN_SOURCE 1
Expand All @@ -109,12 +112,16 @@ endif()

find_package(GSL)
if(GSL_FOUND)
message(STATUS "GSL version is ${GSL_VERSION}")
message(STATUS "GSL include dirs are ${GSL_INCLUDE_DIR}")
add_definitions(-DUSE_GSL)
message(STATUS "GSL version is ${GSL_VERSION}")
message(STATUS "GSL include dirs are ${GSL_INCLUDE_DIR}")
set(GSL_TARGETS src/simsoptpp/symplectic.cpp)
message(STATUS "GSL targets are ${GSL_TARGETS}")
message(STATUS "GSL libraries are ${GSL_LIBRARIES}")
else()
set(GSL_TARGETS)
endif()

add_subdirectory(thirdparty/pybind11)
add_subdirectory(thirdparty/fmt EXCLUDE_FROM_ALL)
set(XTENSOR_USE_OPENMP 0)
set(XTENSOR_USE_TBB 0)

Expand All @@ -126,15 +133,15 @@ pybind11_add_module(${PROJECT_NAME}
src/simsoptpp/tracing.cpp
src/simsoptpp/python_boozermagneticfield.cpp
src/simsoptpp/boozerradialinterpolant.cpp
)
${GSL_TARGETS}
)

set_target_properties(${PROJECT_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)

target_include_directories(${PROJECT_NAME} PRIVATE "thirdparty/xtensor/include" "thirdparty/xtensor-python/include" "thirdparty/xsimd/include" "thirdparty/xtl/include" ${Python_NumPy_INCLUDE_DIRS} "src/simsoptpp/")
target_link_libraries(${PROJECT_NAME} PRIVATE fmt::fmt-header-only)

if(NOT Boost_FOUND)
add_dependencies(${PROJECT_NAME} ${boost_target})
Expand All @@ -145,6 +152,7 @@ if(OpenMP_CXX_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
endif()

target_include_directories(${PROJECT_NAME} PRIVATE ${GSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE ${GSL_LIBRARIES})

IF (GSL_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${GSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE ${GSL_LIBRARIES})
endif()
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[build-system]
requires = ["setuptools>=45", "wheel", "oldest-supported-numpy", "cmake", "ninja", "setuptools_scm[toml]>=6.0"]
requires = ["setuptools","cmake","wheel","ninja","pybind11","numpy"]
build-backend = "setuptools.build_meta"

[tools.setuptools_scm]
109 changes: 56 additions & 53 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/usr/bin/env python3
# This file was adapted from the "official" pybind11 example at
# https://github.com/pybind/cmake_example

import os
import sys
import re
import subprocess
import sys
from pathlib import Path
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

import setuptools_scm
from setuptools import Extension, setup
from setuptools.command.build_ext import build_ext

# Convert distutils Windows platform specifiers to CMake -A arguments
PLAT_TO_CMAKE = {
Expand All @@ -17,7 +18,6 @@
"win-arm64": "ARM64",
}


# A CMakeExtension needs a sourcedir instead of a file list.
# The name must be the _single_ output extension from the CMake build.
# If you need multiple extensions, see scikit-build.
Expand All @@ -28,16 +28,16 @@ def __init__(self, name, sourcedir=""):


class CMakeBuild(build_ext):
def build_extension(self, ext):
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
def build_extension(self, ext) -> None:
# Must be in this form due to bug in .resolve() only fixed in Python 3.10+
ext_fullpath = Path.cwd() / self.get_ext_fullpath(ext.name)
extdir = ext_fullpath.parent.resolve()

# required for auto-detection of auxiliary "native" libs
if not extdir.endswith(os.path.sep):
extdir += os.path.sep
# Using this requires trailing slash for auto-detection & inclusion of
# auxiliary "native" libs

cfg = "Debug" if self.debug else "Release"
cfg = os.getenv("CMAKE_BUILD_TYPE", cfg)
print(f"Choose CMAKE_BUILD_TYPE={cfg}", flush=True)
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug
cfg = "Debug" if debug else "Release"

# CMake lets you override the generator - we need to check this.
# Can be set with Conda-Build, for example.
Expand All @@ -46,28 +46,39 @@ def build_extension(self, ext):
# Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON
# EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code
# from Python.

PYTHON_ROOT = str((Path(sys.executable).parent / "..").resolve())
cmake_args = [
"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}".format(extdir),
"-DPYTHON_EXECUTABLE={}".format(sys.executable),
"-DEXAMPLE_VERSION_INFO={}".format(self.distribution.get_version()),
"-DCMAKE_BUILD_TYPE={}".format(cfg), # not used on MSVC, but no harm
"-DPython_ROOT_DIR={}".format(PYTHON_ROOT),
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}",
f"-DPYTHON_EXECUTABLE={sys.executable}",
f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm
]
build_args = []
# Adding CMake arguments set as environment variable
# (needed e.g. to build for ARM OSx on conda-forge)
if "CMAKE_ARGS" in os.environ:
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]

# In this example, we pass in the version to C++. You might not need to.
cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}"]

if self.compiler.compiler_type != "msvc":
# Using Ninja-build since it a) is available as a wheel and b)
# multithreads automatically. MSVC would require all variables be
# exported for Ninja to pick it up, which is a little tricky to do.
# Users can override the generator with CMAKE_GENERATOR in CMake
# 3.15+.
if not cmake_generator:
cmake_args += ["-GNinja"]
if not cmake_generator or cmake_generator == "Ninja":
try:
import ninja

ninja_executable_path = Path(ninja.BIN_DIR) / "ninja"
cmake_args += [
"-GNinja",
f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}",
]
except ImportError:
pass

else:

# Single config generators are handled "normally"
single_config = any(x in cmake_generator for x in {"NMake", "Ninja"})

Expand All @@ -83,51 +94,43 @@ def build_extension(self, ext):
# Multi-config generators have a different way to specify configs
if not single_config:
cmake_args += [
"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir)
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}"
]
build_args += ["--config", cfg]

if sys.platform.startswith("darwin"):
# Cross-compile support for macOS - respect ARCHFLAGS if set
archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", ""))
if archs:
cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))]

# Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level
# across all generators.
if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ:
# self.parallel is a Python 3 only way to set parallel jobs by hand
# using -j in the build_ext call, not supported by pip or PyPA-build.
if hasattr(self, "parallel") and self.parallel:
# CMake 3.12+ only.
build_args += ["-j{}".format(self.parallel)]
build_args += [f"-j{self.parallel}"]

# print("build_temp", self.build_temp, flush=True)
# print(ext.sourcedir+"/build", flush=True)
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
build_temp = Path(self.build_temp) / ext.name
if not build_temp.exists():
build_temp.mkdir(parents=True)

subprocess.check_call(
["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp
# ["cmake", ext.sourcedir] + cmake_args, cwd=ext.sourcedir+"/build" # for debug
subprocess.run(
["cmake", ext.sourcedir, *cmake_args], cwd=build_temp, check=True
)
subprocess.check_call(
["cmake", "--build", ".", "--target", "simsoptpp"] + build_args, cwd=self.build_temp
# ["cmake", "--build", ".", "--target", "simsoptpp"] + build_args, cwd=ext.sourcedir+"/build" # for debug
subprocess.run(
["cmake", "--build", ".", *build_args], cwd=build_temp, check=True
)


def my_local_scheme(version: setuptools_scm.version.ScmVersion) -> str:
"""My local node and date version."""
node_and_date = setuptools_scm.version.get_local_node_and_date(version)
dirty = ".dirty" if version.dirty else ""
return str(node_and_date) + dirty

version = setuptools_scm.get_version(
write_to=Path(".") / "src" / "simsopt" / "_version.py",
version_scheme="post-release",
local_scheme=my_local_scheme,
)


# The information here can also be placed in setup.cfg - better separation of
# logic and declaration, and simpler if you include description/version in a file.
setup(
# use_scm_version=True,
version=version,
setup_requires=["setuptools_scm"],
name="simsopt",
package_dir={'':'src'},
ext_modules=[CMakeExtension("simsoptpp")],
cmdclass={"build_ext": CMakeBuild}
cmdclass={"build_ext": CMakeBuild},
zip_safe=False
)
4 changes: 3 additions & 1 deletion src/simsoptpp/python_tracing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ using std::shared_ptr;
using std::vector;
#include "tracing.h"
#include "tracing_helpers.h"
#include "symplectic.h"
#ifdef USE_GSL
#include "symplectic.h"
#endif

void init_tracing(py::module_ &m){
py::class_<StoppingCriterion, shared_ptr<StoppingCriterion>>(m, "StoppingCriterion");
Expand Down
1 change: 0 additions & 1 deletion src/simsoptpp/symplectic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ void SymplField::eval_field(double s, double theta, double zeta)

stz[0, 0] = s; stz[0, 1] = theta; stz[0, 2] = zeta;
field->set_points(stz);

// A = psi \nabla \theta - psip \nabla \zeta
Atheta = s*field->psi0;
Azeta = -field->psip()(0);
Expand Down
4 changes: 3 additions & 1 deletion src/simsoptpp/symplectic.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifdef USE_GSL
#include <memory>
#include <array>
#include <vector>
Expand Down Expand Up @@ -88,4 +89,5 @@ class sympl_dense {
double tcurrent = 0.0;
void update(double t, double dt, array<double, 4> y, SymplField f);
void calc_state(double eval_t, State &temp);
};
};
#endif
8 changes: 7 additions & 1 deletion src/simsoptpp/tracing.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "tracing_helpers.h"
#include "boozermagneticfield.h"
#include "tracing.h"
#include "symplectic.h"
#ifdef USE_GSL
#include "symplectic.h"
#endif

#include <memory>
#include <vector>
Expand Down Expand Up @@ -630,8 +632,12 @@ particle_guiding_center_boozer_tracing(
}

if (solveSympl) {
#ifdef USE_GSL
auto f = SymplField(field, m, q, mu);
return solve_sympl(f, y, tmax, dt, roottol, zetas, omegas, stopping_criteria, vpars, zetas_stop, vpars_stop, forget_exact_path, predictor_step, dt_save);
#else
throw std::invalid_argument("Symplectic solver not available. Please recompile with GSL support.");
#endif
} else {
if (vacuum) {
auto rhs_class = GuidingCenterVacuumBoozerRHS(field, m, q, mu, axis);
Expand Down
Loading

0 comments on commit 38b86ec

Please sign in to comment.