Skip to content

Commit 7647735

Browse files
performant version
1 parent da7d54e commit 7647735

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ The codebase is organized into several modules, each handling different aspects
334334

335335
4. **Analyze Results:**
336336

337-
- If instead you want to re-solve for an existing solution from a `DataFrame` dataset, you can use the `solve_row` function.
337+
- If instead you want to re-solve for an existing solution from a `DataFrame` dataset, you can use the `solve_row` method.
338338

339339
```julia
340340
#- Activate the project
@@ -366,6 +366,35 @@ The codebase is organized into several modules, each handling different aspects
366366
LpA = sol[:LpA]
367367
```
368368

369+
**For High-Throughput Analysis:** If you need to solve many rows from the same `DataFrame` efficiently, use the performant version that returns a solver function. This is useful for loops or parallel processing.
370+
371+
```julia
372+
# Create a performant solver function (one-time setup)
373+
fast_solver = solve_row(results_df, fullrn)
374+
375+
# Now solve any row efficiently
376+
sol1 = fast_solver(1) # Solve first row
377+
sol42 = fast_solver(42) # Solve 42nd row
378+
sol1000 = fast_solver(1000) # Solve 1000th row
379+
380+
# Perfect for loops or parallel processing
381+
solutions = [fast_solver(i) for i in 1:100] # Solve first 100 rows
382+
383+
# Or for specific analysis
384+
interesting_rows = [1, 42, 100, 500, 1000]
385+
interesting_solutions = [fast_solver(i) for i in interesting_rows]
386+
```
387+
388+
**Performance Benefits:**
389+
- **One-time setup cost**: Column extraction and setter creation happens once
390+
- **Fast repeated solves**: Uses pre-extracted matrices and SymbolicIndexingInterface
391+
- **Thread-safe**: Each call creates isolated problem copies
392+
- **Memory efficient**: Uses `view()` for zero-copy matrix access
393+
394+
**When to Use Each Method:**
395+
- **`solve_row(row, odeprob)`**: For interactive use, single solves, or when you have individual rows
396+
- **`solve_row(df, odeprob)`**: For high-throughput workflows, loops, or when you need to solve many rows from the same DataFrame
397+
```
369398
370399
371400

src/utils/datahandling.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,26 @@ function solve_row(data::AbstractDataFrame, odeprob::ODEProblem; tspan = (0.0, 2
7979
parameter_cols = r"k|DF"
8080
species_cols = r"^(L|K|P|A|B|C|D)$"
8181

82+
# Pre-extract data to matrices for fast indexing
83+
param_matrix = Matrix(data[!, parameter_cols])
84+
species_matrix = Matrix(data[!, species_cols])
85+
8286
# Create fast setters
8387
set_params = setp(odeprob, parameter_cols)
8488
set_species = setu(odeprob, species_cols)
8589

8690
# Return function that uses fast setters
8791
return function(row_index::Int; kwargs...)
88-
# Get the row
89-
row = data[row_index, :]
90-
91-
# Set the parameters and species
92-
set_params(odeprob, row[parameter_cols])
93-
set_species(odeprob, row[species_cols])
94-
92+
93+
# Create thread-safe problem copy
94+
prob = remake(odeprob, p = copy(odeprob.p), u0 = copy(odeprob.u0))
95+
96+
# Set the parameters and species using fast matrix indexing
97+
set_params(prob, view(param_matrix, row_index, :))
98+
set_species(prob, view(species_matrix, row_index, :))
99+
95100
# Solve and return
96-
return solve(odeprob, Rodas5P(autodiff = AutoForwardDiff(chunksize = length(odeprob.u0))), abstol = abstol, reltol = reltol, tspan = tspan, kwargs...)
101+
return solve(prob, Rodas5P(autodiff = AutoForwardDiff(chunksize = length(odeprob.u0))), abstol = abstol, reltol = reltol, tspan = tspan, kwargs...)
97102
end
98103
end
99104

0 commit comments

Comments
 (0)