diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2fb05b95..14ff6815 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.10'] + python-version: ['3.14'] runs-on: ubuntu-latest diff --git a/README.md b/README.md index 1f6290cf..21e8d04d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Fidimag solves finite-difference micromagnetic problems and supports atomistic s See: [https://fidimag.readthedocs.io/en/latest/install.html](https://fidimag.readthedocs.io/en/latest/install.html) ### Features -* Optimal LLG equation integration using modern [Sundial's v6](https://github.com/LLNL/sundials/) CVODE solver +* Optimal LLG equation integration using modern [Sundial's v7](https://github.com/LLNL/sundials/) CVODE solver * Offers LLG and LLG with spin torque terms (Zhang-Li and Sloncewski) * Calculations using the Geodesic-Nudged-Elastic-Band and String methods to compute energy barriers. * Exchange, Zeeman, Demagnetising, Uniaxial Anisotropy energy classes. diff --git a/bin/install-fftw.sh b/bin/install-fftw.sh index 9367b55d..da3420d8 100755 --- a/bin/install-fftw.sh +++ b/bin/install-fftw.sh @@ -3,7 +3,7 @@ # This script installs FFTW locally. It may need to environment # variables to work, like 'export CC=gcc' in ARCHER. -FFTW=fftw-3.3.8 +FFTW=fftw-3.3.10 set -e diff --git a/bin/install-sundials.sh b/bin/install-sundials.sh index 5d908bf0..20b034d3 100755 --- a/bin/install-sundials.sh +++ b/bin/install-sundials.sh @@ -5,10 +5,16 @@ set -e # when SUNDIALS moved to a CMake-based installation. Will install locally. # It may need environment variables to work, like `export CC=gcc` in ARCHER. +# Parse command line arguments +SILENT=true +if [[ "$1" == "--not-silent" ]]; then + SILENT=false +fi + # Github release from Sundials repository # https://github.com/LLNL/sundials -SUNDIALS_TAG=v6.6.1 -SUNDIALS=sundials-6.6.1 +SUNDIALS_TAG=v7.6.0 +SUNDIALS=sundials-7.6.0 # Make sure CMake is installed, since SUNDIALS requires it. type cmake >/dev/null 2>&1 || { printf "CMake required to build SUNDIALS. You can install it by typing: \nsudo apt install cmake\n"; exit 1;} @@ -42,10 +48,15 @@ download_and_cmake_install() { cmake ${4} ../${2} echo "Compiling and installing "${2}"." - { + if [ "$SILENT" = true ]; then + { + make -j2 + make install + } > /dev/null + else make -j2 make install - } > /dev/null + fi echo "Cleaning up." cd .. diff --git a/doc/install.rst b/doc/install.rst index ce63547d..acf0ff05 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -37,6 +37,8 @@ though many Linux distributions come with these. Using the scripts provided in F bash install-fftw.sh bash install-sundials.sh +The installation script will automatically download and build SUNDIALS v7.6.0. + Python library dependencies are specified in the `pyproject.toml` file. We can install the `fidimag` library in editable mode, using `pip`: .. code-block:: bash diff --git a/fidimag/common/dipolar/demag.c b/fidimag/common/dipolar/demag.c index 0dfd5707..39b95793 100644 --- a/fidimag/common/dipolar/demag.c +++ b/fidimag/common/dipolar/demag.c @@ -479,7 +479,9 @@ void finalize_plan(fft_demag_plan *restrict plan) { fftw_free(plan->hy); fftw_free(plan->hz); - fftw_cleanup_threads(); + // Note: fftw_cleanup_threads() is a global cleanup function and should + // NOT be called per-object. It should only be called once at program exit. + // Calling it here causes crashes when multiple FFTDemag objects are used. free(plan); } diff --git a/fidimag/common/sundials/cvode.pyx b/fidimag/common/sundials/cvode.pyx index d170a98c..43d7a904 100644 --- a/fidimag/common/sundials/cvode.pyx +++ b/fidimag/common/sundials/cvode.pyx @@ -10,13 +10,14 @@ cdef extern from "sundials/sundials_context.h": struct _SUNContext: pass ctypedef _SUNContext *SUNContext + void* SUN_COMM_NULL int SUNContext_Create(void *comm, SUNContext *ctx) int SUNContext_Free(SUNContext *ctx) cdef extern from "sundials/sundials_types.h": - ctypedef double realtype - ctypedef bint booleantype + ctypedef double sunsunrealtype + ctypedef bint sunsunbooleantype # Types for the Sundials Linear System initialization cdef extern from "sundials/sundials_matrix.h": @@ -42,22 +43,22 @@ cdef extern from "sundials/sundials_nvector.h": cdef extern from "nvector/nvector_serial.h": - cdef N_Vector N_VMake_Serial(long int vec_length, realtype *v_data, SUNContext sunctx) + cdef N_Vector N_VMake_Serial(long int vec_length, double *v_data, SUNContext sunctx) struct _N_VectorContent_Serial: long int length - realtype *data - booleantype own_data + double *data + int own_data ctypedef _N_VectorContent_Serial *N_VectorContent_Serial cdef extern from "nvector/nvector_openmp.h": - cdef N_Vector N_VMake_OpenMP(long int vec_length, realtype *v_data, int num_threads, SUNContext sunctx) + cdef N_Vector N_VMake_OpenMP(long int vec_length, double *v_data, int num_threads, SUNContext sunctx) struct _N_VectorContent_OpenMP: long int length - realtype *data - booleantype own_data + double *data + int own_data int num_threads ctypedef _N_VectorContent_OpenMP *N_VectorContent_OpenMP @@ -100,34 +101,34 @@ cdef extern from "cvode/cvode.h": int CV_BAD_DKY int CV_TOO_CLOSE - ctypedef int (*CVRhsFn)(realtype t, N_Vector y, N_Vector ydot, void *user_data) - ctypedef int (*CVRootFn)(realtype t, N_Vector y, realtype *gout, void *user_data) + ctypedef int (*CVRhsFn)(double t, N_Vector y, N_Vector ydot, void *user_data) + ctypedef int (*CVRootFn)(double t, N_Vector y, double *gout, void *user_data) void *CVodeCreate(int lmm, SUNContext sunctx) - # int CVode "CVode"(void *cvode_mem, realtype tout, N_Vector yout, realtype *tret, int itask) nogil + # int CVode "CVode"(void *cvode_mem, double tout, N_Vector yout, double *tret, int itask) nogil int CVodeSetUserData(void *cvode_mem, void *user_data) int CVodeSetMaxOrd(void *cvode_mem, int maxord) int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps) int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil) - int CVodeSetStabLimDet(void *cvode_mem, booleantype stldet) - int CVodeSetInitStep(void *cvode_mem, realtype hin) - int CVodeSetMinStep(void *cvode_mem, realtype hmin) - int CVodeSetMaxStep(void *cvode_mem, realtype hmax) - int CVodeSetStopTime(void *cvode_mem, realtype tstop) + int CVodeSetStabLimDet(void *cvode_mem, int stldet) + int CVodeSetInitStep(void *cvode_mem, double hin) + int CVodeSetMinStep(void *cvode_mem, double hmin) + int CVodeSetMaxStep(void *cvode_mem, double hmax) + int CVodeSetStopTime(void *cvode_mem, double tstop) int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef) int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor) int CVodeSetMaxConvFails(void *cvode_mem, int maxncf) - int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef) + int CVodeSetNonlinConvCoef(void *cvode_mem, double nlscoef) int CVodeSetIterType(void *cvode_mem, int iter) int CVodeSetRootDirection(void *cvode_mem, int *rootdir) int CVodeSetNoInactiveRootWarn(void *cvode_mem) - int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) - int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) - int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) - int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) + int CVodeInit(void *cvode_mem, CVRhsFn f, double t0, N_Vector y0) + int CVodeReInit(void *cvode_mem, double t0, N_Vector y0) + int CVodeSStolerances(void *cvode_mem, double reltol, double abstol) + int CVodeSVtolerances(void *cvode_mem, double reltol, N_Vector abstol) int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) - int CVode(void *cvode_mem, realtype tout, N_Vector yout, realtype *tret, int itask) - int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) + int CVode(void *cvode_mem, double tout, N_Vector yout, double *tret, int itask) + int CVodeGetDky(void *cvode_mem, double t, int k, N_Vector dky) int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw) int CVodeGetNumSteps(void *cvode_mem, long int *nsteps) int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals) @@ -136,11 +137,11 @@ cdef extern from "cvode/cvode.h": int CVodeGetLastOrder(void *cvode_mem, int *qlast) int CVodeGetCurrentOrder(void *cvode_mem, int *qcur) int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred) - int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused) - int CVodeGetLastStep(void *cvode_mem, realtype *hlast) - int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur) - int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur) - int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfac) + int CVodeGetActualInitStep(void *cvode_mem, double *hinused) + int CVodeGetLastStep(void *cvode_mem, double *hlast) + int CVodeGetCurrentStep(void *cvode_mem, double *hcur) + int CVodeGetCurrentTime(void *cvode_mem, double *tcur) + int CVodeGetTolScaleFactor(void *cvode_mem, double *tolsfac) int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight) int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele) int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals) @@ -148,8 +149,8 @@ cdef extern from "cvode/cvode.h": int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps, long int *nfevals, long int *nlinsetups, long int *netfails, int *qlast, - int *qcur, realtype *hinused, realtype *hlast, - realtype *hcur, realtype *tcur) + int *qcur, double *hinused, double *hlast, + double *hcur, double *tcur) int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters) int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, long int *nncfails) int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, long int *nncfails) @@ -180,17 +181,17 @@ cdef extern from "cvode/cvode_ls.h": # int CVSpilsSetPrecType(void *cvode_mem, int pretype) # int CVSpilsSetGSType(void *cvode_mem, int gstype) # int CVSpilsSetMaxl(void *cvode_mem, int maxl) - # int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac) - - ctypedef int (*CVLsPrecSetupFn)(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, - realtype gamma, void *user_data); - ctypedef int (*CVLsPrecSolveFn)(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, realtype gamma, - realtype delta, int lr, void *user_data); - ctypedef int (*CVLsJacTimesSetupFn)(realtype t, N_Vector y, + # int CVSpilsSetEpsLin(void *cvode_mem, sunrealtype eplifac) + + ctypedef int (*CVLsPrecSetupFn)(double t, N_Vector y, N_Vector fy, + int jok, int *jcurPtr, + double gamma, void *user_data); + ctypedef int (*CVLsPrecSolveFn)(double t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, double gamma, + double delta, int lr, void *user_data); + ctypedef int (*CVLsJacTimesSetupFn)(double t, N_Vector y, N_Vector fy, void *user_data); - ctypedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t, + ctypedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, double t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); @@ -312,8 +313,8 @@ cdef int cv_jtimes_openmp(N_Vector v, N_Vector Jv, double t, N_Vector y, N_Vecto return 0 -# static int PSolve(realtype tn, N_Vector u, N_Vector fu, N_Vector r, N_Vector z, -# realtype gamma, realtype delta, int lr, void *user_data); +# static int PSolve(sunrealtype tn, N_Vector u, N_Vector fu, N_Vector r, N_Vector z, +# sunrealtype gamma, sunrealtype delta, int lr, void *user_data); cdef int psolve(double t, N_Vector y, N_Vector fy, N_Vector r, N_Vector z, double gamma, double delta, int lr, void * user_data): copy_nv2nv(z, r) @@ -375,7 +376,7 @@ cdef class CvodeSolver(object): # All of the SUNDIALS objects (vectors, linear and nonlinear solvers, matrices, etc.) # that collectively form a SUNDIALS simulation, hold a reference to a common simulation context object # defined by the SUNContext class. - SUNContext_Create(NULL, & self.sunctx); + SUNContext_Create(SUN_COMM_NULL, & self.sunctx); # The recommended choices for lmm are CV ADAMS for nonstiff problems and CV BDF for # stiff problems. The default Newton iteration is recommended for stiff problems, and @@ -504,10 +505,10 @@ cdef class CvodeSolver(object): return 0 # From exmaples: cvDiurnal_kry.c in Sundials repo: - # static int Precond(realtype tn, N_Vector u, N_Vector fu, booleantype jok, - # booleantype *jcurPtr, realtype gamma, void *user_data) - cdef int Precond(self, double t, N_Vector y, N_Vector fy, booleantype jok, - booleantype * jcurPtr, double gamma, void * user_data): + # static int Precond(sunrealtype tn, N_Vector u, N_Vector fu, sunbooleantype jok, + # sunbooleantype *jcurPtr, sunrealtype gamma, void *user_data) + cdef int Precond(self, double t, N_Vector y, N_Vector fy, int jok, + int * jcurPtr, double gamma, void * user_data): if not jok: copy_nv2arr(y, self.y) return 0 @@ -600,7 +601,7 @@ cdef class CvodeSolver_OpenMP(object): if jtimes_fun is not None: self.has_jtimes = 1 - SUNContext_Create(NULL, & self.sunctx); + SUNContext_Create(SUN_COMM_NULL, & self.sunctx); # Newton iterator is set by default now (Sundials 4.0) self.cvode_mem = CVodeCreate(CV_BDF, self.sunctx) @@ -702,7 +703,7 @@ cdef class CvodeSolver_OpenMP(object): return 0 cdef int Precond(self, double t, N_Vector y, N_Vector fy, - booleantype jok, booleantype * jcurPtr, double gamma, + int jok, int * jcurPtr, double gamma, void * user_data): if not jok: copy_nv2arr_openmp(y, self.y) diff --git a/pyproject.toml b/pyproject.toml index 08335bab..b78d41c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ readme = "README.md" # Not fully supported: # license-files = ["LICENSE.txt"] # license = "BSD-2-Clause" -requires-python = ">= 3.10" +requires-python = ">= 3.14" dependencies = [ 'numpy', 'scipy', diff --git a/setup.py b/setup.py index e40cdee3..dbf0421a 100644 --- a/setup.py +++ b/setup.py @@ -25,16 +25,10 @@ # rpath: run-time search path for the sundials (cvode) and fftw library objects com_link = ['-Wl,-rpath,{},-rpath,{}'.format(str(LIB_DIR), str(LIB_DIR64)), '-fopenmp'] lib_paths = [str(LIB_DIR), str(LIB_DIR64)] -com_libs = ['m', 'fftw3_omp', 'fftw3', 'sundials_cvodes', 'sundials_nvecserial', 'sundials_nvecopenmp', 'blas', 'lapack'] +com_libs = ['m', 'fftw3_omp', 'fftw3', 'sundials_core', 'sundials_cvodes', 'sundials_nvecserial', 'sundials_nvecopenmp', 'blas', 'lapack'] com_args = ['-O3', '-Wno-cpp', '-Wno-unused-function', '-Wall', '-std=c99', '-fopenmp'] com_args_cpp = ['-O3', '-Wno-unused-function', '-Wall', '-std=c++14', '-fopenmp'] -if 'SUNDIALS_INC' in os.environ: - com_inc.append(os.environ['SUNDIALS_INC']) - -if 'FFTW_INC' in os.environ: - com_inc.append(os.environ['FFTW_INC']) - # Find all .pyx files with extensions (source files) -> relative paths ROOT_DIR = MODULE_DIR / 'fidimag' source_files = [s for s in ROOT_DIR.rglob('*.pyx')] # Paths @@ -49,6 +43,12 @@ com_inc = [numpy.get_include(), str(INCLUDE_DIR)] +if 'SUNDIALS_INC' in os.environ: + com_inc.append(os.environ['SUNDIALS_INC']) + +if 'FFTW_INC' in os.environ: + com_inc.append(os.environ['FFTW_INC']) + ext_modules = [] for i, (module, src) in enumerate(zip(ext_names, source_files)): print(sYellow + f"Compiling module {module}" + sReset) @@ -109,7 +109,7 @@ def get_version(): raise Exception("Couldn't find __version__ in %s" % pkg_init_path) -nthreads = multiprocessing.cpu_count() +nthreads = 0 # Disabled parallel compilation due to Python 3.14 multiprocessing issues (0 = no multiprocessing) print(sYellow + f'Building with {nthreads} threads' + sReset) setup( name='fidimag',