Skip to content

Commit

Permalink
Merge pull request #6 from mctools/ncplugin-fix-SANSND-for-ncrystal4
Browse files Browse the repository at this point in the history
Make SANSND plugin ready for ncrystal v4 #1
  • Loading branch information
nicriz authored Jan 29, 2025
2 parents 68906f6 + b51799f commit 936b504
Show file tree
Hide file tree
Showing 34 changed files with 709 additions and 4,975 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
50 changes: 50 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: test

on:
push:
pull_request:
schedule:
- cron: '8 15 * * 0' # 8:15 every Monday

jobs:
build_and_test_plugin:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]

name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}

steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: src

- name: Install dependencies
run: pip install 'ncrystal-core>=3.9.86' "scikit-build-core>=0.10" "ncrystal-pypluginmgr>=0.0.3" "ncrystal-python>=3.9.86"

- name: Install plugin
run: pip install ./src

- name: Verify plugin loading
shell: python
run: |
import os
os.environ['NCRYSTAL_PLUGIN_RUNTESTS'] = '1'
os.environ['NCRYSTAL_REQUIRED_PLUGINS'] = 'SANSND'
import NCrystal
NCrystal.browsePlugins(dump=True)
- name: Use plugin file
run: nctool -d 'plugins::SANSND/ncplugin-SANSND_nanodiamond.ncmat'

- name: Load all plugin files
shell: python
run: |
from NCrystal.datasrc import browseFiles
from NCrystal.core import createScatter
for f in browseFiles(factory='plugins'):
if f.name.startswith('SANSND/'):
print('Loading f.fullKey')
createScatter( f'{f.fullKey}' )
28 changes: 3 additions & 25 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
#Also needed for vi:
.*.sw?

#ignore tempory cmake build output and installations:
/testcode/utils/cache/
/venv/

#Extra protection against adding in build output created by custom user commands:
*.so
Expand All @@ -29,30 +28,9 @@
*.app

__pycache__/
build/

testcode/data/njoy_calc.txt
testcode/data/teshi.dat
testcode/data/vesuvio_unc.dat
testcode/data/vesuvio.dat
testcode/data/vesuvio_4mm.inp
testcode/scripts/plotradicand.py

.ipynb_checkpoints/
.vscode/

