@@ -80,25 +80,71 @@ auto get_block_variable_by_name(BlockType& block, const std::string& var_name) {
8080 }
8181}
8282
83+ // Helper to reset ghost for a variable by name
84+ template <typename BlockType, typename VariablesTuple, std::size_t Index>
85+ void reset_ghost_for_variable_by_name_impl (BlockType& block, const std::string& var_name) {
86+ using CurrentVar = std::tuple_element_t <Index, VariablesTuple>;
87+
88+ // Check if current variable's name matches
89+ if (var_name == std::string (CurrentVar::name)) {
90+ block.template reset_ghost_for_variable <CurrentVar>();
91+ return ;
92+ }
93+
94+ // Recurse to next variable if not last
95+ if constexpr (Index + 1 < std::tuple_size_v<VariablesTuple>) {
96+ reset_ghost_for_variable_by_name_impl<BlockType, VariablesTuple, Index + 1 >(block, var_name);
97+ } else {
98+ throw std::runtime_error (" Unknown variable name: " + var_name);
99+ }
100+ }
101+
102+ // Helper function to reset ghost for a variable by name
103+ template <typename BlockType>
104+ void reset_ghost_for_variable_by_name (BlockType& block, const std::string& var_name) {
105+ using VariablesTuple = typename BlockType::Variables;
106+
107+ if constexpr (std::tuple_size_v<VariablesTuple> > 0 ) {
108+ reset_ghost_for_variable_by_name_impl<BlockType, VariablesTuple, 0 >(block, var_name);
109+ } else {
110+ throw std::runtime_error (" System has no variables" );
111+ }
112+ }
113+
83114// Helper to convert Eigen Block view to numpy array
84115template <typename BlockExpr>
85116py::array_t <double > block_to_numpy (BlockExpr&& block_expr, py::object parent) {
86117 // Evaluate the expression to get dimensions
87118 auto rows = static_cast <py::ssize_t >(block_expr.rows ());
88119 auto cols = static_cast <py::ssize_t >(block_expr.cols ());
89120
90- // Compute strides based on storage order
91- auto strides = compute_strides (
92- static_cast <std::size_t >(rows),
93- static_cast <std::size_t >(cols)
94- );
121+ // Get actual strides from the Eigen Block expression
122+ // For Eigen Blocks, innerStride() is the stride between elements in the same row/column
123+ // and outerStride() is the stride between rows/columns depending on storage order
124+ // For column-major: innerStride() = 1 (between rows), outerStride() = underlying_rows (between columns)
125+ // For row-major: innerStride() = 1 (between columns), outerStride() = underlying_cols (between rows)
126+ auto inner_stride = static_cast <py::ssize_t >(block_expr.innerStride () * sizeof (double ));
127+ auto outer_stride = static_cast <py::ssize_t >(block_expr.outerStride () * sizeof (double ));
128+
129+ // For numpy, strides are in bytes and represent the step size for each dimension
130+ // For column-major (Eigen default): row_stride = inner_stride, col_stride = outer_stride
131+ // For row-major: row_stride = outer_stride, col_stride = inner_stride
132+ py::ssize_t row_stride, col_stride;
133+ if constexpr (IsColMajor) {
134+ // Column-major: stride between rows is inner_stride, between columns is outer_stride
135+ row_stride = inner_stride;
136+ col_stride = outer_stride;
137+ } else {
138+ // Row-major: stride between rows is outer_stride, between columns is inner_stride
139+ row_stride = outer_stride;
140+ col_stride = inner_stride;
141+ }
95142
96- // Create numpy array view (non-owning)
143+ // Create numpy array view (non-owning) with correct strides
97144 return py::array_t <double >(
98145 {rows, cols},
99- {static_cast <py::ssize_t >(strides.first ),
100- static_cast <py::ssize_t >(strides.second )},
101- block_expr.data (),
146+ {row_stride, col_stride},
147+ const_cast <double *>(block_expr.data ()),
102148 parent // Keep parent object alive
103149 );
104150}
@@ -261,6 +307,65 @@ PYBIND11_MODULE(_memory_block, m) {
261307
262308 This operation updates the dynamic variables including forces
263309 and torques based on the current state.
310+ )pbdoc" )
311+ .def_property_readonly (" ghost_nodes_idx" , [](const BlockRodSystem& block) {
312+ auto indices = block.ghost_nodes_idx ();
313+ // Convert to numpy array (pybind11 will handle the conversion automatically)
314+ return py::cast (indices);
315+ },
316+ R"pbdoc(
317+ Get indices of ghost nodes between rods.
318+
319+ Returns:
320+ numpy.ndarray: An array of ghost node indices (length: n_rods - 1).
321+ The array does not own the data.
322+ )pbdoc" ,
323+ py::keep_alive<0 , 1 >())
324+ .def_property_readonly (" ghost_elems_idx" , [](const BlockRodSystem& block) {
325+ auto indices = block.ghost_elems_idx ();
326+ // Convert to numpy array (pybind11 will handle the conversion automatically)
327+ return py::cast (indices);
328+ },
329+ R"pbdoc(
330+ Get indices of ghost elements between rods.
331+
332+ Returns:
333+ numpy.ndarray: An array of ghost element indices (length: 2 * (n_rods - 1)).
334+ The array does not own the data.
335+ )pbdoc" ,
336+ py::keep_alive<0 , 1 >())
337+ .def_property_readonly (" ghost_voronoi_idx" , [](const BlockRodSystem& block) {
338+ auto indices = block.ghost_voronoi_idx ();
339+ // Convert to numpy array (pybind11 will handle the conversion automatically)
340+ return py::cast (indices);
341+ },
342+ R"pbdoc(
343+ Get indices of ghost voronoi nodes between rods.
344+
345+ Returns:
346+ numpy.ndarray: An array of ghost voronoi indices (length: 3 * (n_rods - 1)).
347+ The array does not own the data.
348+ )pbdoc" ,
349+ py::keep_alive<0 , 1 >())
350+ .def (" reset_ghost_for_variable" , [](BlockRodSystem& block, const std::string& var_name) {
351+ // Helper to reset ghost for a variable by name
352+ reset_ghost_for_variable_by_name (block, var_name);
353+ },
354+ R"pbdoc(
355+ Reset ghost values for a specific variable by name.
356+
357+ Args:
358+ var_name: Name of the variable (e.g., "position", "velocity", "director")
359+ )pbdoc" ,
360+ py::arg (" var_name" ))
361+ .def (" reset_ghost" , [](BlockRodSystem& block) {
362+ block.reset_ghost ();
363+ },
364+ R"pbdoc(
365+ Reset ghost values for all variables.
366+
367+ This operation sets all ghost node/element/voronoi values to their
368+ default ghost_value as defined in each variable type.
264369 )pbdoc" );
265370
266371 // BlockView class
0 commit comments