diff --git a/.gitsubprojects b/.gitsubprojects index c6957b6..9bcd6c2 100644 --- a/.gitsubprojects +++ b/.gitsubprojects @@ -1,4 +1,5 @@ # -*- mode: cmake -*- git_subproject(Servus https://github.com/HBPVIS/Servus.git 567f038) git_subproject(Lunchbox https://github.com/Eyescale/Lunchbox.git b41edcf) -git_subproject(vmmlib https://github.com/Eyescale/vmmlib.git b41e1a5) +git_subproject(vmmlib https://github.com/Eyescale/vmmlib.git 891fce2) +git_subproject(MVDTool https://github.com/BlueBrain/MVDTool.git 7801ae2) diff --git a/brain/CMakeLists.txt b/brain/CMakeLists.txt index 848a701..839b900 100644 --- a/brain/CMakeLists.txt +++ b/brain/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2015, EPFL/Blue Brain Project +# Copyright (c) 2013-2016, EPFL/Blue Brain Project # Juan Hernando # # This file is part of Brion @@ -31,4 +31,10 @@ set(BRAIN_LINK_LIBRARIES PUBLIC Brion vmmlib) set(BRAIN_INCLUDE_NAME brain) set(BRAIN_NAMESPACE brain) +if(TARGET MVDTool) + list(APPEND BRAIN_LINK_LIBRARIES MVDTool) +endif() common_library(Brain) +if(TARGET MVDTool) + target_compile_definitions(Brain PUBLIC BRAIN_USE_MVD3) +endif() diff --git a/brain/circuit.cpp b/brain/circuit.cpp index fa75ab0..254661f 100644 --- a/brain/circuit.cpp +++ b/brain/circuit.cpp @@ -1,5 +1,8 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Juan Hernando + * Adrien.Devresse@epfl.ch + * Daniel.Nachbaur@epfl.ch + * Stefan.Eilemann@epfl.ch * * This file is part of Brion * @@ -27,21 +30,78 @@ #include +#ifdef BRAIN_USE_MVD3 +# include +# include +#endif + #include +using boost::lexical_cast; + namespace brain { +namespace +{ +#ifdef BRAIN_USE_MVD3 +bool isSequence( const GIDSet& gids ) +{ + return ( *gids.rbegin() - *gids.begin() + 1 ) == gids.size(); +} + +::MVD3::Range getRange( const GIDSet& gids ) +{ + const size_t offset = ( *gids.begin( )); + const size_t count = *gids.rbegin() - offset + 1; + return ::MVD3::Range( offset - 1, count ); +} + +template< typename SrcArray, typename DstArray, typename AssignOp > +void assign( const ::MVD3::Range& range, const GIDSet& gids, + SrcArray& src, DstArray& dst, const AssignOp& assignOp ) +{ + if( isSequence( gids )) // OPT: no holes, no translation needed + { + std::transform( src.begin(), src.end(), dst.begin(), assignOp ); + return; + } + + typename DstArray::iterator dst_it = dst.begin(); + for( GIDSet::const_iterator i = gids.begin(); i != gids.end(); ++i ) + { + typename SrcArray::const_iterator src_it = src.begin(); + std::advance( src_it, *i - range.offset - 1 ); + *dst_it = assignOp( *src_it ); + ++dst_it; + } +} + +Vector3f toVector3f( + const ::MVD3::Positions::const_subarray< 1 >::type& subarray ) +{ + return Vector3f( subarray[0], subarray[1], subarray[2] ); +} + +Quaternionf toQuaternion( + const ::MVD3::Rotations::const_subarray< 1 >::type& subarray ) +{ + return Quaternionf( subarray[0], subarray[1], subarray[2], subarray[3] ); +} +#endif + +std::string toString( const std::string& in ) { return in; } +} + class Circuit::Impl { public: Impl( const brion::BlueConfig& config ) - : _circuit( config.getCircuitSource( )) - , _morphologySource( config.getMorphologySource( )) + : _morphologySource( config.getMorphologySource( )) , _circuitTarget( config.getCircuitTarget( )) , _targetParsers( config.getTargets( )) - { - } + {} + virtual ~Impl() {} GIDSet getGIDs( const std::string& target ) const { @@ -49,10 +109,9 @@ class Circuit::Impl _targetParsers, target.empty() ? _circuitTarget : target ); } - const brion::Circuit& getCircuit() const - { - return _circuit; - } + virtual Vector3fs getPositions( const GIDSet& gids ) const = 0; + virtual Quaternionfs getRotations( const GIDSet& gids ) const = 0; + virtual Strings getMorphologyNames( const GIDSet& gids ) const = 0; URI getMorphologyURI( const std::string& name ) const { @@ -63,20 +122,150 @@ class Circuit::Impl } private: - const brion::Circuit _circuit; const brion::URI _morphologySource; const std::string _circuitTarget; const brion::Targets _targetParsers; +}; + +class MVD2 : public Circuit::Impl +{ +public: + MVD2( const brion::BlueConfig& config ) + : Impl( config ) + , _circuit( config.getCircuitSource().getPath( )) + {} + + Vector3fs getPositions( const GIDSet& gids ) const final + { + const brion::NeuronMatrix& data = _circuit.get( gids, + brion::NEURON_POSITION_X | brion::NEURON_POSITION_Y | + brion::NEURON_POSITION_Z ); + + Vector3fs positions( gids.size( )); +#pragma omp parallel for + for( size_t i = 0; i < gids.size(); ++i ) + { + try + { + positions[i] = + brion::Vector3f( lexical_cast< float >( data[i][0] ), + lexical_cast< float >( data[i][1] ), + lexical_cast< float >( data[i][2] )); + } + catch( const boost::bad_lexical_cast& ) + { + GIDSet::const_iterator gid = gids.begin(); + std::advance( gid, i ); + LBWARN << "Error parsing circuit position for gid " + << *gid << std::endl; + } + } + return positions; + } + + Quaternionfs getRotations( const GIDSet& gids ) const final + { + const float deg2rad = float( M_PI ) / 180.f; + const brion::NeuronMatrix& data = + _circuit.get( gids, brion::NEURON_ROTATION ); + Quaternionfs rotations( gids.size( )); + +#pragma omp parallel for + for( size_t i = 0; i < gids.size(); ++i ) + { + try + { + // transform rotation Y angle in degree into rotation quaternion + const float angle = lexical_cast( data[i][0] ) * deg2rad; + rotations[i] = Quaternionf( angle, Vector3f( 0, 1, 0 )); + } + catch( const boost::bad_lexical_cast& ) + { + GIDSet::const_iterator gid = gids.begin(); + std::advance( gid, i ); + LBWARN << "Error parsing circuit orientation for gid " + << *gid << std::endl; + } + } + return rotations; + } + + Strings getMorphologyNames( const GIDSet& gids ) const final + { + brion::NeuronMatrix matrix = + _circuit.get( gids, brion::NEURON_MORPHOLOGY_NAME ); + Strings res( matrix.shape()[ 0 ]); + + brion::NeuronMatrix::array_view<1>::type view = + matrix[ boost::indices[brion::NeuronMatrix::index_range( )][ 0 ]]; + std::transform( view.begin(), view.end(), res.begin(), toString ); + return res; + } + +private: + brion::Circuit _circuit; +}; + +#ifdef BRAIN_USE_MVD3 +class MVD3 : public Circuit::Impl +{ +public: + MVD3( const brion::BlueConfig& config ) + : Impl( config ) + , _circuit( config.getCircuitSource().getPath( )) + {} + + Vector3fs getPositions( const GIDSet& gids ) const final + { + Vector3fs results( gids.size( )); + const ::MVD3::Range& range = getRange( gids ); + const ::MVD3::Positions& positions = _circuit.getPositions( range ); + assign( range, gids, positions, results, toVector3f ); + return results; + } + + Quaternionfs getRotations( const GIDSet& gids ) const final + { + Quaternionfs results( gids.size( )); + const ::MVD3::Range& range = getRange( gids ); + const ::MVD3::Rotations& rotations = _circuit.getRotations( range ); + assign( range, gids, rotations, results, toQuaternion ); + return results; + } + + Strings getMorphologyNames( const GIDSet& gids ) const final + { + Strings results( gids.size( )); + const ::MVD3::Range& range = getRange( gids ); + const Strings& morphos = _circuit.getMorphologies( range ); + assign( range, gids, morphos, results, toString ); + return results; + } +private: + ::MVD3::MVD3File _circuit; }; +#endif + +Circuit::Impl* newImpl( const brion::BlueConfig& config ) +{ + const std::string circuit = config.getCircuitSource().getPath(); + if( boost::algorithm::ends_with( circuit, ".mvd2" )) + return new MVD2( config ); +#ifdef BRAIN_USE_MVD3 + return new MVD3( config ); +#else + throw std::runtime_error( "MVD3 support requires CMake 3" ); +#endif +} Circuit::Circuit( const URI& source ) - : _impl( new Impl( brion::BlueConfig( source.getPath( )))) + : _impl( newImpl( brion::BlueConfig( source.getPath( )))) { } Circuit::Circuit( const brion::BlueConfig& config ) - : _impl( new Impl( config )) + : _impl( newImpl( config )) { } @@ -92,18 +281,17 @@ GIDSet Circuit::getGIDs( const std::string& target ) const URIs Circuit::getMorphologyURIs( const GIDSet& gids ) const { - const brion::NeuronMatrix& matrix = - _impl->getCircuit().get( gids, brion::NEURON_MORPHOLOGY_NAME ); + const Strings& names = _impl->getMorphologyNames( gids ); URIs uris; - uris.reserve( gids.size( )); - for( size_t index = 0; index != gids.size(); ++index ) - uris.push_back( _impl->getMorphologyURI( matrix[index][0] )); + uris.reserve( names.size( )); + for( Strings::const_iterator i = names.begin(); i < names.end(); ++i ) + uris.push_back( _impl->getMorphologyURI( *i )); return uris; } neuron::Morphologies Circuit::loadMorphologies( const GIDSet& gids, - const Coordinates coords ) const + const Coordinates coords ) const { const URIs& uris = getMorphologyURIs( gids ); neuron::Morphologies result; @@ -141,65 +329,25 @@ neuron::Morphologies Circuit::loadMorphologies( const GIDSet& gids, Vector3fs Circuit::getPositions( const GIDSet& gids ) const { - const brion::NeuronMatrix& data = _impl->getCircuit().get( - gids, brion::NEURON_POSITION_X | brion::NEURON_POSITION_Y | - brion::NEURON_POSITION_Z ); - - brion::GIDSet::const_iterator gid = gids.begin(); - Vector3fs positions( gids.size( )); - #pragma omp parallel for - for( size_t i = 0; i < gids.size(); ++i ) - { - try - { - positions[i] = - brion::Vector3f( boost::lexical_cast< float >( data[i][0] ), - boost::lexical_cast< float >( data[i][1] ), - boost::lexical_cast< float >( data[i][2] )); - } - catch( const boost::bad_lexical_cast& ) - { - LBWARN << "Error parsing circuit position or orientation for gid " - << *gid << ". Morphology not transformed." << std::endl; - positions[i] = Vector3f::ZERO; - } - #pragma omp critical (brain_circuit_getPositions) - ++gid; - } - return positions; + return _impl->getPositions( gids ); } Matrix4fs Circuit::getTransforms( const GIDSet& gids ) const { - const brion::NeuronMatrix& data = _impl->getCircuit().get( - gids, brion::NEURON_POSITION_X | brion::NEURON_POSITION_Y | - brion::NEURON_POSITION_Z | brion::NEURON_ROTATION ); + const Vector3fs& positions = _impl->getPositions( gids ); + const Quaternionfs& rotations = _impl->getRotations( gids ); + if( positions.size() != rotations.size( )) + throw std::runtime_error( + "Positions not equal rotations for given GIDs" ); - brion::GIDSet::const_iterator gid = gids.begin(); - Matrix4fs transforms( gids.size(), Matrix4f::IDENTITY ); - #pragma omp parallel for - for( size_t i = 0; i < gids.size(); ++i ) - { - Matrix4f& matrix = transforms[i]; - try - { - matrix.rotate_y( - boost::lexical_cast< float >( data[i][3] ) * ( M_PI/180.0f )); - matrix.set_translation( - Vector3f( boost::lexical_cast< float >( data[i][0] ), - boost::lexical_cast< float >( data[i][1] ), - boost::lexical_cast< float >( data[i][2] ))); - } - catch( const boost::bad_lexical_cast& ) - { - LBWARN << "Error parsing circuit position or orientation for gid " - << *gid << ". Morphology not transformed." << std::endl; - matrix = Matrix4f::IDENTITY; - } - #pragma omp critical (brain_circuit_getTransforms) - ++gid; - } + Matrix4fs transforms( positions.size( )); + +#pragma omp parallel for + for( size_t i = 0; i < positions.size(); ++i ) + transforms[i] = Matrix4f( rotations[i], positions[i] ); return transforms; + } + } diff --git a/brain/circuit.h b/brain/circuit.h index 97f682f..73e5082 100644 --- a/brain/circuit.h +++ b/brain/circuit.h @@ -1,5 +1,6 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Juan Hernando + * Adrien.Devresse@epfl.ch * * This file is part of Brion * @@ -23,6 +24,7 @@ #include #include +#include // return value #include namespace brain @@ -59,10 +61,10 @@ class Circuit : public boost::noncopyable /** * @return The set of GIDs for the given target name. If empty it will - * return the circuit target specified on the - * BlueConfig/CircuitConfig file. - * If the target cannot be found or an empty string was given and - * there is no circuit target, the return value is an empty set. + * return the circuit target specified on the BlueConfig or + * CircuitConfig file. If the target cannot be found or an empty + * string was given and there is no circuit target, the return value + * is an empty set. */ BRAIN_API GIDSet getGIDs( const std::string& target = "" ) const; @@ -83,8 +85,9 @@ class Circuit : public boost::noncopyable /** @return The local to world transformations of the given cells. */ BRAIN_API Matrix4fs getTransforms( const GIDSet& gids ) const; + class Impl; //!< @internal + private: - class Impl; Impl* _impl; }; diff --git a/brain/neuron/morphologyImpl.h b/brain/neuron/morphologyImpl.h index 3a7fd38..fa558a5 100644 --- a/brain/neuron/morphologyImpl.h +++ b/brain/neuron/morphologyImpl.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Juan Hernando * * This file is part of Brion @@ -25,6 +25,7 @@ #include #include +#include namespace brain { diff --git a/brain/types.h b/brain/types.h index 63b2740..4722275 100644 --- a/brain/types.h +++ b/brain/types.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Juan Hernando * * This file is part of Brion @@ -30,21 +30,24 @@ using namespace brion::enums; class Circuit; +using vmml::Matrix4f; +using vmml::Quaternionf; using vmml::Vector2i; using vmml::Vector3f; using vmml::Vector4f; -using vmml::Matrix4f; +using brion::GIDSet; +using brion::SectionTypes; +using brion::Strings; +using brion::URI; using brion::Vector2is; using brion::Vector3fs; using brion::Vector4fs; -typedef std::vector< Matrix4f > Matrix4fs; -using brion::uint32_ts; using brion::floats; +using brion::uint32_ts; -using brion::SectionTypes; -using brion::GIDSet; -using brion::URI; +typedef std::vector< Matrix4f > Matrix4fs; +typedef std::vector< Quaternionf > Quaternionfs; typedef std::vector< URI > URIs; namespace neuron @@ -60,4 +63,3 @@ namespace neuron } #endif - diff --git a/brion/blueConfig.cpp b/brion/blueConfig.cpp index 718c410..a977230 100644 --- a/brion/blueConfig.cpp +++ b/brion/blueConfig.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Daniel Nachbaur * * This file is part of Brion @@ -28,6 +28,7 @@ #include #include #include +#include namespace fs = boost::filesystem; namespace boost @@ -248,14 +249,18 @@ brion::Targets BlueConfig::getTargets() const URI BlueConfig::getCircuitSource() const { + const std::string& path = get( CONFIGSECTION_RUN, _impl->getRun(), + BLUECONFIG_CIRCUIT_PATH_KEY ); + const std::string filename = path + + ( fs::exists( fs::path( path ) / CIRCUIT_FILE_MVD3 ) ? + CIRCUIT_FILE_MVD3 : CIRCUIT_FILE_MVD2 ); + URI uri; - uri.setScheme("file"); - uri.setPath( get( CONFIGSECTION_RUN, _impl->getRun(), - BLUECONFIG_CIRCUIT_PATH_KEY ) + CIRCUIT_FILE ); + uri.setScheme( "file" ); + uri.setPath( filename ); return uri; } - URI BlueConfig::getSynapseSource() const { URI uri; diff --git a/brion/blueConfig.h b/brion/blueConfig.h index febbf34..b49c7df 100644 --- a/brion/blueConfig.h +++ b/brion/blueConfig.h @@ -102,7 +102,8 @@ class BlueConfig : public boost::noncopyable /** @name Semantic read API */ //@{ /** - * @return the URI to the circuit information. @sa Circuit + * @return the URI to the circuit information. + * @sa Circuit * @version 1.7 */ BRION_API URI getCircuitSource() const; diff --git a/brion/circuit.cpp b/brion/circuit.cpp index 6601ae1..da7e63a 100644 --- a/brion/circuit.cpp +++ b/brion/circuit.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Daniel Nachbaur * Juan Hernando * @@ -25,6 +25,7 @@ #include #include #include +#include namespace brion { diff --git a/brion/constants.h b/brion/constants.h index 2f42d35..c26c259 100644 --- a/brion/constants.h +++ b/brion/constants.h @@ -24,7 +24,8 @@ namespace brion { const char* const SPIKE_FILE = "/out.dat"; -const char* const CIRCUIT_FILE = "/circuit.mvd2"; +const char* const CIRCUIT_FILE_MVD2 = "/circuit.mvd2"; +const char* const CIRCUIT_FILE_MVD3 = "/circuit.mvd3"; const char* const CIRCUIT_TARGET_FILE = "/start.target"; const char* const MORPHOLOGY_HDF5_FILES_SUBDIRECTORY = "h5"; diff --git a/brion/detail/meshBinary.h b/brion/detail/meshBinary.h index e4d8bae..a28ac64 100644 --- a/brion/detail/meshBinary.h +++ b/brion/detail/meshBinary.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Daniel Nachbaur * * This file is part of Brion @@ -25,7 +25,8 @@ #include #include #include - +#include +#include namespace brion { diff --git a/brion/morphology.h b/brion/morphology.h index eaa7836..32d43e1 100644 --- a/brion/morphology.h +++ b/brion/morphology.h @@ -22,6 +22,7 @@ #include #include +#include // return value #include namespace brion diff --git a/brion/plugin/morphologySWC.cpp b/brion/plugin/morphologySWC.cpp index 27bb82d..e4844dc 100644 --- a/brion/plugin/morphologySWC.cpp +++ b/brion/plugin/morphologySWC.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Juan Hernando * * This file is part of Brion @@ -23,9 +23,9 @@ #include #include - -#include #include +#include +#include namespace brion { diff --git a/brion/plugin/spikeReportFile.cpp b/brion/plugin/spikeReportFile.cpp index e581c28..2f15cbf 100644 --- a/brion/plugin/spikeReportFile.cpp +++ b/brion/plugin/spikeReportFile.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Raphael Dumusc * * This file is part of Brion @@ -20,14 +20,14 @@ #include "spikeReportFile.h" #include "../detail/skipWhiteSpace.h" -#include -#include -#include #include #include - #include +#include +#include +#include #include +#include namespace brion { diff --git a/brion/target.cpp b/brion/target.cpp index 61c1ac6..1f4cbf3 100644 --- a/brion/target.cpp +++ b/brion/target.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, EPFL/Blue Brain Project +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project * Daniel Nachbaur * * This file is part of Brion @@ -19,11 +19,12 @@ #include "target.h" +#include +#include #include #include #include -#include -#include +#include namespace boost { diff --git a/brion/types.h b/brion/types.h index d32ef1b..4f6d30b 100644 --- a/brion/types.h +++ b/brion/types.h @@ -30,15 +30,9 @@ #include #include -#define VMMLIB_CUSTOM_CONFIG -#ifndef NDEBUG -# define VMMLIB_SAFE_ACCESSORS -#endif -#undef VMMLIB_ALIGN -#define VMMLIB_ALIGN( var ) var #pragma warning(push) #pragma warning(disable : 4996) -# include +# include #pragma warning(pop) /** @namespace brion Blue Brain File IO classes */ diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..135f318 --- /dev/null +++ b/default.nix @@ -0,0 +1,30 @@ +# Nix development environment +# +# build: +# nix-build -I "BBPpkgs=https://github.com/BlueBrain/bbp-nixpkgs/archive/master.tar.gz" default.nix +# +# build and test: +# nix-build -I "BBPpkgs=https://github.com/BlueBrain/bbp-nixpkgs/archive/master.tar.gz" --arg testExec true default.nix -j 4 +# +# dev shell: +# nix-shell -I "BBPpkgs=https://github.com/BlueBrain/bbp-nixpkgs/archive/master.tar.gz" default.nix +# +with import { }; + + +stdenv.mkDerivation rec { + name = "Brion-DEV"; + src = ./.; + buildInputs = [stdenv pkgconfig boost zlib cmake cmake-external hdf5-cpp servus lunchbox vmmlib mvdtool bbptestdata ]; + + + doCheck= true; + + checkPhase= '' + export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH; + ctest -E perf -V; + ''; + + +} + diff --git a/tests/circuit.cpp b/tests/circuit.cpp index 584ebfc..9aa46ec 100644 --- a/tests/circuit.cpp +++ b/tests/circuit.cpp @@ -70,7 +70,6 @@ BOOST_AUTO_TEST_CASE(test_all_attributes) const brion::NeuronMatrix& data = circuit.get( brion::GIDSet(), brion::NEURON_ALL_ATTRIBUTES ); - std::cout << data << std::endl; BOOST_CHECK_EQUAL( data.shape()[0], 10 ); // 10 neurons BOOST_CHECK_EQUAL( data.shape()[1], brion::NEURON_ALL ); @@ -95,7 +94,6 @@ BOOST_AUTO_TEST_CASE(test_some_attributes) gids.insert( 6 ); const brion::NeuronMatrix& data = circuit.get( gids, brion::NEURON_ETYPE | brion::NEURON_MORPHOLOGY_NAME ); - std::cout << data << std::endl; BOOST_CHECK_EQUAL( data.shape()[0], 2 ); // 2 neurons BOOST_CHECK_EQUAL( data.shape()[1], 2 ); // 2 attributes @@ -219,6 +217,8 @@ void _checkMorphology( const brain::neuron::Morphology& morphology, transform ); const brain::Vector4fs& p = morphology.getPoints(); const brain::Vector4fs& q = reference.getPoints(); + BOOST_CHECK( reference.getTransformation().equals( transform )); + BOOST_REQUIRE( p.size() == q.size( )); for( size_t i = 0; i != p.size(); ++i ) BOOST_CHECK_SMALL(( p[i] - q[i] ).length( ), 0.0001f); @@ -283,3 +283,89 @@ BOOST_AUTO_TEST_CASE( load_global_morphologies ) _checkMorphology( *morphologies[0], "R-C010306G.h5", matrix ); } + +#ifdef BRAIN_USE_MVD3 + +BOOST_AUTO_TEST_CASE(all_mvd3) +{ + brion::BlueConfig config(BBP_TEST_BLUECONFIG3); + brain::Circuit circuit(config); + BOOST_CHECK_EQUAL( circuit.getGIDs().size(), 1000 ); + + brain::Vector3fs positions = circuit.getPositions( circuit.getGIDs( )); + brain::Matrix4fs transforms = circuit.getTransforms( circuit.getGIDs( )); + BOOST_CHECK_EQUAL( positions.size(), 1000 ); + BOOST_CHECK_EQUAL( transforms.size(), 1000 ); + + BOOST_CHECK_SMALL( + ( positions[20] - brion::Vector3f( 30.1277100000, 1794.1259110000, 19.8605870000 )).length(), + 0.000001f ); + BOOST_CHECK_SMALL( + ( positions[100] - brion::Vector3f( 48.7579240000, 1824.4589930000, 15.3025840000 )).length(), + 0.000001f ); + + BOOST_CHECK( transforms[20].equals( + brain::Matrix4f( + brain::Quaternionf( 0.383102, 0, 0.923706, 0 ), + brain::Vector3f( 30.12771, 1794.125911, 19.860587 )), + 0.00001f )); + BOOST_CHECK( transforms[100].equals( + brain::Matrix4f( + brain::Quaternionf ( 0.120884, 0, -0.992667, 0 ), + brain::Vector3f( 48.757924, 1824.458993, 15.302584 )), + 0.00001f )); +} + +BOOST_AUTO_TEST_CASE(partial_mvd3) +{ + brion::BlueConfig config(BBP_TEST_BLUECONFIG3); + brain::Circuit circuit(config); + + brion::GIDSet gids; + gids.insert(6); + gids.insert(21); + gids.insert(101); + gids.insert(501); + + const brain::Vector3fs& positions = circuit.getPositions( gids ); + const brain::Matrix4fs& transforms = circuit.getTransforms( gids ); + BOOST_CHECK_EQUAL( positions.size(), 4 ); + BOOST_CHECK_EQUAL( transforms.size(), 4 ); + + BOOST_CHECK_SMALL( + ( positions[1] - brion::Vector3f( 30.1277100000, 1794.1259110000, 19.8605870000 )).length(), + 0.000001f ); + BOOST_CHECK_SMALL( + ( positions[2] - brion::Vector3f( 48.7579240000, 1824.4589930000, 15.3025840000 )).length(), + 0.000001f ); + + BOOST_CHECK( transforms[1].equals( + brain::Matrix4f( + brain::Quaternionf( 0.383102, 0, 0.923706, 0 ), + brain::Vector3f( 30.12771, 1794.125911, 19.860587 )), + 0.00001f )); + BOOST_CHECK( transforms[2].equals( + brain::Matrix4f( + brain::Quaternionf( 0.120884, 0, -0.992667, 0 ), + brain::Vector3f( 48.757924, 1824.458993, 15.302584 )), + 0.00001f )); +} + +BOOST_AUTO_TEST_CASE(morphology_names_mvd3) +{ + brion::BlueConfig config(BBP_TEST_BLUECONFIG3); + brain::Circuit circuit(config); + + brion::GIDSet gids; + gids.insert(21); + gids.insert(501); + + const brain::URIs& names = circuit.getMorphologyURIs( gids ); + BOOST_REQUIRE_EQUAL( names.size(), 2 ); + BOOST_CHECK( boost::algorithm::ends_with( std::to_string( names[0] ), + "dend-C280998A-P3_axon-sm110131a1-3_INT_idA.h5" )); + BOOST_CHECK( boost::algorithm::ends_with( std::to_string( names[1] ), + "dend-ch160801B_axon-Fluo55_low.h5" )); +} + +#endif