The code.ill.fr has been recreated and upgraded with the latest version this weekend, If you encounter any problem please inform the Helpdesk.

Commit 1975c8cf authored by Simon Ward's avatar Simon Ward Committed by Elisa Rebolini
Browse files

Auto stash before merge of "feature-python_api-build_wheels" and...

Auto stash before merge of "feature-python_api-build_wheels" and "origin/feature-python_api-build_wheels"
parent dc5abf95
name: Python libs
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
# schedule:
# # Every day at 1am
# - cron: '0 1 * * *'
jobs:
get_Latest:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[ci skip]')"
steps:
- name: Checkout ILL repo
run: |
git clone https://code.ill.fr/scientific-software/crysfml/ ./
git checkout feature-python_api-build_wheels
rm -rf ./.git ./Html
- uses: actions/upload-artifact@v2
with:
name: CrysFML_SRC
path: ${{ github.workspace }}
retention-days: 1
create-Linux:
runs-on: ubuntu-latest
needs: get_Latest
steps:
- uses: actions/download-artifact@v2
with:
name: CrysFML_SRC
- name: Build manylinux wheels
run: |
chmod +x ./Scripts/buildscript.sh
docker run -e PLAT=manylinux2010_x86_64 -v ${{ github.workspace }}:/io quay.io/pypa/manylinux2010_x86_64 /io/Scripts/buildscript.sh
- uses: actions/upload-artifact@v2
with:
name: CrysFML - Linux
path: ${{ github.workspace }}/dist/*.whl
create-OSX:
strategy:
max-parallel: 4
matrix:
python-version: ['3.8']
os: [macos-10.15]
gcc_v: [ 10 ] # Version of GFortran we want to use.
runs-on: ${{ matrix.os }}
needs: get_Latest
steps:
- uses: actions/download-artifact@v2
with:
name: CrysFML_SRC
- name: Setup python
uses: actions/setup-python@v1
with:
python-version: ${{matrix.python-version}}
- name: Install cmake
run: pip3 install cmake delocate wheel
- name: Build CFML (OSX)
env:
FC: gfortran-${{ matrix.gcc_v }}
CC: gcc-${{ matrix.gcc_v }}
run: |
pip3 wheel ./ --no-deps -w ./old/
delocate-wheel -w dist -v ./old/*.whl
- uses: actions/upload-artifact@v2
with:
name: CrysFML - MacOS
path: ./dist/*.whl
create-Windows:
strategy:
max-parallel: 1
matrix:
python-version: [ '3.6', '3.7']
os: [ windows-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
python-version: ${{ matrix.python-version }}
auto-activate-base: true
- uses: msys2/setup-msys2@v2
with:
msystem: MSYS
install: cmake mingw-w64-x86_64-toolchain
update: true
path-type: inherit
- name: Build CFML
shell: msys2 {0}
id: build
run: python setup.py bdist_wheel
env:
MINGW_ARCH: MINGW64
- uses: actions/upload-artifact@v2
with:
name: CrysFML - Windows
path: ./dist/*.whl
Upload_Artifacts:
runs-on: ubuntu-latest
needs: [create-Linux, create-OSX]
steps:
- uses: actions/download-artifact@v2
- name: What is downloaded
run: |
ls -al
- name: Upload Artifacts GitHub releases
uses: ncipollo/release-action@v1
with:
draft: false
prerelease: true
allowUpdates: true
replacesArtifacts: true
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: "./**/*.whl"
tag: "CurrentBuild"
body: "This is a build of the CFML libraries."
......@@ -37,3 +37,12 @@
# Directories
Build
.idea/
build/
CFML.egg-info/
dist/
*.whl
......@@ -14,6 +14,7 @@ option(HEAP_ARRAYS "Put arrays in heap instead of stack (only for Windows ifort)
option(PROG_EX "Build the Program Examples" ON)
option(PYTHON_API "Build Python API" OFF)
option(QPARALLEL "qparallel option for Ifort on Windows" ON)
option(PYSETUP "Building from setup.py" OFF)
if(DEFINED CMAKE_Fortran_COMPILER)
set(CMAKE_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING "The Fortran compiler. One of 'ifort', 'g95' or 'gfortran'.")
......@@ -52,16 +53,34 @@ message(STATUS "CrysFML installation path set to ${CRYSFML_PREFIX}")
# Include and library paths for Python.
# They must be set by the user.
if(DEFINED PYTHON_LIBRARY_PATH)
set(PYTHON_LIBRARY_PATH ${PYTHON_LIBRARY_PATH} CACHE PATH "Python library path")
else()
set(PYTHON_LIBRARY_PATH "" CACHE PATH "Python library path")
endif()
if(DEFINED PYTHON_INTERPRETER_PATH)
set(PYTHON_INTERPRETER_PATH ${PYTHON_INTERPRETER_PATH} CACHE PATH "Python interpreter path")
else()
set(PYTHON_INTERPRETER_PATH "" CACHE PATH "Python interpreter path")
endif()
# if(DEFINED PYTHON_LIBRARY_PATH)
# set(PYTHON_LIBRARY_PATH ${PYTHON_LIBRARY_PATH} CACHE PATH "Python library path")
# else()
# set(PYTHON_LIBRARY_PATH "" CACHE PATH "Python library path")
# endif()
# if(DEFINED PYTHON_INTERPRETER_PATH)
# set(PYTHON_INTERPRETER_PATH ${PYTHON_INTERPRETER_PATH} CACHE PATH "Python interpreter path")
# else()
# set(PYTHON_INTERPRETER_PATH "" CACHE PATH "Python interpreter path")
# endif()
# Use CMake v3.12+ FindPython3 to find the system-compatible interpreter *and* libraries at once
# This solves a potential issue on convoluted Windows build systems which have multiple
# python interpreters, some of which do not have build-system compatibility (I'm looking at you, msys2 python)
# In such a case FindPythonInterp might point to the wrong python interpreter and then further configuration
# steps will fail to find any (or any compatible) libraries which match the interpreter.
# find_package(Python3 COMPONENTS Interpreter Development)
# # Since FindPython3 and FindPythonInterp set different variables, fake the FindPythonInterp result
# # to prevent it running if called by, e.g., FindPybind11
# if(Python3_FOUND)
# set(PYTHONINTERP_FOUND ON)
# set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
# message(STATUS "USING PYTHON: " ${PYTHON_EXECUTABLE})
# # set(PYTHON_INTERPRETER_PATH ${Python3_EXECUTABLE})
# set(PYTHON_VERSION_STRING "${Python3_VERSION}")
# set(PYTHON_VERSION_MAJOR ${Python3_VERSION_MAJOR})
# set(PYTHON_VERSION_MINOR ${Python3_VERSION_MINOR})
# set(PYTHON_VERSION_PATCH ${Python3_VERSION_PATCH})
# endif()
# Include and library paths for HDF5.
# They must be set by the user.
......
......@@ -20,7 +20,7 @@ target_link_libraries(read_nexus crysfml)
link_directories(${HDF5_LIBRARY_DIR})
target_link_libraries(read_nexus ${HDF5_LIBRARIES})
if(WIN32)
if(WIN32 OR MSYS)
get_filename_component(COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME_WE)
if(COMPILER_NAME STREQUAL ifort)
# Copy hdf5.dll hdf5_f90cstub.dll hdf5_fortran.dll
......
......@@ -42,7 +42,7 @@ class Atom(CFML_api.FortranBindedClass):
def __str__(self):
xyz = self.xyz
return 'ATOM %s %s %s %s %s %s %s'%(self.label, self.chemical_symbol, str(xyz[0]), str(xyz[1]), str(xyz[2]), self.biso, self.site_multiplicity)
return 'ATOM %s %s %s %s %s %s %s %s %s'%(self.label, self.chemical_symbol, str(xyz[0]), str(xyz[1]), str(xyz[2]), str(self.biso), str(self.occ), str(self.moment), str(self.formal_charge))
@property
def label(self):
......@@ -343,7 +343,12 @@ class AtomList(CFML_api.FortranBindedClass):
"""
def __init__(self, string_array=None):
CFML_api.FortranBindedClass.__init__(self)
self._mult = True
self._adp = True
if string_array:
self._mult = False
self._adp = False
dict = CFML_api.crysfml_api.atom_typedef_atomlist_from_CIF_string_array(string_array)
self._set_fortran_address(dict["AtomList"])
......@@ -366,7 +371,7 @@ class AtomList(CFML_api.FortranBindedClass):
@property
def natoms(self):
"""
total number of atoms in the list
Total number of atoms in the list
"""
return CFML_api.crysfml_api.atom_typedef_get_natoms(self.get_fortran_address())["natoms"]
......@@ -374,3 +379,29 @@ class AtomList(CFML_api.FortranBindedClass):
""" Print the list of atoms. """
CFML_api.crysfml_api.atom_typedef_write_atom_list(self.get_fortran_address())
def set_mult_occ_cif(self,spg):
"""
Update the multiplicity and modify the occupancy when reading from a CIF array,
in order to be in agreement with the definitions of Sfac in CrysFML
This needs to be run when the AtomList is initialised from a CIF-like stringarray
rather than from the class CIFFile
"""
if (self._mult == False):
CFML_api.crysfml_api.atom_typedef_atomlist_reset_occ_cif(self.get_fortran_address(),spg.get_fortran_address())
self._mult = True
else:
print("Warning: multiplicity and occupancy have already been set")
def set_all_anisotropic_displacement_parameters_cif(self,cell):
"""
Update all Atom fields for Us, Bs and betas
This needs to be run when the AtomList is initialised from a CIF-like stringarray
rather than from the class CIFFile
"""
if (self._adp == False):
CFML_api.crysfml_api.atom_typedef_atomlist_set_all_adp_cif(self.get_fortran_address(),cell.get_fortran_address())
self._adp = True
else:
print("Warning: Anisotropic Displacement Parameters have already been set")
......@@ -170,3 +170,72 @@ class Cell(CFML_api.FortranBindedClass):
return CFML_api.crysfml_api.crystal_metrics_get_CartType(self.get_fortran_address())["CartType"]
def k_to_cart_vector(code, vector, cell):
"""
Convert a vector in crystal space to cartesian components
The value of code has been extended to use also the Busing-Levy
Cartesian system as reference also for direct and reciprocal space.
Codes:
The Cartesian frame is that defined by the setting of the Cell object
D: The components are given with respect to basis (a,b,c)
R: The components are given with respect to basis (a*,b*,c*)
BL: The components are given with respect to basis (a*,b*,c*) but
the Cartesian frame is that defined by Busing and Levy
BLD: The components are given with respect to basis (a,b,c) but
the Cartesian frame is that defined by Busing and Levy
...
Parameters
----------
code : str
Cartesian frame
vector : np.array[dtype='float32', ndim=1]
kx,ky,kz coordinates
cell : CMFL_api.crysfml_api.Cell
Returns:
np.array[dtype='float32', ndim=1] : coordinates in the chosen cartesian frame
"""
return CFML_api.crysfml_api.crystal_metrics_cart_vector(code, vector, cell.get_fortran_address())["cart_vec"]
def k_to_cart_unitary_vector(code, vector, cell):
"""
Convert a vector in crystal space to unitary cartesian components
The value of code has been extended to use also the Busing-Levy
Cartesian system as reference also for direct and reciprocal space.
Codes:
The Cartesian frame is that defined by the setting of the Cell object
D: The components are given with respect to basis (a,b,c)
R: The components are given with respect to basis (a*,b*,c*)
BL: The components are given with respect to basis (a*,b*,c*) but
the Cartesian frame is that defined by Busing and Levy
BLD: The components are given with respect to basis (a,b,c) but
the Cartesian frame is that defined by Busing and Levy
...
Parameters
----------
code : str
Cartesian frame
vector : np.array[dtype='float32', ndim=1]
kx,ky,kz coordinates
cell : CMFL_api.crysfml_api.Cell
Returns:
np.array[dtype='float32', ndim=1] : coordinates in the chosen cartesian frame
"""
return CFML_api.crysfml_api.crystal_metrics_cart_u_vector(code, vector, cell.get_fortran_address())["cart_vec"]
def betas_from_biso(biso, cell):
"""
Get Betas from Biso
...
Parameters
----------
biso : float32
cell : CMFL_api.crysfml_api.Cell
Returns
np.array[dtype='float32', ndim=1] : betas[0:5] b11, b22, b33, b12, b13, b23
"""
return CFML_api.crysfml_api.crystal_metrics_get_betas_from_biso(cell.get_fortran_address(),biso)["betas"]
#################################
# Commad line arguments section
#################################
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
#################################
# Project section
......@@ -29,39 +29,38 @@ set_source_files_properties(forpy_mod.f90 PROPERTIES COMPILE_FLAG "-cpp")
# Dependencies section
#################################
# Add a dependency to crysfml_common to keep sure that the crysfml_common library will be built first.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/19226 for linking
add_dependencies(${LIBRARY_NAME} crysfml_common)
set(COMPATIBLE_VERSIONS 3.8 3.7 3.6 3.5)
if (NOT PYTHON_INTERPRETER_PATH)
set(Python_ADDITIONAL_VERSIONS ${COMPATIBLE_VERSIONS})
find_package(PythonInterp REQUIRED)
set(PYTHON_INTERPRETER_PATH ${PYTHON_EXECUTABLE})
message(STATUS ${PYTHON_INTERPRETER_PATH})
else()
message(STATUS "using Python interpreter provided with PYTHON_INTERPRETER_PATH variable: " ${PYTHON_INTERPRETER_PATH})
endif()
if (NOT PYTHON_LIBRARY_PATH)
set(Python_ADDITIONAL_VERSIONS ${COMPATIBLE_VERSIONS})
find_package(PythonLibs REQUIRED)
set(PYTHON_LIBRARY_PATH ${PYTHON_LIBRARY})
message(STATUS ${PYTHON_LIBRARY_PATH})
if (NOT PYTHON_INTERPRETER_PATH OR NOT PYTHON_LIBRARY_PATH)
set(Python3_USE_STATIC_LIBS, TRUE)
find_package(Python3 COMPONENTS Interpreter Development)
set(PYTHON_INTERPRETER_PATH ${Python3_EXECUTABLE})
set(PYTHON_LIBRARY_PATH Python3::Python)
message(STATUS "Using Python interpreter found with PYTHON_INTERPRETER_PATH variable: " ${PYTHON_INTERPRETER_PATH})
message(STATUS "Linking Python extension with found PYTHON_LIBRARY_PATH variable: " ${PYTHON_LIBRARY_PATH})
else()
message(STATUS "Using Python interpreter provided with PYTHON_INTERPRETER_PATH variable: " ${PYTHON_INTERPRETER_PATH})
message(STATUS "Linking Python extension with provided PYTHON_LIBRARY_PATH variable: " ${PYTHON_LIBRARY_PATH})
endif()
if (UNIX)
add_library(Python3_LIB SHARED IMPORTED)
set_property(TARGET Python3_LIB PROPERTY IMPORTED_LOCATION ${PYTHON_LIBRARY_PATH})
elseif(WIN32)
if(WIN32 OR MSYS)
add_library(Python3_LIB STATIC IMPORTED)
set_property(TARGET Python3_LIB PROPERTY IMPORTED_LOCATION ${PYTHON_LIBRARY_PATH})
target_link_libraries(${LIBRARY_NAME} Python3_LIB)
endif()
# Set -Wl,-undefined,dynamic_lookup to OTHER_LDFLAGS
# Set include and linking
include_directories(${CRYSFML_COMMON_MODULE_DIRECTORY})
target_link_libraries(${LIBRARY_NAME} crysfml_common)
target_link_libraries(${LIBRARY_NAME} Python3_LIB)
# Fix a problem on Mac OS X when building shared libraries
if(APPLE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup")
endif()
# Set library extension
set_target_properties(${LIBRARY_NAME} PROPERTIES PREFIX "" OUTPUT_NAME ${LIBRARY_NAME})
......@@ -69,7 +68,7 @@ set(LIBRARY_FILENAME "crysfml_api.so")
if(APPLE)
set_target_properties(${LIBRARY_NAME} PROPERTIES SUFFIX ".so")
set(LIBRARY_FILENAME "crysfml_api.so")
elseif(WIN32)
elseif(WIN32 OR MSYS)
set_target_properties(${LIBRARY_NAME} PROPERTIES SUFFIX ".pyd")
set(LIBRARY_FILENAME "crysfml_api.pyd")
endif()
......@@ -112,42 +111,56 @@ endif (DOXYGEN_FOUND)
#################################
# Add tests
add_test(NAME "Python_API_Tests" COMMAND ${PYTHON_INTERPRETER_PATH} -m unittest discover ${CMAKE_CURRENT_BINARY_DIR}/../Tests)
add_custom_target(Python_Files ALL
if(PYSETUP)
add_custom_target(Python_Files ALL
COMMAND
${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/../Tests
${CMAKE_CURRENT_BINARY_DIR}/../Tests
COMMAND
${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/../Tests/CFML_api
)
else()
add_custom_target(Python_Files ALL
COMMAND
${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/../Tests
${CMAKE_CURRENT_BINARY_DIR}/../Tests
COMMAND
${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/../Tests/CFML_api
COMMAND
${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_FILENAME}
${CMAKE_CURRENT_BINARY_DIR}/../Tests/CFML_api
${CMAKE_CURRENT_BINARY_DIR}/../Tests/CFML_api/${LIBRARY_FILENAME}
)
add_dependencies(Python_Files ${LIBRARY_NAME})
endif()
add_dependencies(Python_Files ${LIBRARY_NAME})
#################################
# Install section
#################################
# The rules for installing the library.
install(DIRECTORY "" DESTINATION ${PYTHON_API_PREFIX}/CFML_api FILES_MATCHING PATTERN "*.py" PATTERN "Extensions" EXCLUDE)
if(WIN32)
install(TARGETS ${LIBRARY_NAME} RUNTIME DESTINATION ${PYTHON_API_PREFIX}/CFML_api)
if(WIN32 OR MSYS)
install(TARGETS ${LIBRARY_NAME} RUNTIME DESTINATION ${PYTHON_API_PREFIX}/CFML_api)
else()
install(TARGETS ${LIBRARY_NAME} LIBRARY DESTINATION ${PYTHON_API_PREFIX}/CFML_api)
install(TARGETS ${LIBRARY_NAME} LIBRARY DESTINATION ${PYTHON_API_PREFIX}/CFML_api)
endif()
# Installing example files
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../Examples" DESTINATION ${PYTHON_API_PREFIX} FILES_MATCHING PATTERN "*.py")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../Examples/Data" DESTINATION ${PYTHON_API_PREFIX}/Examples FILES_MATCHING PATTERN "*.cfl" PATTERN "*.cif")
# Installing tests files
#
# # Installing tests files
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../Tests" DESTINATION ${PYTHON_API_PREFIX} FILES_MATCHING PATTERN "*.py")
# Installing documentation files
#
# # Installing documentation files
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doxygen/html" DESTINATION ${PYTHON_API_PREFIX}/Doc OPTIONAL)
\ No newline at end of file
......@@ -4,6 +4,8 @@ module API_Atom_TypeDef
use, intrinsic :: iso_c_binding
use, intrinsic :: iso_fortran_env
use CFML_GlobalDeps, only : cp, eps
use CFML_Atom_TypeDef, only: &
Atom_List_type, &
Atoms_Cell_type, &
......@@ -13,9 +15,23 @@ module API_Atom_TypeDef
Write_Atom_list, &
Atom_type
Use CFML_Crystallographic_Symmetry, only: &
Get_Multip_Pos
use CFML_Crystal_Metrics, only: &
Convert_U_Betas, Convert_B_Betas
use CFML_IO_Formats, only: &
Read_Atom, Read_Cif_Atom
use API_Crystallographic_Symmetry, only: &
Space_Group_type_p, &
get_space_group_type_from_arg
use API_Crystal_Metrics, only: &
Crystal_Cell_type_p, &
get_cell_from_arg
implicit none
type Atom_type_p
......@@ -178,6 +194,118 @@ contains
end function atom_typedef_atomlist_from_CIF_string_array
!---- Modify occupation factors and set multiplicity of atoms
!---- in order to be in agreement with the definitions of Sfac in CrysFML
function atom_typedef_atomlist_reset_occ_cif(self_ptr, args_ptr) result(r) bind(c)
type(c_ptr), value :: self_ptr
type(c_ptr), value :: args_ptr
type(c_ptr) :: r
type(tuple) :: args
type(dict) :: retval
integer :: num_args
integer :: ierror
type(Atom_List_Type_p) :: a_p
type(Space_Group_type_p) :: spg
real(kind=cp),dimension(6):: pos
integer :: i
r = C_NULL_PTR ! in case of an exception return C_NULL_PTR
! use unsafe_cast_from_c_ptr to cast from c_ptr to tuple
call unsafe_cast_from_c_ptr(args, args_ptr)
! Check if the arguments are OK
ierror = args%len(num_args)
! we should also check ierror, but this example does not do complete error checking for simplicity
if (num_args /= 2) then
call raise_exception(TypeError, "update_occ_cif expects exactly 1 argument")
call args%destroy
return
endif
! Doing boring stuff
call get_atom_list_type_from_arg(args, a_p, 0)
call get_space_group_type_from_arg(args, spg, 1)
do i=1,a_p%p%natoms
pos(1:3)=a_p%p%atom(i)%x
a_p%p%atom(i)%Mult = Get_Multip_Pos(pos(1:3),SpG%p)
! This step is needed for CIF file only as the convention is different!
a_p%p%atom(i)%Occ = a_p%p%atom(i)%Occ*real(a_p%p%atom(i)%Mult)/max(1.0,real(SpG%p%Multip))
if(a_p%p%atom(i)%occ < eps) a_p%p%atom(i)%occ=real(a_p%p%atom(i)%Mult)/max(1.0,real(SpG%p%Multip))
enddo
ierror = dict_create(retval)
r = retval%get_c_ptr()
call args%destroy
end function atom_typedef_atomlist_reset_occ_cif
function atom_typedef_atomlist_set_all_adp_cif(self_ptr, args_ptr) result(r) bind(c)
type(c_ptr), value :: self_ptr
type(c_ptr), value :: args_ptr
type(c_ptr) :: r
type(tuple) :: args
type(dict) :: retval
integer :: num_args
integer :: ierror
type(Atom_List_Type_p) :: a_p
type(Crystal_Cell_type_p) :: cell
integer :: i
r = C_NULL_PTR ! in case of an exception return C_NULL_PTR
! use unsafe_cast_from_c_ptr to cast from c_ptr to tuple
call unsafe_cast_from_c_ptr(args, args_ptr)
! Check if the arguments are OK
ierror = args%len(num_args)
! we should also check ierror, but this example does not do complete error checking for simplicity
if (num_args /= 2) then
call raise_exception(TypeError, "update_occ_cif expects exactly 1 argument")
call args%destroy
return
endif