From 8a65f5fbf18444e2340e2c385cbd9dbc07295a6d Mon Sep 17 00:00:00 2001 From: Juan Hernando Vieites Date: Tue, 25 Apr 2017 16:25:56 +0200 Subject: [PATCH 1/2] Added support for parsing Projection sections in blue configs --- brion/blueConfig.cpp | 37 +++++++++++++++++++++++++++---------- brion/blueConfig.h | 13 ++++++++++--- brion/constants.h | 2 ++ brion/enums.h | 3 ++- tests/blueConfig.cpp | 28 ++++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/brion/blueConfig.cpp b/brion/blueConfig.cpp index 113d12a..ace7241 100644 --- a/brion/blueConfig.cpp +++ b/brion/blueConfig.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -41,12 +40,14 @@ inline brion::BlueConfigSection lexical_cast(const std::string& s) return brion::CONFIGSECTION_RUN; if (s == "Connection") return brion::CONFIGSECTION_CONNECTION; + if (s == "Projection") + return brion::CONFIGSECTION_PROJECTION; + if (s == "Report") + return brion::CONFIGSECTION_REPORT; if (s == "Stimulus") return brion::CONFIGSECTION_STIMULUS; if (s == "StimulusInject") return brion::CONFIGSECTION_STIMULUSINJECT; - if (s == "Report") - return brion::CONFIGSECTION_REPORT; return brion::CONFIGSECTION_UNKNOWN; } @@ -59,12 +60,14 @@ inline std::string lexical_cast(const brion::BlueConfigSection& b) return "Run"; case brion::CONFIGSECTION_CONNECTION: return "Connection"; + case brion::CONFIGSECTION_PROJECTION: + return "Projection"; + case brion::CONFIGSECTION_REPORT: + return "Report"; case brion::CONFIGSECTION_STIMULUS: return "Stimulus"; case brion::CONFIGSECTION_STIMULUSINJECT: return "StimulusInject"; - case brion::CONFIGSECTION_REPORT: - return "Report"; default: return "UNKNOWN"; } @@ -128,7 +131,7 @@ class BlueConfig boost::split(lines, content, boost::is_any_of("\n"), boost::token_compress_on); - BOOST_FOREACH (std::string line, lines) + for (std::string line : lines) { boost::trim(line); if (line.empty()) @@ -237,7 +240,7 @@ brion::Targets BlueConfig::getTargets() const { Targets targets; const URIs& uris = getTargetSources(); - BOOST_FOREACH (const URI& uri, uris) + for (const URI& uri : uris) targets.push_back(Target(uri.getPath())); return targets; } @@ -266,6 +269,21 @@ URI BlueConfig::getSynapseSource() const return uri; } +URI BlueConfig::getProjectionSource(const std::string& name) const +{ + std::string path = + get(CONFIGSECTION_PROJECTION, name, BLUECONFIG_PROJECTION_PATH_KEY); + if (path.empty()) + { + LBWARN << "Invalid or missing projection " << name << std::endl; + return URI(); + } + URI uri; + uri.setScheme("file"); + uri.setPath(path); + return uri; +} + URI BlueConfig::getMorphologySource() const { URI uri; @@ -368,12 +386,11 @@ std::ostream& operator<<(std::ostream& os, const BlueConfig& config) { for (size_t i = 0; i < CONFIGSECTION_ALL; ++i) { - BOOST_FOREACH (const ValueTable::value_type& entry, - config._impl->table[i]) + for (const ValueTable::value_type& entry : config._impl->table[i]) { os << boost::lexical_cast(BlueConfigSection(i)) << " " << entry.first << std::endl; - BOOST_FOREACH (const KVStore::value_type& pair, entry.second) + for (const KVStore::value_type& pair : entry.second) { os << " " << pair.first << " " << pair.second << std::endl; } diff --git a/brion/blueConfig.h b/brion/blueConfig.h index 62681e8..a920f01 100644 --- a/brion/blueConfig.h +++ b/brion/blueConfig.h @@ -116,10 +116,17 @@ class BlueConfig : public boost::noncopyable BRION_API URI getSynapseSource() const; /** - * @return the full path to the morphology database. A suffix may be - * prepended to the to the bare path from the BlueConfig. - * @version 1.7 + * @return the URI to the location of synapse nrn files for projections from + * external circuits (e.g. thalamocortical projections) + * @version 2.0 */ + BRION_API URI getProjectionSource(const std::string& name) const; + + /** + * @return the full path to the morphology database. A suffix may be + * prepended to the to the bare path from the BlueConfig. + * @version 1.7 + */ BRION_API URI getMorphologySource() const; /** @return the URI to the named report. @sa CompartmentReport diff --git a/brion/constants.h b/brion/constants.h index b545b0e..3b0337a 100644 --- a/brion/constants.h +++ b/brion/constants.h @@ -39,6 +39,8 @@ const char* const BLUECONFIG_SPIKES_PATH_KEY = "SpikesPath"; const char* const BLUECONFIG_CIRCUIT_TARGET_KEY = "CircuitTarget"; const char* const BLUECONFIG_REPORT_FORMAT_KEY = "Format"; const char* const BLUECONFIG_DT_KEY = "Dt"; + +const char* const BLUECONFIG_PROJECTION_PATH_KEY = "Path"; } #endif diff --git a/brion/enums.h b/brion/enums.h index 65ab642..432583b 100644 --- a/brion/enums.h +++ b/brion/enums.h @@ -33,9 +33,10 @@ enum BlueConfigSection { CONFIGSECTION_RUN = 0, CONFIGSECTION_CONNECTION, + CONFIGSECTION_PROJECTION, + CONFIGSECTION_REPORT, CONFIGSECTION_STIMULUS, CONFIGSECTION_STIMULUSINJECT, - CONFIGSECTION_REPORT, CONFIGSECTION_UNKNOWN, CONFIGSECTION_ALL //!< @internal must be last }; diff --git a/tests/blueConfig.cpp b/tests/blueConfig.cpp index 13ac41f..40e280b 100644 --- a/tests/blueConfig.cpp +++ b/tests/blueConfig.cpp @@ -25,7 +25,7 @@ #include #include -BOOST_AUTO_TEST_CASE(test_invalid_open) +BOOST_AUTO_TEST_CASE(invalid_open) { BOOST_CHECK_THROW(brion::BlueConfig("/bla"), std::runtime_error); BOOST_CHECK_THROW(brion::BlueConfig("bla"), std::runtime_error); @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(test_invalid_open) BOOST_CHECK_THROW(brion::BlueConfig(path.string()), std::runtime_error); } -BOOST_AUTO_TEST_CASE(test_verify_loaded_data) +BOOST_AUTO_TEST_CASE(verify_raw_data) { brion::BlueConfig config(bbp::test::getBlueconfig()); std::cout << config << std::endl; @@ -149,6 +149,30 @@ BOOST_AUTO_TEST_CASE(test_verify_loaded_data) 99.f); } +BOOST_AUTO_TEST_CASE(projection_section) +{ + brion::BlueConfig config(bbp::test::getCircuitconfig()); + std::cout << config << std::endl; + + const std::string prefix(BBP_TESTDATA); + const brion::Strings& projections = + config.getSectionNames(brion::CONFIGSECTION_PROJECTION); + + BOOST_REQUIRE(projections.size() == 1); + BOOST_CHECK_EQUAL(projections[0], "Thalamocortical_fake_input"); + + const std::string path = prefix + + "/circuitBuilding_1000neurons/MesoBuilder_output/" + "merged_circuit/ncsThalamocortical_L4_tcS2F_3p0"; + + BOOST_CHECK_EQUAL(config.get(brion::CONFIGSECTION_PROJECTION, + "Thalamocortical_fake_input", "Path"), + path); + + BOOST_CHECK_EQUAL(config.getProjectionSource("Thalamocortical_fake_input"), + brion::URI(path)); +} + BOOST_AUTO_TEST_CASE(semantic_api) { const std::string prefix(BBP_TESTDATA); From 96c955bf28d1334c65515fb8bd51c9c41f64f578 Mon Sep 17 00:00:00 2001 From: Juan Hernando Vieites Date: Tue, 25 Apr 2017 19:14:14 +0200 Subject: [PATCH 2/2] Implemented Circuit::getAfferentProjections This function gives access to synape data for afferent projections external to the circuit. --- brain/circuit.cpp | 7 ++++ brain/circuit.h | 21 +++++++++++ brain/detail/circuit.h | 37 ++++++++++++++++++ brain/detail/synapsesStream.h | 25 ++++++++++++- brain/python/circuit.cpp | 13 +++++++ brain/synapses.cpp | 87 +++++++++++++++++++++++++++++++++++++------ brain/synapses.h | 2 + brain/synapsesStream.cpp | 7 ++++ brain/synapsesStream.h | 3 ++ brion/blueConfig.h | 2 +- doc/Changelog.md | 4 ++ tests/brain/synapses.cpp | 44 ++++++++++++++++++++++ 12 files changed, 238 insertions(+), 14 deletions(-) diff --git a/brain/circuit.cpp b/brain/circuit.cpp index 1e40e56..295d158 100644 --- a/brain/circuit.cpp +++ b/brain/circuit.cpp @@ -207,6 +207,13 @@ SynapsesStream Circuit::getAfferentSynapses( return SynapsesStream(*this, gids, true, prefetch); } +SynapsesStream Circuit::getExternalAfferentSynapses( + const GIDSet& gids, const std::string& source, + const SynapsePrefetch prefetch) const +{ + return SynapsesStream(*this, gids, source, prefetch); +} + SynapsesStream Circuit::getEfferentSynapses( const GIDSet& gids, const SynapsePrefetch prefetch) const { diff --git a/brain/circuit.h b/brain/circuit.h index 69cb0ee..4c6352a 100644 --- a/brain/circuit.h +++ b/brain/circuit.h @@ -157,6 +157,27 @@ class Circuit SynapsePrefetch prefetch = SynapsePrefetch::none) const; /** + * Access all afferent synapses projected from another circuit into the + * given GIDs. + * + * @param gids the gids of the post-synaptic cells + * @param source the name of the projecting circuit. This corresponds + * to the label of a Projection section in the CircuitConfig. + * If the source doesn't exist an exception will be thrown by the + * first operation that tries to access the data. + * \if pybind + * @param prefetch which synapse data to preload + * \else + * @param prefetch which synapse data to load on SynapsesStream.read() + * @return synapse data stream. The pre-synaptic GIDs in the synapses refer + * to cells in the projecting circuit. + * \endif + */ + BRAIN_API SynapsesStream getExternalAfferentSynapses( + const GIDSet& gids, const std::string& source, + SynapsePrefetch prefetch = SynapsePrefetch::none) const; + + /** * Access all efferent synapses of the given GIDs. * * @param gids the gids to load efferent synapses for diff --git a/brain/detail/circuit.h b/brain/detail/circuit.h index 8bd7346..bab1041 100644 --- a/brain/detail/circuit.h +++ b/brain/detail/circuit.h @@ -53,6 +53,7 @@ namespace brain { const std::string summaryFilename("/nrn_summary.h5"); const std::string afferentFilename("/nrn.h5"); +const std::string externalAfferentFilename("/proj_nrn.h5"); const std::string efferentFilename("/nrn_efferent.h5"); const std::string afferentPositionsFilename("/nrn_positions.h5"); const std::string efferentPositionsFilename("/nrn_positions_efferent.h5"); @@ -156,6 +157,12 @@ class Circuit::Impl , _cache(keyv::Map::createCache()) , _synapsePositionColumns(0) { + for (auto&& projection : + config.getSectionNames(brion::CONFIGSECTION_PROJECTION)) + { + _afferentProjectionSources[projection] = + config.getProjectionSource(projection); + } } virtual ~Impl() {} @@ -243,6 +250,32 @@ class Circuit::Impl return **_synapseAttributes[i]; } + const brion::Synapse& getAfferentProjectionAttributes( + const std::string& name) const + { + auto& lockable = _externalAfferents[name]; + lunchbox::ScopedWrite mutex(lockable); + auto& synapses = *lockable; + if (!synapses) + { + auto&& source = _afferentProjectionSources.find(name); + if (source == _afferentProjectionSources.end()) + { + _externalAfferents.erase(name); + LBTHROW(std::runtime_error( + "Afferent synaptic projection not found: " + name)); + } + fs::path path(source->second.getPath() + externalAfferentFilename); + if (fs::is_regular_file(path) || fs::is_symlink(path)) + synapses.reset(new brion::Synapse(path.string())); + else + // Trying with the afferent synapses filename as a fallback + synapses.reset(new brion::Synapse(source->second.getPath() + + afferentFilename)); + } + return *synapses; + } + const brion::Synapse* getSynapseExtra() const { lunchbox::ScopedWrite mutex(_synapseExtra); @@ -401,6 +434,7 @@ class Circuit::Impl const brion::URI _circuitSource; const brion::URI _morphologySource; const brion::URI _synapseSource; + std::unordered_map _afferentProjectionSources; const brion::URIs _targetSources; mutable brion::Targets _targetParsers; mutable keyv::MapPtr _cache; @@ -413,6 +447,9 @@ class Circuit::Impl mutable LockPtr _synapseExtra; mutable LockPtr _synapsePositions[2]; mutable size_t _synapsePositionColumns; + + mutable std::unordered_map> + _externalAfferents; }; class MVD2 : public Circuit::Impl diff --git a/brain/detail/synapsesStream.h b/brain/detail/synapsesStream.h index d28e729..7990a16 100644 --- a/brain/detail/synapsesStream.h +++ b/brain/detail/synapsesStream.h @@ -51,10 +51,23 @@ struct SynapsesStream { } + SynapsesStream(const Circuit& circuit, const GIDSet& gids, + const std::string& source, const SynapsePrefetch prefetch) + : _circuit(circuit) + , _afferent(true) + , _gids(gids) + , _externalSource(source) + , _prefetch(prefetch) + , _it(_gids.begin()) + { + } + const Circuit& _circuit; const bool _afferent; const GIDSet _gids; const GIDSet _filterGIDs; + // Source name for external afferent projections + const std::string _externalSource; const SynapsePrefetch _prefetch; GIDSet::const_iterator _it; @@ -69,9 +82,17 @@ struct SynapsesStream GIDSet::const_iterator start = _it; std::advance(_it, count); GIDSet::const_iterator end = _it; + + if (_externalSource.empty()) + { + return std::async(std::launch::async, [&, start, end] { + return Synapses(_circuit, GIDSet(start, end), _filterGIDs, + _afferent, _prefetch); + }); + } return std::async(std::launch::async, [&, start, end] { - return Synapses(_circuit, GIDSet(start, end), _filterGIDs, - _afferent, _prefetch); + return Synapses(_circuit, GIDSet(start, end), _externalSource, + _prefetch); }); } }; diff --git a/brain/python/circuit.cpp b/brain/python/circuit.cpp index c6d616b..20065cf 100644 --- a/brain/python/circuit.cpp +++ b/brain/python/circuit.cpp @@ -171,6 +171,15 @@ SynapsesWrapper Circuit_getAfferentSynapses( circuit); } +SynapsesWrapper Circuit_getExternalAfferentSynapses( + const CircuitPtr& circuit, bp::object gids, const std::string& source, + const brain::SynapsePrefetch prefetch) +{ + return SynapsesWrapper(circuit->getExternalAfferentSynapses( + gidsFromPython(gids), source, prefetch), + circuit); +} + SynapsesWrapper Circuit_getEfferentSynapses( const CircuitPtr& circuit, bp::object gids, const brain::SynapsePrefetch prefetch) @@ -249,6 +258,10 @@ circuitWrapper (selfarg, bp::arg("gids"), bp::arg("prefetch") = SynapsePrefetch::none), DOXY_FN(brain::Circuit::getAfferentSynapses)) + .def("external_afferent_synapses", Circuit_getExternalAfferentSynapses, + (selfarg, bp::arg("gids"), bp::arg("source"), + bp::arg("prefetch") = SynapsePrefetch::none), + DOXY_FN(brain::Circuit::getExternalAfferentSynapses)) .def("efferent_synapses", Circuit_getEfferentSynapses, (selfarg, bp::arg("gids"), bp::arg("prefetch") = SynapsePrefetch::none), diff --git a/brain/synapses.cpp b/brain/synapses.cpp index d21cc9e..0ad57da 100644 --- a/brain/synapses.cpp +++ b/brain/synapses.cpp @@ -80,6 +80,22 @@ struct Synapses::Impl : public Synapses::BaseImpl _loadPositions(gids, filterGIDs); } + Impl(const Circuit& circuit, const GIDSet& gids, const std::string& source, + const SynapsePrefetch prefetch) + : _circuit(circuit) + , _gids(prefetch != SynapsePrefetch::all ? gids : GIDSet()) + , _afferent(true) + , _externalSource(source) + , _size(0) + { + if (prefetch == SynapsePrefetch::none) + // We don't have a summary file for projected afferent synapses. + return; + + if (int(prefetch) & int(SynapsePrefetch::attributes)) + _loadAttributes(gids, GIDSet()); + } + #define FILTER(gid) \ if (!filterGIDs.empty() && filterGIDs.find(gid) == filterGIDs.end()) \ continue; @@ -123,14 +139,19 @@ struct Synapses::Impl : public Synapses::BaseImpl return; const brion::Synapse& synapseAttributes = - _circuit._impl->getSynapseAttributes(_afferent); - const brion::Synapse* synapseExtra = _circuit._impl->getSynapseExtra(); + _externalSource.empty() + ? _circuit._impl->getSynapseAttributes(_afferent) + : _circuit._impl->getAfferentProjectionAttributes( + _externalSource); + const brion::Synapse* synapseExtra = + _externalSource.empty() ? _circuit._impl->getSynapseExtra() : 0; const bool haveExtra = _afferent && synapseExtra; const bool haveSize = _size > 0; _allocateAttributes(haveSize ? _size : synapseAttributes.getNumSynapses(gids), haveExtra); + const bool haveGIDs = _externalSource.empty() && haveSize; size_t i = 0; for (const auto gid : gids) @@ -144,7 +165,7 @@ struct Synapses::Impl : public Synapses::BaseImpl const uint32_t preGid = attr[j][0]; FILTER(preGid); - if (!haveSize) + if (!haveGIDs) { _preGID.get()[i] = preGid; _postGID.get()[i] = gid; @@ -180,6 +201,13 @@ struct Synapses::Impl : public Synapses::BaseImpl void _loadPositions(const GIDSet& gids, const GIDSet& filterGIDs) const { + if (!_externalSource.empty()) + { + LBTHROW( + std::runtime_error("Synapse positions are not available " + "for external projection synapses")); + } + if (_preCenterPositionX) return; @@ -353,6 +381,17 @@ struct Synapses::Impl : public Synapses::BaseImpl _allocate(_postCenterPositionZ, size); } + void _ensureGIDs() const + { + if (_externalSource.empty() || _hasAttributes()) + return; + + lunchbox::ScopedWrite mutex(_lock); + // For external projections we don't have a summary file, so we load + // all the attributes instead. + _loadAttributes(_gids, _filterGIDs); + } + void _ensureAttributes() const { if (_hasAttributes()) @@ -383,10 +422,25 @@ struct Synapses::Impl : public Synapses::BaseImpl return _preCenterPositionX.get() != nullptr; } + size_t _getSize() const + { + lunchbox::ScopedRead mutex(_lock); + + if (!_externalSource.empty() && _size == 0) + { + const brion::Synapse& attributes = + _circuit._impl->getAfferentProjectionAttributes( + _externalSource); + _size = attributes.getNumSynapses(_gids); + } + return _size; + } + const Circuit& _circuit; const GIDSet _gids; const GIDSet _filterGIDs; const bool _afferent; + std::string _externalSource; template struct FreeDeleter @@ -436,10 +490,16 @@ struct Synapses::Impl : public Synapses::BaseImpl mutable std::mutex _lock; }; -Synapses::Synapses(const Circuit& circuit, const GIDSet& pre, - const GIDSet& post, const bool afferent, +Synapses::Synapses(const Circuit& circuit, const GIDSet& gids, + const GIDSet& filterGIDs, const bool afferent, const SynapsePrefetch prefetch) - : _impl(new Impl(circuit, pre, post, afferent, prefetch)) + : _impl(new Impl(circuit, gids, filterGIDs, afferent, prefetch)) +{ +} + +Synapses::Synapses(const Circuit& circuit, const GIDSet& gids, + const std::string& source, const SynapsePrefetch prefetch) + : _impl(new Impl(circuit, gids, source, prefetch)) { } @@ -448,9 +508,13 @@ Synapses::~Synapses() } Synapses::Synapses(const SynapsesStream& stream) - : _impl(new Impl(stream._impl->_circuit, stream._impl->_gids, - stream._impl->_filterGIDs, stream._impl->_afferent, - stream._impl->_prefetch)) + : _impl(stream._impl->_externalSource.empty() + ? new Impl(stream._impl->_circuit, stream._impl->_gids, + stream._impl->_filterGIDs, stream._impl->_afferent, + stream._impl->_prefetch) + : new Impl(stream._impl->_circuit, stream._impl->_gids, + stream._impl->_externalSource, + stream._impl->_prefetch)) { } @@ -481,8 +545,7 @@ Synapses& Synapses::operator=(Synapses&& rhs) size_t Synapses::size() const { const Impl& impl = static_cast(*_impl); - lunchbox::ScopedRead mutex(impl._lock); - return impl._size; + return impl._getSize(); } bool Synapses::empty() const @@ -517,6 +580,7 @@ const size_t* Synapses::indices() const const uint32_t* Synapses::preGIDs() const { const Impl& impl = static_cast(*_impl); + impl._ensureGIDs(); return impl._preGID.get(); } @@ -586,6 +650,7 @@ const float* Synapses::preCenterZPositions() const const uint32_t* Synapses::postGIDs() const { const Impl& impl = static_cast(*_impl); + impl._ensureGIDs(); return impl._postGID.get(); } diff --git a/brain/synapses.h b/brain/synapses.h index 11e5404..2db2beb 100644 --- a/brain/synapses.h +++ b/brain/synapses.h @@ -226,6 +226,8 @@ class Synapses friend struct detail::SynapsesStream; Synapses(const Circuit& circuit, const GIDSet& gids, const GIDSet& filterGIDs, bool afferent, SynapsePrefetch prefetch); + Synapses(const Circuit& circuit, const GIDSet& gids, + const std::string& source, SynapsePrefetch prefetch); }; } diff --git a/brain/synapsesStream.cpp b/brain/synapsesStream.cpp index 0c18509..8bcfc15 100644 --- a/brain/synapsesStream.cpp +++ b/brain/synapsesStream.cpp @@ -39,6 +39,13 @@ SynapsesStream::SynapsesStream(const Circuit& circuit, const GIDSet& preGIDs, { } +SynapsesStream::SynapsesStream(const Circuit& circuit, const GIDSet& gids, + const std::string& source, + const SynapsePrefetch prefetch) + : _impl(new detail::SynapsesStream(circuit, gids, source, prefetch)) +{ +} + SynapsesStream::~SynapsesStream() { } diff --git a/brain/synapsesStream.h b/brain/synapsesStream.h index 583a033..fbc6e47 100644 --- a/brain/synapsesStream.h +++ b/brain/synapsesStream.h @@ -74,6 +74,9 @@ class SynapsesStream SynapsePrefetch prefetch); SynapsesStream(const Circuit& circuit, const GIDSet& preGIDs, const GIDSet& postGIDs, SynapsePrefetch prefetch); + // Constructor for afferent external projections + SynapsesStream(const Circuit& circuit, const GIDSet& gids, + const std::string& source, SynapsePrefetch prefetch); friend class Synapses; std::unique_ptr _impl; diff --git a/brion/blueConfig.h b/brion/blueConfig.h index a920f01..27b7162 100644 --- a/brion/blueConfig.h +++ b/brion/blueConfig.h @@ -124,7 +124,7 @@ class BlueConfig : public boost::noncopyable /** * @return the full path to the morphology database. A suffix may be - * prepended to the to the bare path from the BlueConfig. + * prepended to the bare path from the BlueConfig. * @version 1.7 */ BRION_API URI getMorphologySource() const; diff --git a/doc/Changelog.md b/doc/Changelog.md index b1967d2..2a7176c 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,10 @@ Changelog {#Changelog} # git master +* [150](https://github.com/BlueBrain/Brion/pull/150): + - Added a new method in brain::Circuit to obtain synapses for afferent + projections from outside the circuit (e.g. thalamocortical projections). + - Support for Projections sections in brion::BlueConfig * [141](https://github.com/BlueBrain/Brion/pull/141): Fixed documentation to specify that morphology section samples report diameters and not radii. diff --git a/tests/brain/synapses.cpp b/tests/brain/synapses.cpp index 1830adf..e217f63 100644 --- a/tests/brain/synapses.cpp +++ b/tests/brain/synapses.cpp @@ -93,6 +93,31 @@ BOOST_AUTO_TEST_CASE(afferent_synapses) BOOST_CHECK_THROW(synapses[3].getGID(), std::runtime_error); } +BOOST_AUTO_TEST_CASE(bad_external_afferent_synapses) +{ + const brain::Circuit circuit(brion::URI(BBP_TEST_CIRCUITCONFIG)); + const brain::Synapses& bad = + circuit.getExternalAfferentSynapses({1}, "Unexistent"); + BOOST_CHECK_THROW(bad.size(), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(external_afferent_synapses) +{ + const brain::Circuit circuit(brion::URI(BBP_TEST_CIRCUITCONFIG)); + + const std::string label("Thalamocortical_fake_input"); + const brain::Synapses& synapses = + circuit.getExternalAfferentSynapses(circuit.getGIDs("Layer1"), label, + brain::SynapsePrefetch::all); + BOOST_CHECK_EQUAL(synapses.size(), 1172); + BOOST_CHECK_EQUAL(synapses[0].getPresynapticGID(), 10); + BOOST_CHECK_CLOSE(synapses[1].getPostsynapticDistance(), 1.34995711f, + 0.00001f); + BOOST_CHECK_CLOSE(synapses[2].getConductance(), 0.34758395f, 0.00001f); + // Positions never available for these datasets + BOOST_CHECK_THROW(synapses.preSurfaceXPositions(), std::runtime_error); +} + BOOST_AUTO_TEST_CASE(efferent_synapses) { const brain::Circuit circuit(brion::URI(BBP_TEST_BLUECONFIG3)); @@ -141,6 +166,25 @@ BOOST_AUTO_TEST_CASE(lazy_loading_afferent) synapsesLazy[0].getPostsynapticCenterPosition()); } +BOOST_AUTO_TEST_CASE(lazy_loading_external_afferent_synapses) +{ + const brain::Circuit circuit(brion::URI(BBP_TEST_CIRCUITCONFIG)); + + const std::string label("Thalamocortical_fake_input"); + const brain::Synapses& synapses = + circuit.getExternalAfferentSynapses(circuit.getGIDs("Layer1"), label, + brain::SynapsePrefetch::all); + const brain::Synapses& synapsesLazy = + circuit.getExternalAfferentSynapses(circuit.getGIDs("Layer1"), label); + BOOST_CHECK_EQUAL(synapses.size(), synapsesLazy.size()); + for (auto s1 = synapses.begin(), s2 = synapsesLazy.begin(); + s1 != synapses.end(); ++s1, ++s2) + { + BOOST_CHECK_EQUAL((*s1).getPresynapticGID(), (*s2).getPresynapticGID()); + BOOST_CHECK_EQUAL((*s1).getConductance(), (*s2).getConductance()); + } +} + BOOST_AUTO_TEST_CASE(lazy_loading_efferent) { const brain::Circuit circuit(brion::URI(BBP_TEST_BLUECONFIG3));