#Miscellaneous:
.DS_Store
vgcore.*
.vscode/
testcode/data/openmc_fwd.dat
testcode/data/nesvi.dat
testcode/data/openmc_bkw.dat
testcode/data/F4690504.tmp:Zone.Identifier
testcode/data/AA6BE253.tmp:Zone.Identifier
testcode/data/9CC7D60B.tmp:Zone.Identifier
testcode/data/3DCFA2D9.tmp:Zone.Identifier
boost
testcode/data/Ersez_dataset:Zone.Identifier
testcode/data/*:Zone.Identifier
testcode/data/muvals
testcode/data/muvals_files
compile_plugin.sh
198 changes: 54 additions & 144 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,167 +1,77 @@

# CMake code for building the plugin and possible also testcode in the testcode/
# subdirectory. In general, please try to refrain from editing this file!
# Anything special that needs to be done to support the plugin development
# environment can be done in testcode/CMakeLists.txt, so it won't affect the main plugin.

cmake_minimum_required(VERSION 3.10...3.19)

execute_process( COMMAND ncrystal-config --show cmakedir
OUTPUT_VARIABLE NCrystal_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE )
find_package(NCrystal REQUIRED)
cmake_minimum_required(VERSION 3.20...3.30)

#Extract plugin name from ncplugin_name.txt:
file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/ncplugin_name.txt" NCPlugin_NAME LIMIT_COUNT 1)
file( STRINGS "${CMAKE_CURRENT_LIST_DIR}/ncplugin_name.txt" NCPlugin_NAME LIMIT_COUNT 1)
string(STRIP "${NCPlugin_NAME}" NCPlugin_NAME)

project( "NCPlugin_${NCPlugin_NAME}" VERSION 0.0.1 LANGUAGES CXX)

#Project has two options. While developing the project, one should use the default values.

#1) NCPLUGIN_DEVMODE: enables the subproject in testcode/ and enables various
# strict compilation options, which helps to ensure that the plugin will
# contain code appropriate for NCrystal.
#2) NCPLUGIN_ASBUILTIN: This option is used when the plugin code should be
# embedded directly into the primary NCrystal library.

option(NCPLUGIN_DEVMODE "Enable strict compilation flags and build test code" ON)
option(NCPLUGIN_ASBUILTIN "Do not build plugin, just prepare CMake variables for static inclusion (variable used by NCrystal's CMake code)" OFF)

if (NCPLUGIN_DEVMODE AND NCPLUGIN_ASBUILTIN)
message(FATAL_ERROR "The options NCPLUGIN_ASBUILTIN and NCPLUGIN_DEVMODE can not be enabled simultaneously")
endif()
set( ncplugin_data_file_pattern "data/*.ncmat" )

#Ensure we have a default build type if not already specified:
if ( NOT DEFINED CMAKE_BUILD_TYPE )
if (NCPLUGIN_DEVMODE)
set( CMAKE_BUILD_TYPE Debug )
else()
set( CMAKE_BUILD_TYPE RelWithDebInfo )
if ( DEFINED SKBUILD_PROJECT_NAME )
if ( NOT "${SKBUILD_PROJECT_NAME}" STREQUAL "ncrystal_plugin_${NCPlugin_NAME}" )
message(
FATAL_ERROR "Mismatch in plugin name hardcoded in "
" ncplugin_name.txt and pyproject.toml's project.name field."
)
endif()
endif()

#Plugin C++ files:
function(srcfileglob varname pattern)
#Glob with CONFIGURE_DEPENDS + ignoring temporary files left around by editors.
file( GLOB tmpall LIST_DIRECTORIES false CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/${pattern}" )
#Must always build against NCrystal:
if( NOT DEFINED "NCrystal_DIR" )
#Need to invoke "ncrystal-config --show cmakedir" if we want to be able to
#work with ncrystal-core installed via python wheels:
execute_process(
COMMAND ncrystal-config --show cmakedir
OUTPUT_VARIABLE "NCrystal_DIR" OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
find_package( NCrystal 3.9.85 REQUIRED )

function( ncrystal_srcfileglob varname pattern )
#Glob while ignoring temporary files.
file(
GLOB tmpall LIST_DIRECTORIES false
CONFIGURE_DEPENDS "${pattern}"
)
set(tmp "")
foreach(fn ${tmpall})
get_filename_component( bn "${fn}" NAME)
if (bn MATCHES "(#|~| )+")#could ignore . as well for scripts "|\\."
message("----> Ignoring file with invalid name: ${bn}")
if (bn MATCHES "(#|~| )+")
message( WARNING "Ignoring file with invalid name: ${bn}")
else()
list(APPEND tmp "${fn}")
endif()
endforeach()
set( ${varname} ${tmp} PARENT_SCOPE )
endfunction()

#Find files (also has the effect of triggering auto-reconf if the glob results change):
srcfileglob( plugin_srcfiles "src/*.cc" )
srcfileglob( plugin_hdrfiles "include/*.hh" )
srcfileglob( plugin_hdrfiles_icc "include/*.icc" )
srcfileglob( plugin_datafiles "data/*.ncmat" )
list(APPEND plugin_hdrfiles ${plugin_hdrfiles_icc})
srcfileglob( dummy "src/*.hh" )#To trigger reconf
srcfileglob( dummy "src/*.icc" )#To trigger reconf

if (NCPLUGIN_ASBUILTIN)
#Special mode which does almost nothing.
#NCrystal's main cmake code will build the plugin code into the primary
#NCrystal library. For that to work, we need to ensure that the files from the
#current plugin get the correct compile definitions:
get_directory_property(hasParent PARENT_DIRECTORY)
if (NOT hasParent)
message(FATAL_ERROR "NCPLUGIN_ASBUILTIN option can only be used when the plugin project is a sub-project")
endif()
set(NCPLUGIN_SRCFILES ${plugin_srcfiles} PARENT_SCOPE)#<--- pass up variable to parent project
set(NCPLUGIN_DATAFILES ${plugin_datafiles} PARENT_SCOPE)#<--- pass up variable to parent project
set(NCPLUGIN_COMPILEDEFS NCPLUGIN_NAME=${NCPlugin_NAME} NCPLUGIN_ASBUILTIN PARENT_SCOPE)
set(NCPLUGIN_INCDIRS ${PROJECT_SOURCE_DIR}/include PARENT_SCOPE)
return()
endif()

#Standard build, need NCrystal as dependency:

find_package(NCrystal 3.0.0 REQUIRED)

if ( NCPLUGIN_DEVMODE )
#Compile with very strict C++11 options during normal development (this gives
#better quality code, and ensures that the code developed is better suited for
#possible inclusion in NCrystal at some point):
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} -Wall -Wextra -pedantic -Werror )
#Limit how many errors are dumped on the poor developer:
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag( -fmax-errors=3 COMPILER_SUPPORTS_MAXERRORS )
if ( COMPILER_SUPPORTS_MAXERRORS )
set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} -fmax-errors=3 )
endif()
#Try to make life easier by adding rpaths (to ncrystal lib):
if ( NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH )
set( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE )
endif()
endif()

#The actual plugin should be build as a shared library. In case it is ever
#needed, we export everything for possible downstream usage: header files,
#targets, and cmake cfg files:
add_library( pluginlib SHARED ${plugin_srcfiles} )
target_compile_definitions( pluginlib PRIVATE NCPLUGIN_NAME=${NCPlugin_NAME} )
set_target_properties( pluginlib PROPERTIES OUTPUT_NAME ${PROJECT_NAME} )
target_compile_definitions( pluginlib PRIVATE NCRYSTAL_NO_CMATH_CONSTANTS )
target_link_libraries( pluginlib PUBLIC NCrystal::NCrystal )
target_include_directories( pluginlib PRIVATE "${PROJECT_SOURCE_DIR}/src"
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}> )
install( TARGETS pluginlib EXPORT ${PROJECT_NAME}Targets DESTINATION lib )
install( FILES ${plugin_hdrfiles} DESTINATION include/${PROJECT_NAME} )
install( EXPORT ${PROJECT_NAME}Targets FILE "${PROJECT_NAME}Targets.cmake" NAMESPACE "${PROJECT_NAME}::" DESTINATION lib/cmake )
add_library("${PROJECT_NAME}::pluginlib" ALIAS pluginlib)
include(CMakePackageConfigHelpers)
write_basic_package_version_file( "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion )
configure_file( "${PROJECT_SOURCE_DIR}/PkgConfig.cmake.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" @ONLY )
install( FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" DESTINATION lib/cmake )

#For simplicity, any data files are embedded directly in the library (except in
#NCPLUGIN_DEVMODE where the testcode project will make them available via
#symlinks):

if (plugin_datafiles)
#In any mode we sanity check the names of the data files (so developers will
#notice and fix any issues):
foreach(df ${plugin_datafiles})
get_filename_component(dfbn "${df}" NAME)
if(NOT dfbn MATCHES "ncplugin-${NCPlugin_NAME}_.+\.ncmat")
message(FATAL_ERROR "ERROR: name of exported datafile ${dfbn} does not have required form: ncplugin-${NCPlugin_NAME}_*.ncmat")
endif()
endforeach()
if (NOT NCPLUGIN_DEVMODE)
#Check that data file name follows convention: ncplugin-<pluginname>_*.ncmat:
if (NOT NCrystal_CMD_NCMAT2CPP)
message(FATAL_ERROR "ERROR: NCrystal installation does not provide ncrystal_ncmat2cpp command which is needed to embed datafiles in plugin.")
endif()
#Generate C++ code from the .ncmat files:
execute_process(COMMAND "${NCrystal_CMD_NCMAT2CPP}"
"-n" "NCPluginNamespace::registerDataFiles"
--include NCrystal/NCPluginBoilerplate.hh
"-o" "${PROJECT_BINARY_DIR}/autogen_${NCPlugin_NAME}_ncmat_data.cc" ${plugin_datafiles} RESULT_VARIABLE status )
if(status AND NOT status EQUAL 0)
message(FATAL_ERROR "Failure while trying to invoke ncrystal_ncmat2cpp (from ${NCrystal_CMD_NCMAT2CPP}).")
endif()
target_sources(pluginlib PRIVATE "${PROJECT_BINARY_DIR}/autogen_${NCPlugin_NAME}_ncmat_data.cc")#too late to just append to plugin_srcfiles
target_compile_definitions(pluginlib PRIVATE NCPLUGIN_DO_REGISTERDATAFILES)
message("-- Generated autogen_${NCPlugin_NAME}_ncmat_data.cc with embedded NCMAT data (will be compiled into the plugin library).")
endif()
ncrystal_srcfileglob( plugin_srcfiles "${PROJECT_SOURCE_DIR}/src/*.cc" )
ncrystal_srcfileglob( plugin_hdrfiles "${PROJECT_SOURCE_DIR}/src/*.hh" )
set( pluglib "NCPlugin_${NCPlugin_NAME}" )
add_library( ${pluglib} MODULE ${plugin_srcfiles} )
set_source_files_properties( ${plugin_srcfiles} PROPERTIES OBJECT_DEPENDS "${plugin_hdrfiles}" )
target_compile_definitions( ${pluglib} PRIVATE "NCPLUGIN_NAME=${NCPlugin_NAME}" "NCRYSTAL_NO_CMATH_CONSTANTS" )
target_link_libraries( ${pluglib} PRIVATE NCrystal::NCrystal )
target_include_directories( ${pluglib} PRIVATE "${PROJECT_SOURCE_DIR}/src" )

if ( ncplugin_data_file_pattern )
file(GLOB plugin_datafiles LIST_DIRECTORIES false CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/${ncplugin_data_file_pattern}" )
else()
set( plugin_datafiles "" )
endif()

if ( NCPLUGIN_DEVMODE )
#Development code:
add_subdirectory(testcode)
if ( DEFINED SKBUILD_PROJECT_NAME )
#Install in wheel platlib dir:
set( pymoddir "${SKBUILD_PLATLIB_DIR}/ncrystal_plugin_${NCPlugin_NAME}")
install( TARGETS ${pluglib} LIBRARY DESTINATION "${pymoddir}/plugins" )
#Also add an empty __init__.py:
file( TOUCH "${PROJECT_BINARY_DIR}/__init__.py" )
INSTALL( FILES "${PROJECT_BINARY_DIR}/__init__.py" DESTINATION "${pymoddir}" )
#Special location for data files:
install( FILES ${plugin_datafiles} DESTINATION "${pymoddir}/data" )
else()
install( TARGETS ${pluglib} LIBRARY DESTINATION lib )
install( FILES ${plugin_datafiles} DESTINATION data )
endif()
4 changes: 0 additions & 4 deletions PkgConfig.cmake.in

This file was deleted.

Loading

0 comments on commit 936b504

Please sign in to comment.