diff --git a/bioexplorer/backend/science/api/Params.cpp b/bioexplorer/backend/science/api/Params.cpp index d5a0d0b61..d50e167f9 100644 --- a/bioexplorer/backend/science/api/Params.cpp +++ b/bioexplorer/backend/science/api/Params.cpp @@ -939,7 +939,7 @@ bool from_json(NeuronsDetails ¶m, const std::string &payload) FROM_JSON(param, js, loadAxon); FROM_JSON(param, js, loadBasalDendrites); FROM_JSON(param, js, loadApicalDendrites); - FROM_JSON(param, js, loadSynapses); + FROM_JSON(param, js, synapsesType); FROM_JSON(param, js, generateInternals); FROM_JSON(param, js, generateExternals); FROM_JSON(param, js, showMembrane); diff --git a/bioexplorer/backend/science/common/SDFGeometries.cpp b/bioexplorer/backend/science/common/SDFGeometries.cpp index 39b3fb596..8dbef3061 100644 --- a/bioexplorer/backend/science/common/SDFGeometries.cpp +++ b/bioexplorer/backend/science/common/SDFGeometries.cpp @@ -63,11 +63,9 @@ Vector4fs SDFGeometries::_getProcessedSectionPoints(const MorphologyRepresentati const Vector4fs& points) { Vector4fs localPoints; - if (representation == MorphologyRepresentation::bezier && points.size() > DEFAULT_BEZIER_STEP * 2) - { - for (double t = 0.0; t <= 1.0; t += 1.0 / static_cast(points.size() * DEFAULT_BEZIER_STEP)) + if (representation == MorphologyRepresentation::bezier) + for (double t = 0.0; t <= 1.0; t += 1.0 / static_cast(points.size())) localPoints.push_back(getBezierPoint(points, t)); - } else localPoints = points; return localPoints; diff --git a/bioexplorer/backend/science/common/ThreadSafeContainer.cpp b/bioexplorer/backend/science/common/ThreadSafeContainer.cpp index 2f0b572e9..25067c570 100644 --- a/bioexplorer/backend/science/common/ThreadSafeContainer.cpp +++ b/bioexplorer/backend/science/common/ThreadSafeContainer.cpp @@ -36,7 +36,7 @@ namespace common { using namespace core; -const float equalityEpsilon = 0.001f; +const float equalityEpsilon = 1e-6f; ThreadSafeContainer::ThreadSafeContainer(Model& model, const double alignToGrid, const Vector3d& position, const Quaterniond& rotation, const Vector3d& scale) @@ -93,7 +93,7 @@ uint64_t ThreadSafeContainer::addCone(const Vector3f& sourcePosition, const floa _bounds.merge(scaledDstPosition - scaledDstRadius); return _addSDFGeometry(materialId, geom, neighbours); } - if (abs(sourceRadius - targetRadius) < equalityEpsilon) + if (fabs(sourceRadius - targetRadius) < equalityEpsilon) { const auto scaledSrcRadius = sourceRadius * scale.x; const auto scaledDstRadius = targetRadius * scale.x; diff --git a/bioexplorer/backend/science/common/Types.h b/bioexplorer/backend/science/common/Types.h index b3210bc9a..bfb7b3dad 100644 --- a/bioexplorer/backend/science/common/Types.h +++ b/bioexplorer/backend/science/common/Types.h @@ -330,8 +330,18 @@ using NeuronsPtr = std::shared_ptr; class Synapses; using SynapsesPtr = std::shared_ptr; +enum class MorphologySynapseType +{ + none = 0, + afferent = 1, + efferent = 2, + debug = 4, + all = 8 +}; + typedef struct { + MorphologySynapseType type; uint64_t postSynapticNeuronId; uint64_t postSynapticSectionId; uint64_t postSynapticSegmentId; @@ -1394,6 +1404,7 @@ typedef struct /** Amplitude applied to the radius */ double amplitude{1.0}; } VasculatureRadiusReportDetails; + typedef struct { /** Name of the assembly containing the astrocytes */ @@ -1461,8 +1472,8 @@ typedef struct bool loadBasalDendrites{true}; /** Load apical dendrites if set to true */ bool loadApicalDendrites{true}; - /** Load synapses if set to true */ - bool loadSynapses{false}; + /** Type of synapses to load */ + morphology::MorphologySynapseType synapsesType{morphology::MorphologySynapseType::none}; /** Generate internal components (nucleus and mitochondria) */ bool generateInternals{false}; /** Generate external components (myelin steath) */ diff --git a/bioexplorer/backend/science/common/Utils.cpp b/bioexplorer/backend/science/common/Utils.cpp index 1218a6841..a7babe3d1 100644 --- a/bioexplorer/backend/science/common/Utils.cpp +++ b/bioexplorer/backend/science/common/Utils.cpp @@ -537,6 +537,11 @@ size_t getMaterialIdFromOrientation(const Vector3d& orientation) return ((rgb.x & 0x0ff) << 16) | ((rgb.y & 0x0ff) << 8) | (rgb.z & 0x0ff); } +double rnd0() +{ + return static_cast(rand() % 1000) / 1000.0; +} + double rnd1() { return static_cast(rand() % 1000 - 500) / 1000.0; diff --git a/bioexplorer/backend/science/common/Utils.h b/bioexplorer/backend/science/common/Utils.h index b07afc9e5..4618f1ed4 100644 --- a/bioexplorer/backend/science/common/Utils.h +++ b/bioexplorer/backend/science/common/Utils.h @@ -212,6 +212,13 @@ double worleyNoise(const core::Vector3d& p, const double cellCount); size_t getMaterialIdFromOrientation(const core::Vector3d& orientation); +/** + * @brief Return a random double between 0 and 1 + * + * @return double A random double between 0 and 1 + */ +double rnd0(); + /** * @brief Return a random double between -0.5 and 0.5 * diff --git a/bioexplorer/backend/science/io/db/DBConnector.cpp b/bioexplorer/backend/science/io/db/DBConnector.cpp index 7ba070981..4239d8560 100644 --- a/bioexplorer/backend/science/io/db/DBConnector.cpp +++ b/bioexplorer/backend/science/io/db/DBConnector.cpp @@ -743,8 +743,8 @@ SectionMap DBConnector::getNeuronSections(const std::string& populationName, con return sections; } -SectionSynapseMap DBConnector::getNeuronSynapses(const std::string& populationName, const uint64_t neuronId, - const std::string& sqlCondition) const +SectionSynapseMap DBConnector::getNeuronAfferentSynapses(const std::string& populationName, const uint64_t neuronId, + const std::string& sqlCondition) const { CHECK_DB_INITIALIZATION SectionSynapseMap sectionSynapseMap; @@ -776,6 +776,7 @@ SectionSynapseMap DBConnector::getNeuronSynapses(const std::string& populationNa const auto preSynapticSectionId = c[0].as(); const auto preSynapticSegmentId = c[1].as(); Synapse synapse; + synapse.type = MorphologySynapseType::afferent; synapse.preSynapticSegmentDistance = c[2].as(); synapse.postSynapticNeuronId = c[3].as(); synapse.postSynapticSectionId = c[4].as(); diff --git a/bioexplorer/backend/science/io/db/DBConnector.h b/bioexplorer/backend/science/io/db/DBConnector.h index 99e390758..291efb316 100644 --- a/bioexplorer/backend/science/io/db/DBConnector.h +++ b/bioexplorer/backend/science/io/db/DBConnector.h @@ -258,7 +258,7 @@ class DBConnector const std::string& sqlCondition = "") const; /** - * @brief Get the synapses attached to a given neuron + * @brief Get the afferent synapses attached to a given neuron * * @param populationName Name of the population * @param neuronId Identifier of the neuron @@ -266,8 +266,8 @@ class DBConnector * statement * @return SectionSynapseMap A map of synapses */ - morphology::SectionSynapseMap getNeuronSynapses(const std::string& populationName, const uint64_t neuronId, - const std::string& sqlCondition = "") const; + morphology::SectionSynapseMap getNeuronAfferentSynapses(const std::string& populationName, const uint64_t neuronId, + const std::string& sqlCondition = "") const; /** * @brief Get a selection of spikes from a neuron spike report diff --git a/bioexplorer/backend/science/morphologies/Morphologies.h b/bioexplorer/backend/science/morphologies/Morphologies.h index 7ac212f06..c2ee398f5 100644 --- a/bioexplorer/backend/science/morphologies/Morphologies.h +++ b/bioexplorer/backend/science/morphologies/Morphologies.h @@ -37,7 +37,8 @@ const size_t MATERIAL_OFFSET_SOMA = 1; const size_t MATERIAL_OFFSET_AXON = 2; const size_t MATERIAL_OFFSET_DENDRITE = 3; const size_t MATERIAL_OFFSET_APICAL_DENDRITE = 4; -const size_t MATERIAL_OFFSET_SYNAPSE = 5; +const size_t MATERIAL_OFFSET_AFFERENT_SYNAPSE = 5; +const size_t MATERIAL_OFFSET_EFFERENT_SYNAPSE = 6; const size_t MATERIAL_OFFSET_MITOCHONDRION = 7; const size_t MATERIAL_OFFSET_NUCLEUS = 8; const size_t MATERIAL_OFFSET_MYELIN_SHEATH = 9; diff --git a/bioexplorer/backend/science/morphologies/Neurons.cpp b/bioexplorer/backend/science/morphologies/Neurons.cpp index d061c5510..8daa33a85 100644 --- a/bioexplorer/backend/science/morphologies/Neurons.cpp +++ b/bioexplorer/backend/science/morphologies/Neurons.cpp @@ -292,6 +292,48 @@ void Neurons::_buildOrientations(ThreadSafeContainer& container, const NeuronSom } } +SectionSynapseMap Neurons::_buildDebugSynapses(const uint64_t neuronId, const SectionMap& sections) +{ + SectionSynapseMap synapses; + for (const auto& section : sections) + { + if (static_cast(section.second.type) == NeuronSectionType::axon) + continue; + + const auto& points = section.second.points; + double sectionLength = 0.0; + doubles segmentEnds; + for (size_t i = 0; i < points.size() - 1; ++i) + { + const auto segmentLength = length(points[i + 1] - points[i]); + segmentEnds.push_back(sectionLength); + sectionLength += segmentLength; + } + const size_t potentialNumberOfSynapses = sectionLength / DEFAULT_SPINE_RADIUS + 1; + const size_t effectiveNumberOfSynapses = potentialNumberOfSynapses * (0.5 + 0.5 * rnd0()); + + for (size_t i = 0; i < effectiveNumberOfSynapses; ++i) + { + const double distance = rnd0() * sectionLength; + size_t segmentId = 0; + while (segmentEnds[segmentId] < distance && segmentId < segmentEnds.size()) + ++segmentId; + + const auto preSynapticSectionId = section.first; + const auto preSynapticSegmentId = segmentId; + Synapse synapse; + synapse.type = (rand() % 2 == 0 ? MorphologySynapseType::afferent : MorphologySynapseType::efferent); + synapse.preSynapticSegmentDistance = segmentEnds[segmentId] - distance; + synapse.postSynapticNeuronId = neuronId; + synapse.postSynapticSectionId = 0; + synapse.postSynapticSegmentId = 0; + synapse.postSynapticSegmentDistance = 0.0; + synapses[preSynapticSectionId][preSynapticSegmentId].push_back(synapse); + } + } + return synapses; +} + void Neurons::_buildMorphology(ThreadSafeContainer& container, const uint64_t neuronId, const NeuronSoma& soma, const uint64_t neuronIndex) { @@ -404,8 +446,19 @@ void Neurons::_buildMorphology(ThreadSafeContainer& container, const uint64_t ne // Load synapses for all sections SectionSynapseMap synapses; - if (_details.loadSynapses) - synapses = connector.getNeuronSynapses(_details.populationName, neuronId); + switch (_details.synapsesType) + { + case morphology::MorphologySynapseType::afferent: + { + synapses = connector.getNeuronAfferentSynapses(_details.populationName, neuronId); + break; + } + case morphology::MorphologySynapseType::debug: + { + synapses = _buildDebugSynapses(neuronId, sections); + break; + } + } // Sections (dendrites and axon) uint64_t geometryIndex = 0; @@ -654,12 +707,12 @@ void Neurons::_addSection(ThreadSafeContainer& container, const uint64_t neuronI } const auto& srcPoint = localPoints[i]; - const float srcRadius = _getCorrectedRadius(srcPoint.w * 0.5f, _details.radiusMultiplier); + const double srcRadius = _getCorrectedRadius(srcPoint.w * 0.5, _details.radiusMultiplier); const auto src = _animatedPosition(Vector4d(somaPosition + somaRotation * Vector3d(srcPoint), srcRadius), neuronId); const auto& dstPoint = localPoints[i + 1]; - const float dstRadius = _getCorrectedRadius(dstPoint.w * 0.5f, _details.radiusMultiplier); + const double dstRadius = _getCorrectedRadius(dstPoint.w * 0.5, _details.radiusMultiplier); const auto dst = _animatedPosition(Vector4d(somaPosition + somaRotation * Vector3d(dstPoint), dstRadius), neuronId); const double sampleLength = length(dstPoint - srcPoint); @@ -697,17 +750,25 @@ void Neurons::_addSection(ThreadSafeContainer& container, const uint64_t neuronI const auto it = segmentSynapses.find(i); if (it != segmentSynapses.end()) { - const size_t spineMaterialId = _details.morphologyColorScheme == MorphologyColorScheme::section_type - ? baseMaterialId + MATERIAL_OFFSET_SYNAPSE - : materialId; const auto synapses = (*it).second; PLUGIN_INFO(3, "Adding " << synapses.size() << " spines to segment " << i << " of section " << sectionId); for (const auto& synapse : synapses) { - const Vector3d segmentDirection = normalize(dst - src); - const Vector3d surfacePosition = src + segmentDirection * synapse.preSynapticSegmentDistance; - _addSpine(container, neuronId, morphologyId, sectionId, synapse, spineMaterialId, surfacePosition); + const size_t spineMaterialId = + _details.morphologyColorScheme == MorphologyColorScheme::section_type + ? baseMaterialId + (synapse.type == MorphologySynapseType::afferent + ? MATERIAL_OFFSET_AFFERENT_SYNAPSE + : MATERIAL_OFFSET_EFFERENT_SYNAPSE) + : materialId; + const Vector3d segmentDirection = dst - src; + const double radiusInSegment = + srcRadius + ((1.0 / length(segmentDirection)) * synapse.preSynapticSegmentDistance) * + (dstRadius - srcRadius); + const Vector3d positionInSegment = + src + normalize(segmentDirection) * synapse.preSynapticSegmentDistance; + _addSpine(container, neuronId, morphologyId, sectionId, synapse, spineMaterialId, positionInSegment, + radiusInSegment); } } @@ -716,11 +777,9 @@ void Neurons::_addSection(ThreadSafeContainer& container, const uint64_t neuronI geometryIndex = container.addCone(src, srcRadius, dst, dstRadius, materialId, useSdf, userData, neighbours, displacement); - neighbours.insert(geometryIndex); - // Stop if distance to soma in greater than the specified - // max value + // Stop if distance to soma in greater than the specified max value _maxDistanceToSoma = std::max(_maxDistanceToSoma, distanceToSoma + sectionLength); if (_details.maxDistanceToSoma > 0.0 && distanceToSoma + sectionLength >= _details.maxDistanceToSoma) break; @@ -916,91 +975,24 @@ void Neurons::_addAxonMyelinSheath(ThreadSafeContainer& container, const uint64_ void Neurons::_addSpine(ThreadSafeContainer& container, const uint64_t neuronId, const uint64_t morphologyId, const uint64_t sectionId, const Synapse& synapse, const size_t SpineMaterialId, - const Vector3d& preSynapticSurfacePosition) + const Vector3d& preSynapticSurfacePosition, const double radiusAtSurfacePosition) { const double radius = DEFAULT_SPINE_RADIUS; - - // Spine geometry -#if 0 - const auto& connector = DBConnector::getInstance(); - const auto postSynapticSections = connector.getNeuronSections( - _details.populationName, synapse.postSynapticNeuronId, - "s.section_guid=" + std::to_string(synapse.postSynapticSectionId)); - - if (postSynapticSections.empty()) - { - PLUGIN_ERROR("Spine: " << neuronId << " / " << sectionId << " -> " - << synapse.postSynapticNeuronId << " / " - << synapse.postSynapticSectionId << " / " - << synapse.postSynapticSegmentId); - PLUGIN_ERROR("Could not find section " << synapse.postSynapticSectionId - << "of neuron " - << synapse.postSynapticNeuronId); - return; - } - - - if (postSynapticSegmentId >= nbPostSynapticSegments - 1) - { - PLUGIN_ERROR("Spine: " << neuronId << " / " << sectionId << " -> " - << synapse.postSynapticNeuronId << " / " - << synapse.postSynapticSectionId << " / " - << synapse.postSynapticSegmentId); - PLUGIN_ERROR("Post-synaptic segment Id is out of range: " - << postSynapticSegmentId << "/" << nbPostSynapticSegments - << ". Section " << synapse.postSynapticSectionId - << " of neuron " << synapse.postSynapticNeuronId); - return; - } - - const auto& postSynapticSection = postSynapticSections.begin()->second; - auto postSynapticSegmentId = synapse.postSynapticSegmentId; - const auto nbPostSynapticSegments = postSynapticSection.points.size(); - - const auto spineSmallRadius = radius * spineRadiusRatio * 0.15; - const auto spineBaseRadius = radius * spineRadiusRatio * 0.25; - const auto spineLargeRadius = radius * spineRadiusRatio; - - const Vector3d postSynapticSegmentDirection = - normalize(postSynapticSection.points[postSynapticSegmentId + 1] - - postSynapticSection.points[postSynapticSegmentId]); - - const Vector3d postSynapticSurfacePosition = - Vector3d(postSynapticSection.points[postSynapticSegmentId]) + - postSynapticSegmentDirection * synapse.postSynapticSegmentDistance; - - const Vector3d animatedPostSynapticSurfacePosition = - _animatedPosition(Vector4d(postSynapticSurfacePosition, - spineBaseRadius), - synapse.postSynapticNeuronId); - const auto direction = - animatedPostSynapticSurfacePosition - preSynapticSurfacePosition; - const auto l = length(direction) - spineLargeRadius; -#else const double spineScale = 0.25; + const double spineLength = 0.5; const auto spineSmallRadius = radius * spineRadiusRatio * 0.5 * spineScale; const auto spineBaseRadius = radius * spineRadiusRatio * 0.75 * spineScale; const auto spineLargeRadius = radius * spineRadiusRatio * 2.5 * spineScale; - const auto direction = - Vector3d((rand() % 200 - 100) / 100.0, (rand() % 200 - 100) / 100.0, (rand() % 200 - 100) / 100.0); - const auto l = 6.f * radius * spineScale; -#endif - - // container.addSphere(preSynapticSurfacePosition, - // DEFAULT_SPINE_RADIUS - // * 3.f, - // SpineMaterialId, neuronId); - - const auto origin = preSynapticSurfacePosition; - const auto target = origin + normalize(direction) * l; + const auto direction = normalize(Vector3d(rnd1(), rnd1(), rnd1())); + const auto origin = preSynapticSurfacePosition + normalize(direction) * radiusAtSurfacePosition; + const auto target = preSynapticSurfacePosition + normalize(direction) * (radiusAtSurfacePosition + spineLength); // Create random shape between origin and target auto middle = (target + origin) / 2.0; - const double d = length(target - origin) / 1.5; - const auto i = neuronId * 4; - middle += Vector3f(d * rnd2(i), d * rnd2(i + 1), d * rnd2(i + 2)); - const float spineMiddleRadius = spineSmallRadius + d * 0.1 * rnd2(i + 3); + const double d = length(target - origin) / 2.0; + middle += Vector3f(d * rnd1(), d * rnd1(), d * rnd1()); + const float spineMiddleRadius = spineSmallRadius + d * 0.1 * rnd1(); const auto displacement = Vector3f(_getDisplacementValue(DisplacementElement::morphology_spine_strength), _getDisplacementValue(DisplacementElement::morphology_spine_frequency), 0.f); @@ -1023,129 +1015,6 @@ void Neurons::_addSpine(ThreadSafeContainer& container, const uint64_t neuronId, ++_nbSpines; } -#if 0 -void Neurons::_addSpine2(ThreadSafeContainer& container, - const uint64_t neuronId, const uint64_t morphologyId, - const uint64_t sectionId, const Synapse& synapse, - const size_t SpineMaterialId, - const Vector3d& preSynapticSurfacePosition) -{ - // TO REMOVE - container.addSphere(preSynapticSurfacePosition, DEFAULT_SPINE_RADIUS * 3.f, - SpineMaterialId, neuronId); - // TO REMOVE - - const auto& connector = DBConnector::getInstance(); - const double radius = DEFAULT_SPINE_RADIUS; - - // Spine geometry - const auto spineSmallRadius = radius * spineRadiusRatio * 0.15; - const auto spineBaseRadius = radius * spineRadiusRatio * 0.25; - const auto spineLargeRadius = radius * spineRadiusRatio; - - const auto postSynapticSections = connector.getNeuronSections( - _details.populationName, synapse.postSynapticNeuronId, - "s.section_guid=" + std::to_string(synapse.postSynapticSectionId)); - - if (postSynapticSections.empty()) - { - PLUGIN_ERROR("Spine: " << neuronId << " / " << sectionId << " -> " - << synapse.postSynapticNeuronId << " / " - << synapse.postSynapticSectionId << " / " - << synapse.postSynapticSegmentId); - PLUGIN_ERROR("Could not find section " << synapse.postSynapticSectionId - << "of neuron " - << synapse.postSynapticNeuronId); - return; - } - - const auto& postSynapticSection = postSynapticSections.begin()->second; - auto postSynapticSegmentId = synapse.postSynapticSegmentId; - const auto nbPostSynapticSegments = postSynapticSection.points.size(); - if (postSynapticSegmentId >= nbPostSynapticSegments - 1) - { - PLUGIN_ERROR("Spine: " << neuronId << " / " << sectionId << " -> " - << synapse.postSynapticNeuronId << " / " - << synapse.postSynapticSectionId << " / " - << synapse.postSynapticSegmentId); - PLUGIN_ERROR("Post-synaptic segment Id is out of range: " - << postSynapticSegmentId << "/" << nbPostSynapticSegments - << ". Section " << synapse.postSynapticSectionId - << " of neuron " << synapse.postSynapticNeuronId); - return; - } - - // const Vector3d postSynapticSegmentDirection = - // normalize(postSynapticSection.points[postSynapticSegmentId + 1] - - // postSynapticSection.points[postSynapticSegmentId]); - - // const Vector3d postSynapticSurfacePosition = - // Vector3d(postSynapticSection.points[postSynapticSegmentId]) + - // postSynapticSegmentDirection * synapse.postSynapticSegmentDistance; - - // const Vector3d animatedPostSynapticSurfacePosition = - // _animatedPosition(Vector4d(postSynapticSurfacePosition, - // spineBaseRadius), - // synapse.postSynapticNeuronId); - - PLUGIN_ERROR("Postsynaptic neuron ID: " << synapse.postSynapticNeuronId); - const auto postSynapticNeuronSomas = - connector.getNeurons(_details.populationName, - "guid=" + - std::to_string(synapse.postSynapticNeuronId)); - const auto& postSynapticSoma = postSynapticNeuronSomas.begin()->second; - - const Vector3f postSynapticSurfacePosition = _animatedPosition( - Vector4d(postSynapticSoma.position + - postSynapticSoma.rotation * - Vector3d( - postSynapticSection.points[postSynapticSegmentId]), - DEFAULT_SPINE_RADIUS * 3.f), - synapse.postSynapticNeuronId); - - container.addSphere(postSynapticSurfacePosition, DEFAULT_SPINE_RADIUS * 3.f, - SpineMaterialId, neuronId); - container.addCone(preSynapticSurfacePosition, DEFAULT_SPINE_RADIUS * 3.f, - postSynapticSurfacePosition, DEFAULT_SPINE_RADIUS * 3.f, - SpineMaterialId, neuronId); - // TO REMOVE - - // const auto direction = - // animatedPostSynapticSurfacePosition - preSynapticSurfacePosition; - // const auto l = length(direction) - spineLargeRadius; - - // const auto origin = postSynapticSurfacePosition; - // const auto target = origin + normalize(direction) * l; - - // // Create random shape between origin and target - // auto middle = (target + origin) / 2.0; - // const double d = length(target - origin) / 1.5; - // const auto i = neuronId * 4; - // middle += Vector3f(d * rnd2(i), d * rnd2(i + 1), d * rnd2(i + 2)); - // const float spineMiddleRadius = spineSmallRadius + d * 0.1 * rnd2(i + 3); - - // const auto displacement = - // Vector3f(spineDisplacementStrength, spineDisplacementFrequency, 0.f); - // Neighbours neighbours; - // if (!_details.useSdf) - // container.addSphere(target, spineLargeRadius, SpineMaterialId, - // neuronId); - // neighbours.insert(container.addSphere(middle, spineMiddleRadius, - // SpineMaterialId, neuronId, - // neighbours, displacement)); - // if (middle != origin) - // container.addCone(origin, spineSmallRadius, middle, - // spineMiddleRadius, - // SpineMaterialId, neuronId, neighbours, - // displacement); - // if (middle != target) - // container.addCone(middle, spineMiddleRadius, target, - // spineLargeRadius, - // SpineMaterialId, neuronId, neighbours, - // displacement); -} -#endif - Vector4ds Neurons::getNeuronSectionPoints(const uint64_t neuronId, const uint64_t sectionId) { const auto& connector = DBConnector::getInstance(); diff --git a/bioexplorer/backend/science/morphologies/Neurons.h b/bioexplorer/backend/science/morphologies/Neurons.h index 77539054c..738afe5da 100644 --- a/bioexplorer/backend/science/morphologies/Neurons.h +++ b/bioexplorer/backend/science/morphologies/Neurons.h @@ -83,6 +83,8 @@ class Neurons : public Morphologies void _buildMorphology(common::ThreadSafeContainer& container, const uint64_t neuronId, const NeuronSoma& soma, const uint64_t neuronIndex); + SectionSynapseMap _buildDebugSynapses(const uint64_t neuronId, const SectionMap& sections); + void _addArrow(common::ThreadSafeContainer& container, const uint64_t neuronId, const core::Vector3d& somaPosition, const core::Quaterniond& somaRotation, const core::Vector4d& srcNode, const core::Vector4d& dstNode, const details::NeuronSectionType sectionType, const size_t baseMaterialId, @@ -96,7 +98,7 @@ class Neurons : public Morphologies void _addSpine(common::ThreadSafeContainer& container, const uint64_t neuronId, const uint64_t morphologyId, const uint64_t sectionId, const Synapse& synapse, const size_t baseMaterialId, - const core::Vector3d& surfacePosition); + const core::Vector3d& surfacePosition, const double radiusAtSurfacePosition); void _addSectionInternals(common::ThreadSafeContainer& container, const uint64_t neuronId, const core::Vector3d& somaPosition, const core::Quaterniond& somaRotation, diff --git a/bioexplorer/pythonsdk/bioexplorer/bio_explorer.py b/bioexplorer/pythonsdk/bioexplorer/bio_explorer.py index 67307a4c4..460402300 100644 --- a/bioexplorer/pythonsdk/bioexplorer/bio_explorer.py +++ b/bioexplorer/pythonsdk/bioexplorer/bio_explorer.py @@ -644,6 +644,13 @@ class BioExplorer: SYNAPSE_REPRESENTATION_SPHERE = 0 SYNAPSE_REPRESENTATION_SPINE = 1 + # Neuron synapses types + NEURON_SYNAPSES_NONE = 0 + NEURON_SYNAPSES_AFFERENT = 1 + NEURON_SYNAPSES_EFFERENT = 2 + NEURON_SYNAPSES_DEBUG = 4 + NEURON_SYNAPSES_ALL = 8 + # Material offsets in neurons NB_MATERIALS_PER_MORPHOLOGY = 10 NEURON_MATERIAL_VARICOSITY = 0 @@ -651,7 +658,8 @@ class BioExplorer: NEURON_MATERIAL_AXON = 2 NEURON_MATERIAL_BASAL_DENDRITE = 3 NEURON_MATERIAL_APICAL_DENDRITE = 4 - NEURON_MATERIAL_SYNAPSE = 5 + NEURON_MATERIAL_AFFERENT_SYNAPSE = 5 + NEURON_MATERIAL_EFFERENT_SYNAPSE = 6 NEURON_MATERIAL_MITOCHONDRION = 7 NEURON_MATERIAL_NUCLEUS = 8 NEURON_MATERIAL_MYELIN_SHEATH = 9 @@ -3306,7 +3314,7 @@ def add_neurons( load_axon=True, load_basal_dendrites=True, load_apical_dendrites=True, - load_synapses=False, + synapses_type=NEURON_SYNAPSES_NONE, generate_internals=False, generate_externals=False, generate_varicosities=False, @@ -3367,7 +3375,7 @@ def add_neurons( params["loadAxon"] = load_axon params["loadBasalDendrites"] = load_basal_dendrites params["loadApicalDendrites"] = load_apical_dendrites - params["loadSynapses"] = load_synapses + params["synapsesType"] = synapses_type params["generateInternals"] = generate_internals params["generateExternals"] = generate_externals params["showMembrane"] = show_membrane diff --git a/bioexplorer/pythonsdk/notebooks/metabolism/BioExplorer_metabolism_plots.ipynb b/bioexplorer/pythonsdk/notebooks/metabolism/BioExplorer_metabolism_plots.ipynb index 5a69a8ff2..b3559b89f 100644 --- a/bioexplorer/pythonsdk/notebooks/metabolism/BioExplorer_metabolism_plots.ipynb +++ b/bioexplorer/pythonsdk/notebooks/metabolism/BioExplorer_metabolism_plots.ipynb @@ -76,7 +76,7 @@ " population_name='o1',\n", " realism_level=realism_level,\n", " load_somas=True, load_basal_dendrites=True, load_apical_dendrites=True, load_axon=True,\n", - " load_synapses=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT,\n", " generate_internals=True, generate_externals=False,\n", " sql_node_filter=neuron_sql_filter)\n", "\n", @@ -657,4 +657,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuromodulation_movie.ipynb b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuromodulation_movie.ipynb index 8307b0623..476c4389a 100644 --- a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuromodulation_movie.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuromodulation_movie.ipynb @@ -80,7 +80,7 @@ " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " population_name=neuron_population_name,\n", " realism_level=realism_level, generate_buttons=True,\n", - " load_synapses=True, show_membrane=not load_mesh_neuron,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, show_membrane=not load_mesh_neuron,\n", " generate_internals=True, generate_externals=False,\n", " sql_node_filter=neuron_sql_filter, scale=scale,\n", " animation_params=MolecularSystemAnimationParams(1))\n", @@ -757,4 +757,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_components.ipynb b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_components.ipynb index d316c4f67..c3d95e490 100644 --- a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_components.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_components.ipynb @@ -89,7 +89,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SECTION,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=generate_internals, generate_externals=False,\n", @@ -114,7 +114,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SECTION,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=False,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=False,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=generate_internals, generate_externals=False,\n", diff --git a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_covers.ipynb b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_covers.ipynb index cbd86528a..abdcf6728 100644 --- a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_covers.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_covers.ipynb @@ -86,7 +86,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=True, generate_externals=False,\n", @@ -116,7 +116,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=True, generate_externals=False,\n", diff --git a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_full_movie.ipynb b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_full_movie.ipynb index 6aec6bd1d..1d1de3192 100644 --- a/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_full_movie.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neuromodulation/BioExplorer_neuronmodulation_full_movie.ipynb @@ -96,7 +96,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=generate_internals, generate_externals=False,\n", @@ -148,7 +148,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=False,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=False,\n", " load_somas=True, load_axon=False, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=generate_internals, generate_externals=False,\n", @@ -189,7 +189,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=False, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=generate_internals, generate_externals=False,\n", diff --git a/bioexplorer/pythonsdk/notebooks/neurons/BioExplorer_neurons.ipynb b/bioexplorer/pythonsdk/notebooks/neurons/BioExplorer_neurons.ipynb index 69b1a9919..01c147784 100644 --- a/bioexplorer/pythonsdk/notebooks/neurons/BioExplorer_neurons.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neurons/BioExplorer_neurons.ipynb @@ -61,7 +61,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_BEZIER,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " generate_internals=True, generate_externals=True,\n", diff --git a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_animated_neurons.ipynb b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_animated_neurons.ipynb index fe14ab95c..045588443 100644 --- a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_animated_neurons.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_animated_neurons.ipynb @@ -149,7 +149,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SECTION,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=False,\n", + " synapses_type=be.NEURON_SYNAPSES_NONE,\n", " load_somas=True, \n", " load_axon=False, generate_varicosities=False,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", @@ -243,4 +243,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neuron.ipynb b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neuron.ipynb index bc50f2bcb..45d72715d 100644 --- a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neuron.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neuron.ipynb @@ -142,7 +142,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " sql_node_filter='guid=49',\n", diff --git a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neurons.ipynb b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neurons.ipynb index bc50f2bcb..45d72715d 100644 --- a/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neurons.ipynb +++ b/bioexplorer/pythonsdk/notebooks/neurons/animation/BioExplorer_growing_neurons.ipynb @@ -142,7 +142,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SEGMENT,\n", " morphology_color_scheme=be.MORPHOLOGY_COLOR_SCHEME_SECTION_TYPE,\n", " realism_level=be.MORPHOLOGY_REALISM_LEVEL_ALL,\n", - " load_synapses=True, generate_varicosities=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT, generate_varicosities=True,\n", " load_somas=True, load_axon=True, show_membrane=True,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", " sql_node_filter='guid=49',\n", diff --git a/bioexplorer/pythonsdk/notebooks/vasculature/animation/BioExplorer_animated_ngv.ipynb b/bioexplorer/pythonsdk/notebooks/vasculature/animation/BioExplorer_animated_ngv.ipynb index d83e68c0f..5a74af35f 100644 --- a/bioexplorer/pythonsdk/notebooks/vasculature/animation/BioExplorer_animated_ngv.ipynb +++ b/bioexplorer/pythonsdk/notebooks/vasculature/animation/BioExplorer_animated_ngv.ipynb @@ -110,7 +110,7 @@ " morphology_representation=be.MORPHOLOGY_REPRESENTATION_SECTION,\n", " simulation_report_id=2,\n", " realism_level=morphology_realism_level,\n", - " load_synapses=True,\n", + " synapses_type=be.NEURON_SYNAPSES_AFFERENT,\n", " load_somas=True,\n", " load_axon=True, generate_varicosities=False, generate_externals=False,\n", " load_basal_dendrites=True, load_apical_dendrites=True,\n", @@ -283,4 +283,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file