From 9b6d9e2605d5259661bb8aea6f0ff95066796bf6 Mon Sep 17 00:00:00 2001 From: Likitha Nanduri Date: Fri, 8 May 2026 09:59:36 -0700 Subject: [PATCH 1/2] [issue-722] Fix default recorder variable setup --- Simulator/Connections/Neuro/ConnGrowth.cpp | 7 ++- Simulator/Connections/Neuro/ConnStatic.cpp | 22 +++++++- Simulator/Connections/Neuro/ConnStatic.h | 3 ++ Simulator/Edges/AllEdges.h | 26 +++++++++- Simulator/Layouts/NG911/Layout911.cpp | 22 +++++++- Simulator/Layouts/NG911/Layout911.h | 11 +++- docs/Notes/RecordersNotes.md | 58 +++++++++++++++++++--- docs/User/configuration.md | 4 +- 8 files changed, 139 insertions(+), 14 deletions(-) diff --git a/Simulator/Connections/Neuro/ConnGrowth.cpp b/Simulator/Connections/Neuro/ConnGrowth.cpp index 8b754e74e..34e72c4ac 100644 --- a/Simulator/Connections/Neuro/ConnGrowth.cpp +++ b/Simulator/Connections/Neuro/ConnGrowth.cpp @@ -333,4 +333,9 @@ void ConnGrowth::printRadii() const void ConnGrowth::registerHistoryVariables() { -} \ No newline at end of file + Recorder &recorder = Simulator::getInstance().getModel().getRecorder(); + recorder.registerVariable("radii", radii_, Recorder::UpdatedType::DYNAMIC); + recorder.registerVariable("rates", rates_, Recorder::UpdatedType::DYNAMIC); + recorder.registerVariable("outgrowth", outgrowth_, Recorder::UpdatedType::DYNAMIC); + recorder.registerVariable("deltaR", deltaR_, Recorder::UpdatedType::DYNAMIC); +} diff --git a/Simulator/Connections/Neuro/ConnStatic.cpp b/Simulator/Connections/Neuro/ConnStatic.cpp index 3f2f712fa..77e41b32d 100644 --- a/Simulator/Connections/Neuro/ConnStatic.cpp +++ b/Simulator/Connections/Neuro/ConnStatic.cpp @@ -93,7 +93,6 @@ void ConnStatic::printParameters() const void ConnStatic::registerHistoryVariables() { // Register the following variables to be recorded - // Note: There may be potential duplicate weight, source, destination vertices Recorder &recorder = Simulator::getInstance().getModel().getRecorder(); recorder.registerVariable("weight", WCurrentEpoch_, Recorder::UpdatedType::DYNAMIC); recorder.registerVariable("sourceVertex", sourceVertexIndexCurrentEpoch_, @@ -101,3 +100,24 @@ void ConnStatic::registerHistoryVariables() recorder.registerVariable("destinationVertex", destVertexIndexCurrentEpoch_, Recorder::UpdatedType::DYNAMIC); } + +bool ConnStatic::updateConnections() +{ + AllEdges &edges = getEdges(); + const vector &inUse = edges.getInUse(); + const vector &weights = edges.getWeights(); + const vector &sourceVertices = edges.getSourceVertexIndices(); + const vector &destVertices = edges.getDestVertexIndices(); + + // Copy one value per active edge into parallel recorder vectors. + // weight/source/destination entries at the same index describe the same edge. + for (BGSIZE iEdg = 0; iEdg < inUse.size(); iEdg++) { + if (inUse[iEdg]) { + WCurrentEpoch_.push_back(weights[iEdg]); + sourceVertexIndexCurrentEpoch_.push_back(sourceVertices[iEdg]); + destVertexIndexCurrentEpoch_.push_back(destVertices[iEdg]); + } + } + + return false; +} diff --git a/Simulator/Connections/Neuro/ConnStatic.h b/Simulator/Connections/Neuro/ConnStatic.h index 67d0a8fb6..fbb7bbc44 100644 --- a/Simulator/Connections/Neuro/ConnStatic.h +++ b/Simulator/Connections/Neuro/ConnStatic.h @@ -64,6 +64,9 @@ class ConnStatic : public Connections { /// Registers history variables for recording during simulation virtual void registerHistoryVariables() override; + /// Populates edge history variables for recording during the current epoch. + virtual bool updateConnections() override; + /// Get array of vertex weights const vector &getWCurrentEpoch() const { diff --git a/Simulator/Edges/AllEdges.h b/Simulator/Edges/AllEdges.h index ccc49308a..b726cdfec 100644 --- a/Simulator/Edges/AllEdges.h +++ b/Simulator/Edges/AllEdges.h @@ -59,6 +59,30 @@ class AllEdges { /// Populate a edge index map. virtual void createEdgeIndexMap(EdgeIndexMap &edgeIndexMap); + /// Get array of source vertex indices. + const vector &getSourceVertexIndices() const + { + return sourceVertexIndex_; + } + + /// Get array of destination vertex indices. + const vector &getDestVertexIndices() const + { + return destVertexIndex_; + } + + /// Get array of edge weights. + const vector &getWeights() const + { + return W_; + } + + /// Get array of active edge flags. + const vector &getInUse() const + { + return inUse_; + } + /// Cereal serialization method template void serialize(Archive &archive); @@ -253,4 +277,4 @@ template void AllEdges::serialize(Archive &archive) cereal::make_nvp("totalEdgeCount", totalEdgeCount_), cereal::make_nvp("maxEdgesPerVertex", maxEdgesPerVertex_), cereal::make_nvp("countVertices", countVertices_)); -} \ No newline at end of file +} diff --git a/Simulator/Layouts/NG911/Layout911.cpp b/Simulator/Layouts/NG911/Layout911.cpp index d024e2ea1..35ca5e893 100644 --- a/Simulator/Layouts/NG911/Layout911.cpp +++ b/Simulator/Layouts/NG911/Layout911.cpp @@ -46,16 +46,23 @@ void Layout911::setup() // so we call its method first Layout::setup(); + // xloc_ and yloc_ remain the layout coordinate storage. xloc_.assign(numVertices_, 0); yloc_.assign(numVertices_, 0); - // Loop over all vertices and set their x and y locations + // Size recorder mirrors to one initialized value per vertex. + xlocRecorder_.assign(numVertices_, 0); + ylocRecorder_.assign(numVertices_, 0); + + // Populate layout coordinates and recorder mirrors from GraphML. GraphManager::VertexIterator vi, vi_end; GraphManager &gm = GraphManager::getInstance(); for (boost::tie(vi, vi_end) = gm.vertices(); vi != vi_end; ++vi) { assert(*vi < numVertices_); xloc_[*vi] = gm[*vi].x; yloc_[*vi] = gm[*vi].y; + xlocRecorder_[*vi] = gm[*vi].x; + ylocRecorder_[*vi] = gm[*vi].y; } // Now we cache the between each pair of vertices distances^2 into a matrix @@ -79,6 +86,19 @@ void Layout911::printParameters() const { } +void Layout911::registerHistoryVariables() +{ + Layout::registerHistoryVariables(); + + // Register GraphML coordinates as CONSTANT recorder output. + Recorder &recorder = Simulator::getInstance().getModel().getRecorder(); + string baseName = "Location"; + string xLocation = "x_" + baseName; + string yLocation = "y_" + baseName; + recorder.registerVariable(xLocation, xlocRecorder_, Recorder::UpdatedType::CONSTANT); + recorder.registerVariable(yLocation, ylocRecorder_, Recorder::UpdatedType::CONSTANT); +} + // Creates a vertex type map. void Layout911::generateVertexTypeMap() { diff --git a/Simulator/Layouts/NG911/Layout911.h b/Simulator/Layouts/NG911/Layout911.h index 3b912391a..eb953398d 100644 --- a/Simulator/Layouts/NG911/Layout911.h +++ b/Simulator/Layouts/NG911/Layout911.h @@ -65,6 +65,9 @@ class Layout911 : public Layout { /// Registered to OperationManager as Operation::printParameters virtual void printParameters() const override; + /// Registers history variables for recording during simulation. + virtual void registerHistoryVariables() override; + /// Creates a vertex type map. /// /// @param numVertices number of the vertices to have in the type map. @@ -83,6 +86,10 @@ class Layout911 : public Layout { /// @return The distance between the given vertex and the (x, y) coordinates of a point double getDistance(int vertexId, double x, double y); - DeviceVector xloc_; - DeviceVector yloc_; + DeviceVector xloc_; ///< Layout x coordinates. + DeviceVector yloc_; ///< Layout y coordinates. + + /// Recorder mirrors; DeviceVector cannot be registered directly. + RecordableVector xlocRecorder_; + RecordableVector ylocRecorder_; }; diff --git a/docs/Notes/RecordersNotes.md b/docs/Notes/RecordersNotes.md index 11b92414d..3e4bf5eb2 100644 --- a/docs/Notes/RecordersNotes.md +++ b/docs/Notes/RecordersNotes.md @@ -11,7 +11,7 @@ The current subsystem is built around: - `Recorder`: abstract interface for recorder implementations - `XmlRecorder`: text output, stores captured history in memory, writes at the end - `Hdf5Recorder`: binary output, appends dynamic data to HDF5 datasets during the run -- `Xml911Recorder`: a specialized subclass that still exists in the factory, but its overridden `compileHistories()`, `saveSimData()`, and `printParameters()` are effectively empty today +- `Xml911Recorder`: a legacy specialized subclass that still exists in the factory, but its overridden `compileHistories()`, `saveSimData()`, and `printParameters()` are effectively empty today - `RecordableBase`: abstract interface for anything the recorder can observe - `RecordableVector`: generic 1-D recordable container - `EventBuffer`: epoch-aware event history buffer used by the recorder as a per-epoch view @@ -180,6 +180,21 @@ This is a `RecordableVector`. These are `VectorMatrix` objects containing neuron coordinates. +### NG911 layout + +`Layout911::registerHistoryVariables()` calls the base layout registration and also registers: + +- `x_Location` as `CONSTANT` +- `y_Location` as `CONSTANT` + +These NG911 coordinates are recorded through `RecordableVector` mirrors: + +- `xloc_` and `yloc_` remain the simulation/layout coordinate storage. +- `xlocRecorder_` and `ylocRecorder_` are recorder-compatible mirrors. +- The mirrors are populated from GraphML coordinates during layout setup. +- They are registered as `CONSTANT`, so each coordinate is written once at final save time. +- They do not replace `xloc_` or `yloc_`; they only expose the same coordinates to the recorder. + ### Neuro vertices `AllSpikingNeurons::registerHistoryVariables()` registers: @@ -196,13 +211,31 @@ Each variable is an `EventBuffer` that records spike times for one neu - `sourceVertex` as `DYNAMIC` - `destinationVertex` as `DYNAMIC` -These are `RecordableVector` objects representing the current epoch's changed or relevant connection data. +These three `RecordableVector` objects form an active edge list for each epoch: + +- one value is recorded per active edge for `weight` +- one value is recorded per active edge for `sourceVertex` +- one value is recorded per active edge for `destinationVertex` +- entries at the same index describe the same active edge +- the vectors are populated immediately before dynamic histories are compiled +- the output is the current active edge list per epoch, not only changed edges and not only the initial edge list ### Growth connections -`ConnGrowth::registerHistoryVariables()` currently does nothing. +`ConnGrowth::registerHistoryVariables()` registers: -This is important because some older notes discuss growth-specific recorded data such as radii histories, but those are not currently registered by this class. +- `radii` as `DYNAMIC` +- `rates` as `DYNAMIC` +- `outgrowth` as `DYNAMIC` +- `deltaR` as `DYNAMIC` + +These are 1-D `VectorMatrix` values recorded once per epoch. + +Growth `CompleteMatrix` fields are intentionally not recorded: + +- examples include weights, deltas, and areas +- `CompleteMatrix` is not a recorder-compatible flat value source +- issue #722 did not add recorder output for those fields ### NG911 connections @@ -245,6 +278,15 @@ The corresponding current container types are: - `numServers_`: `RecordableVector` - `numTrunks_`: `RecordableVector` +Other NG911 setup values remain configuration and log values for now: + +- `redialP` +- `avgDrivingSpeed` +- `psapsToErase` +- `respsToErase` + +They are not registered as recorder constants unless a future scalar-compatible recordable type is added. + ## `CONSTANT` vs `DYNAMIC` The distinction is implementation-significant. @@ -388,7 +430,11 @@ However, in the current code: - `saveSimData()` contains only commented-out legacy code - `printParameters()` is empty -As a result, it should be considered a legacy or placeholder specialization rather than an actively maintained recorder implementation. +As a result: + +- `Xml911Recorder` is legacy/placeholder code. +- It is not the current intended NG911 recorder path. +- NG911 simulations should use the generic recorder registration system through `XmlRecorder` or, when enabled and appropriate, `Hdf5Recorder`. ## `RecordableBase`, `RecordableVector`, and `EventBuffer` @@ -504,7 +550,7 @@ The current implementation makes several assumptions that are worth documenting ### Implementation limitations - `Xml911Recorder` is not an actively functional specialized recorder at present. -- `ConnGrowth` currently registers no history variables. +- NG911 scalar setup values remain configuration and log values until there is a scalar-compatible recordable type. - Some comments in headers still refer to older planned behavior or planned cleanup. - Several recorder diagrams and older notes in the docs describe designs that do not exactly match the current code. diff --git a/docs/User/configuration.md b/docs/User/configuration.md index 8c0f25256..7d19607e6 100644 --- a/docs/User/configuration.md +++ b/docs/User/configuration.md @@ -217,8 +217,8 @@ There are some elements of the main configuration file that is similar to the Ne - - + + Output/Results/test-small-911-out.xml From 82241279704aa1f50299b66cd4f40cdcb00d2f35 Mon Sep 17 00:00:00 2001 From: Likitha Nanduri Date: Tue, 19 May 2026 13:25:01 -0700 Subject: [PATCH 2/2] [issue-722] Sync edge state before GPU recorder read --- Simulator/Connections/Neuro/ConnStatic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Simulator/Connections/Neuro/ConnStatic.cpp b/Simulator/Connections/Neuro/ConnStatic.cpp index 77e41b32d..e96bdc2f8 100644 --- a/Simulator/Connections/Neuro/ConnStatic.cpp +++ b/Simulator/Connections/Neuro/ConnStatic.cpp @@ -104,6 +104,10 @@ void ConnStatic::registerHistoryVariables() bool ConnStatic::updateConnections() { AllEdges &edges = getEdges(); +#if defined(USE_GPU) + edges.copyEdgeDeviceToHost(); +#endif // defined(USE_GPU) + const vector &inUse = edges.getInUse(); const vector &weights = edges.getWeights(); const vector &sourceVertices = edges.getSourceVertexIndices();