Building Catalyst.jl reaction network from a .csv file - error in construction?

Hey Julia crew!

I am trying to import a reaction network from a .csv file to use with Catalyst.jl via Reaction NetworkImporters.jl.

I have been able to successfully construct a ReactionSystem object which can print itself using latexify, but additional commands fail with MethodErrors.

Here is a minimal example:

using Pkg
Pkg.activate(".")
using Catalyst, OrdinaryDiffEq, Plots, Latexify, CSV, DataFrames, ReactionNetworkImporters, GraphMakie, CairoMakie, NetworkLayout



function read_CRN(csvfile::String)
  """
  read_CRN(csvfile::String)

  Reads a CSV file containing the net reaction stoichiometry (products - reactants) and returns 
  two DataFrames containing substrate and product stoichiometry matrices, as well as a 
  numeric vector of rate constants from the first column.

  ### Arguments
  - `csvfile::String`: The path to the input CSV file. The file should have a non-numeric 
    first column (rate constants) and numeric data in subsequent columns, where each row represents a reaction.

  ### Returns
  - `product_matrix::Matrix{Int64}`: A transposed matrix with the stoichiometric coefficients of the products in each reaction.
  - `substrate_matrix::Matrix{Float64}`: A transposed matrix with the stoichiometric coefficients of the substrates in each reaction.
  - `rate_constants::Vector{Float64}`: A numeric vector containing the rate constants from the first column of the CSV.
  - `species::Vector{String}`: A vector of species names corresponding to the columns in the stoichiometry matrix.
  - `m_reactions::Int`: The number of reactions.
  - `n_species::Int`: The number of species.

  ### Example
  product_matrix, substrate_matrix, rate_constants, species, m_reactions, n_species = read_CRN("path/to/file.csv")

  """
  
  # Read the CSV file into a DataFrame
  data = CSV.read(csvfile, DataFrame)
  species = names(data)[2:end]
  rate_constants = Vector{Float64}(data[!, 1])

  data_matrix = Matrix{Float64}(data[:, 2:end])

  product_matrix = max.(data_matrix, 0)
  substrate_matrix = -min.(data_matrix, 0)

  # Transpose the product and substrate matrices for compatibility with catalyst.jl
  product_matrix = Matrix(transpose(product_matrix))
  substrate_matrix = Matrix(transpose(substrate_matrix))

  # Get the number of reactions (rows) and species (columns)
  m_reactions = size(data_matrix, 1)  # Number of reactions (rows)
  n_species = size(data_matrix, 2)    # Number of species (columns)

  # Convert the product matrix to integers
  product_matrix = convert(Matrix{Int}, product_matrix)

  # Return the transposed matrices, rate constants, species names, number of reactions, and number of species
  return product_matrix, substrate_matrix, rate_constants, species, m_reactions, n_species
end


(prod, sub, k, species, m_reactions, n_species) = read_CRN("test_CRN.csv")

@species S(t)[1:n_species]  
@parameters k[1:m_reactions]
@variables t

# Collect to a Vector{Num} type
pars = collect(k)
species = collect(S)

# Create the MatrixNetwork with correct types
mn = MatrixNetwork(pars, sub, prod; species=species, params=pars)

prn = loadrxnetwork(mn)
rn = prn.rn
latexify(rn)

When run on a .csv file with this contents:

rate S1 S2 S3
1 -2 1 0
2 2 -1 0
3 -1 -1 1
4 1 1 -1
5 3 0 -3

The expected latex is printed (edited here to render properly):

\begin{align*} 2.0 \mathrm{\mathtt{S_1}} &\leftrightarrow \mathrm{\mathtt{S_2}} \quad (k_1, k_2) \\ \mathrm{\mathtt{S_1}} + \mathrm{\mathtt{S_2}} &\leftrightarrow \mathrm{\mathtt{S_3}} \quad (k_3, k_4) \\ 3.0 \mathrm{\mathtt{S_3}} &\rightarrow 3.0 \mathrm{\mathtt{S_1}} \quad (k_5) \end{align*}

However, the network has not been properly constructed. Using

plot_network(rn)

returns this system:

Further, any additional calls to other functions appear to fail. Here is an example:

deficiency(rn)
MethodError: no method matching exactdiv(::Float64, ::Float64)
The function `exactdiv` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  exactdiv(!Matched::Integer, ::Any)
   @ ModelingToolkit C:\.julia\packages\ModelingToolkit\Z9mEq\src\systems\alias_elimination.jl:376

All similar functions throw the same error (i.e. <method> exists but no method for this combination of argument types), which suggests that the ReactionSystem object was not actually constructed properly.


Does anyone have any advice for this issue?
I am using Catalyst 15.0.8. and ReactionNetworkImporters 0.16.1

Is your stoichiometry represented using floats instead of integers? You may need to convert that.

In a previous version I had issues with the dataframe automatically reading in as a Matrix{Float} instead of a Matrix{Int}, which causes MatrixNetwork() to fail. Either way I don’t think this is the root cause of the error…

It is missing a dispatch that is expecting an integer. So it does need to convert at some point.

Network analysis functions generally require integer stoichiometry, so they will fail if you aren’t creating a network with integer stochioimetric coefficients as Chris said.

The graph looks ok to me modulo that the species nodes are incorrectly labeled. That seems like a Catalyst bug with labeling graphs when using array species. I’ve opened an issue so we can hopefully get that fixed.

Awesome! Thanks!

In the future is it better to raise an issue directly or start with a discussion here? I figured that this did not relate to underlying functionality/structure of the code and was instead a user error which is why I posted here instead.

Issues are better for feature requests and/or bugs. Discourse is good for general usage questions.

1 Like