diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bd94e50722a6b15e10e1ee1f6f7090d303d7387..da5ac435be809258e42f59ce8a2737c4e0d172ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,8 +355,6 @@ endif() #-------------- if(ARB_WITH_GPU) - target_compile_definitions(arbor-config-defs INTERFACE ARB_HAVE_GPU) - if(ARB_WITH_NVCC OR ARB_WITH_CUDA_CLANG) target_include_directories(arborenv-private-deps INTERFACE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) add_compile_options( diff --git a/arbor/fvm_layout.cpp b/arbor/fvm_layout.cpp index 7ede9f7c8fe816da055c78e240b1a8c5c4761e29..65d0a61a0e19b3c9b5a527b212764bd69b9d284d 100644 --- a/arbor/fvm_layout.cpp +++ b/arbor/fvm_layout.cpp @@ -808,7 +808,7 @@ fvm_mechanism_data fvm_build_mechanism_data( fvm_mechanism_config config; if (info.kind != arb_mechanism_kind_density) { - throw cable_cell_error("expected density mechanism, got " +name +" which has " +arb_mechsnism_kind_str(info.kind)); + throw cable_cell_error("expected density mechanism, got " +name +" which has " +arb_mechanism_kind_str(info.kind)); } config.kind = arb_mechanism_kind_density; @@ -918,7 +918,7 @@ fvm_mechanism_data fvm_build_mechanism_data( mechanism_info info = catalogue[name]; if (info.kind != arb_mechanism_kind_point) { - throw cable_cell_error("expected point mechanism, got " +name +" which has " +arb_mechsnism_kind_str(info.kind)); + throw cable_cell_error("expected point mechanism, got " +name +" which has " +arb_mechanism_kind_str(info.kind)); } post_events |= info.post_events; @@ -1077,7 +1077,7 @@ fvm_mechanism_data fvm_build_mechanism_data( for (const auto& [name, placements]: cell.junctions()) { mechanism_info info = catalogue[name]; if (info.kind != arb_mechanism_kind_gap_junction) { - throw cable_cell_error("expected gap_junction mechanism, got " +name +" which has " +arb_mechsnism_kind_str(info.kind)); + throw cable_cell_error("expected gap_junction mechanism, got " +name +" which has " +arb_mechanism_kind_str(info.kind)); } fvm_mechanism_config config; @@ -1268,7 +1268,7 @@ fvm_mechanism_data fvm_build_mechanism_data( const mechanism_desc& revpot = *maybe_revpot; mechanism_info info = catalogue[revpot.name()]; if (info.kind != arb_mechanism_kind_reversal_potential) { - throw cable_cell_error("expected reversal potential mechanism for ion " +ion +", got "+ revpot.name() +" which has " +arb_mechsnism_kind_str(info.kind)); + throw cable_cell_error("expected reversal potential mechanism for ion " +ion +", got "+ revpot.name() +" which has " +arb_mechanism_kind_str(info.kind)); } verify_mechanism(info, revpot); diff --git a/arbor/fvm_lowered_cell_impl.cpp b/arbor/fvm_lowered_cell_impl.cpp index 01b0ee0fd7eaa5fb0a96db3a59f11fcb11ca7fcb..9e521a9e36d433004cdcae3fa8a943149ef9b667 100644 --- a/arbor/fvm_lowered_cell_impl.cpp +++ b/arbor/fvm_lowered_cell_impl.cpp @@ -3,9 +3,10 @@ #include <arbor/arbexcept.hpp> #include <arbor/common_types.hpp> +#include <arbor/version.hpp> #include "backends/multicore/fvm.hpp" -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED #include "backends/gpu/fvm.hpp" #endif #include "fvm_lowered_cell_impl.hpp" @@ -17,7 +18,7 @@ fvm_lowered_cell_ptr make_fvm_lowered_cell(backend_kind p, const execution_conte case backend_kind::multicore: return fvm_lowered_cell_ptr(new fvm_lowered_cell_impl<multicore::backend>(ctx)); case backend_kind::gpu: -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED return fvm_lowered_cell_ptr(new fvm_lowered_cell_impl<gpu::backend>(ctx)); #endif ; // fall through diff --git a/arbor/gpu_context.cpp b/arbor/gpu_context.cpp index baad4acfea3028fc96593d87738cdae4cb65d245..ff1dbde0f1a659cf061931ff7ce2db00bfc9c802 100644 --- a/arbor/gpu_context.cpp +++ b/arbor/gpu_context.cpp @@ -1,10 +1,10 @@ #include <memory> #include <arbor/arbexcept.hpp> - +#include <arbor/version.hpp> #include "gpu_context.hpp" -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED #include <arbor/gpu/gpu_api.hpp> #endif @@ -30,7 +30,7 @@ bool gpu_context::has_gpu() const { return id_ != -1; } -#ifndef ARB_HAVE_GPU +#ifndef ARB_GPU_ENABLED void gpu_context::set_gpu() const { throw arbor_exception("Arbor must be compiled with CUDA/HIP support to set a GPU."); diff --git a/arbor/hardware/memory.cpp b/arbor/hardware/memory.cpp index 4274ede47640a81846f117cba6944885a75eede8..f2370a68c0f37c348d78f83cd32c53b0fd0795ec 100644 --- a/arbor/hardware/memory.cpp +++ b/arbor/hardware/memory.cpp @@ -1,4 +1,5 @@ #include "memory.hpp" +#include <arbor/version.hpp> #ifdef __linux__ extern "C" { @@ -6,7 +7,7 @@ extern "C" { } #endif -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED #include <arbor/gpu/gpu_api.hpp> #endif diff --git a/arbor/include/arbor/mechanism_abi.h b/arbor/include/arbor/mechanism_abi.h index 69e11c7c47cb5198b8dd2201a5f3ba9b8772c1e3..2998bc765d90f6d54957a4e83c1038dd43a39db7 100644 --- a/arbor/include/arbor/mechanism_abi.h +++ b/arbor/include/arbor/mechanism_abi.h @@ -9,8 +9,8 @@ extern "C" { // Version #define ARB_MECH_ABI_VERSION_MAJOR 0 -#define ARB_MECH_ABI_VERSION_MINOR 0 -#define ARB_MECH_ABI_VERSION_PATCH 1 +#define ARB_MECH_ABI_VERSION_MINOR 1 +#define ARB_MECH_ABI_VERSION_PATCH 0 #define ARB_MECH_ABI_VERSION ((ARB_MECH_ABI_VERSION_MAJOR * 10000L * 10000L) + (ARB_MECH_ABI_VERSION_MAJOR * 10000L) + ARB_MECH_ABI_VERSION_PATCH) typedef const char* arb_mechanism_fingerprint; @@ -28,7 +28,7 @@ typedef uint32_t arb_backend_kind; #define arb_backend_kind_cpu 1 #define arb_backend_kind_gpu 2 -inline const char* arb_mechsnism_kind_str(const arb_mechanism_kind& mech) { +inline const char* arb_mechanism_kind_str(const arb_mechanism_kind& mech) { switch (mech) { case arb_mechanism_kind_density: return "density mechanism kind"; case arb_mechanism_kind_point: return "point mechanism kind"; @@ -208,6 +208,16 @@ typedef struct arb_mechanism_type { arb_size_type n_ions; } arb_mechanism_type; +// Bundle a type and its interfaces +typedef arb_mechanism_type (*arb_get_mechanism_type)(); +typedef arb_mechanism_interface* (*arb_get_mechanism_interface)(); + +typedef struct arb_mechanism { + arb_get_mechanism_type type; + arb_get_mechanism_interface i_cpu; + arb_get_mechanism_interface i_gpu; +} arb_mechanism; + #ifdef __cplusplus } #endif diff --git a/arbor/include/arbor/mechcat.hpp b/arbor/include/arbor/mechcat.hpp index c7811725bea6b7051292ef13a569048e6edbbf16..c8f98bd329b7e80c5b6d801b5f32c2f19565edab 100644 --- a/arbor/include/arbor/mechcat.hpp +++ b/arbor/include/arbor/mechcat.hpp @@ -115,6 +115,6 @@ ARB_ARBOR_API const mechanism_catalogue& global_allen_catalogue(); ARB_ARBOR_API const mechanism_catalogue& global_bbp_catalogue(); // Load catalogue from disk. -ARB_ARBOR_API const mechanism_catalogue& load_catalogue(const std::string&); +ARB_ARBOR_API const mechanism_catalogue load_catalogue(const std::string&); } // namespace arb diff --git a/arbor/mechcat.cpp b/arbor/mechcat.cpp index 161c5f9a58253d770e65f8db721d08ac66de02eb..4fb428d6ead27c2856219c3eab89401067423673 100644 --- a/arbor/mechcat.cpp +++ b/arbor/mechcat.cpp @@ -592,8 +592,8 @@ std::pair<mechanism_ptr, mechanism_overrides> mechanism_catalogue::instance_impl mechanism_catalogue::~mechanism_catalogue() = default; -ARB_ARBOR_API const mechanism_catalogue& load_catalogue(const std::string& fn) { - typedef const void* global_catalogue_t(); +ARB_ARBOR_API const mechanism_catalogue load_catalogue(const std::string& fn) { + typedef void* global_catalogue_t(int*); global_catalogue_t* get_catalogue = nullptr; try { get_catalogue = util::dl_get_symbol<global_catalogue_t*>(fn, "get_catalogue"); @@ -608,7 +608,32 @@ ARB_ARBOR_API const mechanism_catalogue& load_catalogue(const std::string& fn) { * different lifetime than the actual catalogue itfself. This is not a leak, * as `dlopen` caches handles for us. */ - return *((const mechanism_catalogue*)get_catalogue()); + int count = -1; + auto mechs = (arb_mechanism*)get_catalogue(&count); + if (count <= 0) { + throw bad_catalogue_error{util::pprintf("Invalid mechanism count {} in shared object '{}'", count, fn)}; + } + mechanism_catalogue result; + for(int ix = 0; ix < count; ++ix) { + auto type = mechs[ix].type(); + auto name = std::string{type.name}; + if (name == "") { + throw bad_catalogue_error{util::pprintf("Empty name for mechanism in '{}'", fn)}; + } + auto icpu = mechs[ix].i_cpu(); + auto igpu = mechs[ix].i_gpu(); + if (!icpu && !igpu) { + throw bad_catalogue_error{util::pprintf("Empty interfaces for mechanism '{}'", name)}; + } + result.add(name, type); + if (icpu) { + result.register_implementation(name, std::make_unique<mechanism>(type, *icpu)); + } + if (igpu) { + result.register_implementation(name, std::make_unique<mechanism>(type, *igpu)); + } + } + return result; } } // namespace arb diff --git a/arbor/memory/gpu_wrappers.cpp b/arbor/memory/gpu_wrappers.cpp index d037f5b9b732889af9e34c71df6e2a2991a32c08..443bac893f5cee67003f34cf49408bfde8f907bd 100644 --- a/arbor/memory/gpu_wrappers.cpp +++ b/arbor/memory/gpu_wrappers.cpp @@ -2,10 +2,11 @@ #include <string> #include <arbor/arbexcept.hpp> +#include <arbor/version.hpp> #include "util.hpp" -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED #include <arbor/gpu/gpu_api.hpp> diff --git a/arbor/util/config.hpp b/arbor/util/config.hpp index 44273152ef0bbeb5644ad64f23b039447890dc9e..5e8824b74b3d8b2efb1b717556986ebcb9854e09 100644 --- a/arbor/util/config.hpp +++ b/arbor/util/config.hpp @@ -1,5 +1,7 @@ #pragma once +#include <arbor/version.hpp> + namespace arb { namespace config { @@ -29,7 +31,7 @@ constexpr bool has_power_measurement = true; constexpr bool has_power_measurement = false; #endif -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED constexpr bool has_gpu = true; #else constexpr bool has_gpu = false; diff --git a/arborenv/default_env.cpp b/arborenv/default_env.cpp index ddeff5fe82b6b6db388d9cc621037bd69130f644..f35b17308db7bbd4957105a04b0b05764b5b8e64 100644 --- a/arborenv/default_env.cpp +++ b/arborenv/default_env.cpp @@ -1,11 +1,12 @@ #include <limits> #include <optional> +#include <arbor/version.hpp> #include <arborenv/arbenvexcept.hpp> #include <arborenv/concurrency.hpp> #include <arborenv/default_env.hpp> -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED #include "gpu_api.hpp" #endif @@ -29,7 +30,7 @@ ARB_ARBORENV_API unsigned long get_env_num_threads() { return *env_val; } -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED ARB_ARBORENV_API int default_gpu() { constexpr const char* env_var = "ARBENV_GPU_ID"; @@ -60,7 +61,7 @@ ARB_ARBORENV_API int default_gpu() { return -1; } -#endif // def ARB_HAVE_GPU +#endif // def ARB_GPU_ENABLED } // namespace arbenv diff --git a/arborenv/private_gpu.cpp b/arborenv/private_gpu.cpp index ee5cd531d294f70e9914075d67c6f1acc6c83425..edcaef6a459d470ea7901ffdb499d96999dd431b 100644 --- a/arborenv/private_gpu.cpp +++ b/arborenv/private_gpu.cpp @@ -5,13 +5,14 @@ #include <mpi.h> +#include <arbor/version.hpp> #include <arborenv/arbenvexcept.hpp> #include <arborenv/gpu_env.hpp> #include "gpu_uuid.hpp" namespace arbenv { -#ifdef ARB_HAVE_GPU +#ifdef ARB_GPU_ENABLED template <> ARB_ARBORENV_API int find_private_gpu(MPI_Comm comm) { @@ -100,7 +101,7 @@ ARB_ARBORENV_API int find_private_gpu(MPI_Comm comm) { return -1; } -#endif // def ARB_HAVE_GPU +#endif // def ARB_GPU_ENABLED } // namespace arbenv diff --git a/doc/dev/mechanism_abi.rst b/doc/dev/mechanism_abi.rst index a8c9205900f1ca9d98194dfe7f72536657e62316..f077e77296f4f2dfb2ab0bde077ed7132a00140b 100644 --- a/doc/dev/mechanism_abi.rst +++ b/doc/dev/mechanism_abi.rst @@ -444,16 +444,36 @@ interface layer <simd>` for more information. Making A Loadable Mechanism --------------------------- -Mechanisms interface with Arbor by providing three functions, one -returning the metadata portion, and one for each implemented backend (currently -two). The latter may return a NULL pointer, indicating that this backend is not -supported. The naming scheme is shown in the example below +Mechanisms interface with Arbor by providing a single function, returning +a structure + +.. c:struct:: arb_mechanism + + .. c:member:: arb_get_mechanism_type type + + Pointer to a function ``arb_mechanism_type get_type()`` + + .. c:member:: arb_get_mechanism_interface i_cpu + + Pointer to a function ``arb_mechanism_interface get_interface()`` + that returns a pointer to the CPU interface which may be + ``null``. + + .. c:member:: arb_get_mechanism_interface i_gpu + + Pointer to a function ``arb_mechanism_interace get_interface()`` + that returns a pointer to the GPU interface which may be + ``null``. + +You can create mechanisms with both ``i_gpu`` and ``i_cpu`` returning ``null``, +but at least one of the interfaces must be provided or Arbor will refuse to load +the catalogue this mechanism. + +The naming scheme is shown in the example below .. code:: C - arb_mechanism_type make_arb_default_catalogue_pas(); - arb_mechanism_interface* make_arb_default_catalogue_pas_interface_multicore(); - arb_mechanism_interface* make_arb_default_catalogue_pas_interface_gpu(); + arb_mechanism make_arb_default_catalogue_pas(); Writing Mechanisms Directly Against the ABI ------------------------------------------- diff --git a/mechanisms/BuildModules.cmake b/mechanisms/BuildModules.cmake index 3aadf9fcb4a8aa6dc6e3e24633390667f386bb33..83b8467cbb81eb5cc0dea673c70683d6111cfa0b 100644 --- a/mechanisms/BuildModules.cmake +++ b/mechanisms/BuildModules.cmake @@ -123,11 +123,17 @@ function("make_catalogue") list(APPEND catalogue_${MK_CAT_NAME}_source ${MK_CAT_OUT_DIR}/${mech}_gpu.cpp ${MK_CAT_OUT_DIR}/${mech}_gpu.cu) endif() endforeach() + set(${MK_CAT_OUTPUT} ${catalogue_${MK_CAT_NAME}_source} PARENT_SCOPE) if(${MK_CAT_STANDALONE}) add_library(${MK_CAT_NAME}-catalogue SHARED ${catalogue_${MK_CAT_NAME}_source}) target_compile_definitions(${MK_CAT_NAME}-catalogue PUBLIC STANDALONE=1) + + if(ARB_WITH_GPU) + target_compile_definitions(${MK_CAT_NAME}-catalogue PUBLIC ARB_GPU_ENABLED) + endif() + target_compile_options(${MK_CAT_NAME}-catalogue PUBLIC ${MK_CAT_CXX_FLAGS_TARGET}) set_target_properties(${MK_CAT_NAME}-catalogue PROPERTIES diff --git a/mechanisms/generate_catalogue b/mechanisms/generate_catalogue index 53eec3af393cb2a93e7d3eb43d28bc245c68416e..2a63f7d16e1e84df88d02ec568ec6aec97cc37ce 100755 --- a/mechanisms/generate_catalogue +++ b/mechanisms/generate_catalogue @@ -96,19 +96,46 @@ def generate(catalogue, modpfx='', arbpfx='', modules=[], backends=[], namespace r'''// Automatically generated by: // $cmdline -#include <${arbpfx}mechcat.hpp> -#include <${arbpfx}mechanism.hpp> #include <${arbpfx}mechanism_abi.h> -$backend_includes + $module_includes -namespace arb { +#ifdef STANDALONE +extern "C" { + [[gnu::visibility("default")]] const void* get_catalogue(int* n) { + static arb_mechanism cat[${n_modules}] = { + ${insert_modules} + }; + *n = ${n_modules}; + return (void*)cat; + } +} +#else + +#include <${arbpfx}mechcat.hpp> +#include <${arbpfx}mechanism.hpp> +#include <${arbpfx}assert.hpp> +namespace arb { mechanism_catalogue build_${catalogue}_catalogue() { mechanism_catalogue cat; +#define ADD(make) do { \ + auto mech = make(); \ + auto ty = mech.type(); \ + auto nm = ty.name; \ + auto ig = mech.i_gpu(); \ + auto ic = mech.i_cpu(); \ + arb_assert(ic || ig); \ + cat.add(nm, ty); \ + if (ic) cat.register_implementation(nm, std::make_unique<arb::mechanism>(ty, *ic)); \ + if (ig) cat.register_implementation(nm, std::make_unique<arb::mechanism>(ty, *ig)); \ +} while (false) + $add_modules - $register_modules + +#undef ADD + return cat; } @@ -116,36 +143,22 @@ ARB_ARBOR_API const mechanism_catalogue& global_${catalogue}_catalogue() { static mechanism_catalogue cat = build_${catalogue}_catalogue(); return cat; } - } // namespace arb - -#ifdef STANDALONE -extern "C" { - [[gnu::visibility("default")]] const void* get_catalogue() { - static auto cat = arb::build_${catalogue}_catalogue(); - return (void*)&cat; - } -} #endif ''') def indent(n, lines): return '{{:<{0!s}}}'.format(n+1).format('\n').join(lines) - # TODO: use the commented include list below when private/public - # headers are resolved. - return src.safe_substitute(dict( cmdline=" ".join(sys.argv), arbpfx=arbpfx, catalogue=catalogue, - backend_includes = indent(0, []), - module_includes = indent(0, + module_includes=indent(0, ['#include "{}{}.hpp"'.format(modpfx, m) for m in modules]), - add_modules = indent(4, - [f'cat.add("{mod}", make_arb_{catalogue}_catalogue_{mod}());' for mod in modules]), - register_modules = indent(4, - [f'cat.register_implementation("{mod}", std::make_unique<mechanism>(make_arb_{catalogue}_catalogue_{mod}(), *make_arb_{catalogue}_catalogue_{mod}_interface_{be}()));' for mod in modules for be in backends]) + add_modules=indent(4, [f'ADD(make_arb_{catalogue}_catalogue_{mod});' for mod in modules]), + n_modules=len(modules), + insert_modules=indent(12, [f'make_arb_{catalogue}_catalogue_{mod}(),' for mod in modules]), )) diff --git a/modcc/printer/infoprinter.cpp b/modcc/printer/infoprinter.cpp index 0db24b4990e3a18919dc3ee19945031d57769844..c796b513097ac3ae9b9b3ba001efa0f297efefe8 100644 --- a/modcc/printer/infoprinter.cpp +++ b/modcc/printer/infoprinter.cpp @@ -29,15 +29,17 @@ ARB_LIBMODCC_API std::string build_info_header(const Module& m, const printer_op const auto lowest = std::to_string(std::numeric_limits<double>::lowest()); const auto max = std::to_string(std::numeric_limits<double>::max()); + const auto prefix = std::regex_replace(opt.cpp_namespace, std::regex{"::"}, "_"); + out << fmt::format("#pragma once\n\n" "#include <cmath>\n" - "#include <{}mechanism_abi.h>\n\n", + "#include <{0}version.hpp>\n" + "#include <{0}mechanism_abi.h>\n\n", arb_header_prefix()); - out << fmt::format("extern \"C\" {{\n" - " arb_mechanism_type make_{0}_{1}() {{\n" + " arb_mechanism_type make_{0}_{1}_type() {{\n" " // Tables\n", - std::regex_replace(opt.cpp_namespace, std::regex{"::"}, "_"), + prefix, name); const auto& [state_ids, global_ids, param_ids] = public_variable_ids(m); @@ -108,12 +110,22 @@ ARB_LIBMODCC_API std::string build_info_header(const Module& m, const printer_op module_kind_str(m), m.is_linear(), m.has_post_events()) - << fmt::format(" arb_mechanism_interface* make_{0}_{1}_interface_multicore(){2}\n" - " arb_mechanism_interface* make_{0}_{1}_interface_gpu(){3}\n" - "}}\n", - std::regex_replace(opt.cpp_namespace, std::regex{"::"}, "_"), - name, - cpu ? ";" : " { return nullptr; }", - gpu ? ";" : " { return nullptr; }"); + << fmt::format(" arb_mechanism_interface* make_{0}_{1}_interface_multicore();\n" + " arb_mechanism_interface* make_{0}_{1}_interface_gpu();\n" + "\n" + " #ifndef ARB_GPU_ENABLED\n" + " arb_mechanism_interface* make_{0}_{1}_interface_gpu() {{ return nullptr; }}\n" + " #endif\n" + "\n" + " arb_mechanism make_{0}_{1}() {{\n" + " static arb_mechanism result = {{}};\n" + " result.type = make_{0}_{1}_type;\n" + " result.i_cpu = make_{0}_{1}_interface_multicore;\n" + " result.i_gpu = make_{0}_{1}_interface_gpu;\n" + " return result;\n" + " }}\n" + "}} // extern C\n", + prefix, + name); return out.str(); } diff --git a/python/example/dynamic-catalogue.py b/python/example/dynamic-catalogue.py index 773eab0415d400a4d95d194dc105c706e84b0f99..bedd86de81eef64e2e8998a253d42c9e04993cf0 100644 --- a/python/example/dynamic-catalogue.py +++ b/python/example/dynamic-catalogue.py @@ -4,7 +4,7 @@ from pathlib import Path import arbor as arb -cat = 'cat-catalogue.so' +cat = Path('cat-catalogue.so').resolve() class recipe(arb.recipe): def __init__(self): @@ -14,7 +14,7 @@ class recipe(arb.recipe): self.props = arb.neuron_cable_properties() self.props.catalogue = arb.load_catalogue(cat) d = arb.decor() - d.paint('(all)', 'dummy') + d.paint('(all)', arb.density('dummy')) d.set_property(Vm=0.0) self.cell = arb.cable_cell(self.tree, arb.label_dict(), d) @@ -30,10 +30,10 @@ class recipe(arb.recipe): def cell_description(self, gid): return self.cell -if not Path(cat).is_file(): +if not cat.is_file(): print("""Catalogue not found in this directory. -Please ensure it has been compiled by calling") - <arbor>/scripts/build-catalogue cat <arbor>/python/examples/cat +Please ensure it has been compiled by calling + <arbor>/scripts/build-catalogue cat <arbor>/python/example/cat where <arbor> is the location of the arbor source tree.""") exit(1) diff --git a/python/mechanism.cpp b/python/mechanism.cpp index a97d035d730c85b07f11ade750f93fd759438669..a5ee801fc40e519eefda3c92bb13728cc98d3127 100644 --- a/python/mechanism.cpp +++ b/python/mechanism.cpp @@ -101,7 +101,7 @@ void register_mechanisms(pybind11::module& m) { "True if a synapse mechanism has a `POST_EVENT` procedure defined.") .def_property_readonly("kind", [](const arb::mechanism_info& info) { - return arb_mechsnism_kind_str(info.kind); + return arb_mechanism_kind_str(info.kind); }, "String representation of the kind of the mechanism.") .def("__repr__", [](const arb::mechanism_info& inf) { diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index d7d1954a6a834e21afe130f3a8f56c5e3a0189de..98b5eeed9341e0c95ecc4b48424c196910be49dc 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -241,6 +241,10 @@ if(${CMAKE_POSITION_INDEPENDENT_CODE}) add_dependencies(unit dummy-catalogue) endif() +if(ARB_WITH_GPU) + target_compile_definitions(unit PRIVATE ARB_GPU_ENABLED) +endif() + if(ARB_WITH_NVCC) target_compile_options(unit PRIVATE -DARB_CUDA) endif() diff --git a/test/unit/test_mechcat.cpp b/test/unit/test_mechcat.cpp index 181c203476bf73868add8ee28d8b3ecabe59ee89..8c863b6100e94fc70808b9794d4cdf09bdea2d7e 100644 --- a/test/unit/test_mechcat.cpp +++ b/test/unit/test_mechcat.cpp @@ -289,11 +289,9 @@ TEST(mechcat, loading) { #endif #else EXPECT_THROW(load_catalogue(LIBDIR "/libarbor.a"), bad_catalogue_error); + const mechanism_catalogue cat = load_catalogue(LIBDIR "/dummy-catalogue.so"); + EXPECT_EQ(std::vector<std::string>{"dummy"}, cat.mechanism_names()); #endif - const mechanism_catalogue* cat = nullptr; - EXPECT_NO_THROW(cat = &load_catalogue(LIBDIR "/dummy-catalogue.so")); - ASSERT_NE(cat, nullptr); - EXPECT_EQ(std::vector<std::string>{"dummy"}, cat->mechanism_names()); } #endif diff --git a/test/unit/unit_test_catalogue.cpp b/test/unit/unit_test_catalogue.cpp index 807ccabb7688127994a130da2b454236176e44f5..a87b0529485640749c025b6ea8d0780835c3f5fe 100644 --- a/test/unit/unit_test_catalogue.cpp +++ b/test/unit/unit_test_catalogue.cpp @@ -48,60 +48,58 @@ #include "../gtest.h" -#ifndef ARB_GPU_ENABLED -#define ADD_MECH(c, x)\ -c.add(#x, make_testing_##x()); \ -c.register_implementation(#x, std::make_unique<arb::mechanism>(make_testing_##x(), *make_testing_##x##_interface_multicore())); -#else -#define ADD_MECH(c, x)\ -c.add(#x, make_testing_##x()); \ -c.register_implementation(#x, std::make_unique<arb::mechanism>(make_testing_##x(), *make_testing_##x##_interface_multicore())); \ -c.register_implementation(#x, std::make_unique<arb::mechanism>(make_testing_##x(), *make_testing_##x##_interface_gpu())); -#endif +#define ADD_MECH(c, x) do { \ + auto mech = make_testing_##x(); \ + c.add(#x, mech.type()); \ + c.register_implementation(#x, std::make_unique<arb::mechanism>(mech.type(), *mech.i_cpu())); \ + if (mech.i_gpu()) { \ + c.register_implementation(#x, std::make_unique<arb::mechanism>(mech.type(), *mech.i_gpu())); \ + } \ + } while (false) using namespace arb; mechanism_catalogue make_unit_test_catalogue(const mechanism_catalogue& from) { mechanism_catalogue cat = from; - ADD_MECH(cat, gj0) - ADD_MECH(cat, gj1) - ADD_MECH(cat, test_ca) - ADD_MECH(cat, test_kin1) - ADD_MECH(cat, test_kinlva) - ADD_MECH(cat, ca_linear) - ADD_MECH(cat, celsius_test) - ADD_MECH(cat, diam_test) - ADD_MECH(cat, param_as_state) - ADD_MECH(cat, post_events_syn) - ADD_MECH(cat, test_linear_state) - ADD_MECH(cat, test_linear_init) - ADD_MECH(cat, test_linear_init_shuffle) - ADD_MECH(cat, test0_kin_diff) - ADD_MECH(cat, test0_kin_conserve) - ADD_MECH(cat, test0_kin_steadystate) - ADD_MECH(cat, test0_kin_compartment) - ADD_MECH(cat, test1_kin_diff) - ADD_MECH(cat, test1_kin_conserve) - ADD_MECH(cat, test2_kin_diff) - ADD_MECH(cat, test3_kin_diff) - ADD_MECH(cat, test1_kin_steadystate) - ADD_MECH(cat, test1_kin_compartment) - ADD_MECH(cat, test4_kin_compartment) - ADD_MECH(cat, test5_nonlinear_diff) - ADD_MECH(cat, test6_nonlinear_diff) - ADD_MECH(cat, fixed_ica_current) - ADD_MECH(cat, non_linear) - ADD_MECH(cat, point_ica_current) - ADD_MECH(cat, linear_ca_conc) - ADD_MECH(cat, test_cl_valence) - ADD_MECH(cat, test_ca_read_valence) - ADD_MECH(cat, read_eX) - ADD_MECH(cat, write_Xi_Xo) - ADD_MECH(cat, write_multiple_eX) - ADD_MECH(cat, write_eX) - ADD_MECH(cat, read_cai_init) - ADD_MECH(cat, write_cai_breakpoint) + ADD_MECH(cat, gj0); + ADD_MECH(cat, gj1); + ADD_MECH(cat, test_ca); + ADD_MECH(cat, test_kin1); + ADD_MECH(cat, test_kinlva); + ADD_MECH(cat, ca_linear); + ADD_MECH(cat, celsius_test); + ADD_MECH(cat, diam_test); + ADD_MECH(cat, param_as_state); + ADD_MECH(cat, post_events_syn); + ADD_MECH(cat, test_linear_state); + ADD_MECH(cat, test_linear_init); + ADD_MECH(cat, test_linear_init_shuffle); + ADD_MECH(cat, test0_kin_diff); + ADD_MECH(cat, test0_kin_conserve); + ADD_MECH(cat, test0_kin_steadystate); + ADD_MECH(cat, test0_kin_compartment); + ADD_MECH(cat, test1_kin_diff); + ADD_MECH(cat, test1_kin_conserve); + ADD_MECH(cat, test2_kin_diff); + ADD_MECH(cat, test3_kin_diff); + ADD_MECH(cat, test1_kin_steadystate); + ADD_MECH(cat, test1_kin_compartment); + ADD_MECH(cat, test4_kin_compartment); + ADD_MECH(cat, test5_nonlinear_diff); + ADD_MECH(cat, test6_nonlinear_diff); + ADD_MECH(cat, fixed_ica_current); + ADD_MECH(cat, non_linear); + ADD_MECH(cat, point_ica_current); + ADD_MECH(cat, linear_ca_conc); + ADD_MECH(cat, test_cl_valence); + ADD_MECH(cat, test_ca_read_valence); + ADD_MECH(cat, read_eX); + ADD_MECH(cat, write_Xi_Xo); + ADD_MECH(cat, write_multiple_eX); + ADD_MECH(cat, write_eX); + ADD_MECH(cat, read_cai_init); + ADD_MECH(cat, write_cai_breakpoint); return cat; }