122122
123123function implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
124124 # Define the nonlinear system: F(u_new) = u_new - u_prev - sum(nu_j * (counts_j - tau * (a_j(u_prev) - a_j(u_new)))) = 0
125- function f (u_new, params )
126- rate_new = zeros (eltype (u_new) , numjumps)
125+ function f (u_new)
126+ rate_new = zeros (Float64 , numjumps)
127127 rate (rate_new, u_new, p, t_prev + tau)
128128 residual = u_new - u_prev
129129 for j in 1 : numjumps
@@ -132,19 +132,41 @@ function implicit_tau_step(u_prev, t_prev, tau, rate_cache, counts, nu, p, rate,
132132 return residual
133133 end
134134
135- # Initial guess
136- u_new = copy (u_prev)
137-
138- # Solve the nonlinear system
139- prob = NonlinearProblem (f, u_new, nothing )
140- sol = solve (prob, SimpleNewtonRaphson ())
141-
142- # Check for convergence and numerical stability
143- if sol. retcode != ReturnCode. Success || any (isnan .(sol. u)) || any (isinf .(sol. u))
144- return nothing # Signal failure to trigger tau halving
135+ # Compute Jacobian using finite differences
136+ function compute_jacobian (u_new)
137+ n = length (u_new)
138+ J = zeros (Float64, n, n)
139+ h = 1e-6
140+ f_u = f (u_new)
141+ for j in 1 : n
142+ u_pert = copy (u_new)
143+ u_pert[j] += h
144+ f_pert = f (u_pert)
145+ J[:, j] = (f_pert - f_u) / h
146+ end
147+ return J
145148 end
146149
147- return round .(Int, max .(sol. u, 0.0 ))
150+ # Inline Newton-Raphson
151+ u_new = float .(u_prev + sum (nu[:, j] * counts[j] for j in 1 : numjumps)) # Initial guess: explicit step
152+ tol = 1e-6
153+ maxiters = 100
154+ for iter in 1 : maxiters
155+ F = f (u_new)
156+ if norm (F) < tol
157+ return round .(Int, max .(u_new, 0.0 )) # Converged
158+ end
159+ J = compute_jacobian (u_new)
160+ if abs (det (J)) < 1e-10 # Check for singular Jacobian
161+ return nothing # Signal failure
162+ end
163+ delta = J \ F
164+ u_new -= delta
165+ if any (isnan .(u_new)) || any (isinf .(u_new))
166+ return nothing # Signal failure
167+ end
168+ end
169+ return nothing # Failed to converge
148170end
149171
150172function DiffEqBase. solve (jump_prob:: JumpProblem , alg:: SimpleImplicitTauLeaping ; seed= nothing , dtmin= 1e-10 , saveat= nothing )
@@ -216,7 +238,6 @@ function DiffEqBase.solve(jump_prob::JumpProblem, alg::SimpleImplicitTauLeaping;
216238 continue
217239 end
218240 else
219- # Implicit update using NonlinearSolve
220241 u_new = implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
221242 if u_new === nothing || any (u_new .< 0 )
222243 # Halve tau to avoid negative populations, as per Cao et al. (2006, J. Chem. Phys., DOI: 10.1063/1.2159468)
0 commit comments