41 if (P.physics_option != 0 && P.physics_option != 1)
return -1;
45 const int N_eq = P.N_eq;
46 const int i_mob = std::max(1, P.i_mobile);
47 const int v_mob = std::max(1, P.v_mobile);
48 const int he_off = I + V;
52 const int cons_off = P.cons_off;
53 const int n_he = cons_off - he_off;
56 std::vector<std::vector<int>> col_rows(N_eq);
58 auto add = [&](
int row,
int col) {
59 if (row < 0 || row >= N_eq || col < 0 || col >= N_eq)
return;
60 col_rows[col].push_back(row);
64 auto mark_dense_col = [&](
int col) {
65 for (
int r = 0; r < N_eq; ++r) add(r, col);
69 for (
int j = 0; j < std::min(i_mob, I); ++j) mark_dense_col(j);
72 for (
int j = I; j < I + std::min(v_mob, V); ++j) mark_dense_col(j);
75 for (
int j = he_off; j < he_off + n_he; ++j) mark_dense_col(j);
85 for (
int r = 0; r < I; ++r) {
86 const int j_lo = std::max(0, r - i_mob);
87 const int j_hi = std::min(I - 1, r + v_mob);
88 for (
int j = j_lo; j <= j_hi; ++j) {
89 if (j < i_mob)
continue;
93 if (r - 1 >= i_mob) add(r, r - 1);
94 if (r + 1 < I) add(r, r + 1);
100 for (
int j = I + v_mob; j < I + V; ++j) add(r, j);
110 for (
int m = 1; m <= V; ++m) {
111 const int r = I + m - 1;
112 const int m_lo = std::max(1, m - v_mob);
113 const int m_hi = std::min(V, m + i_mob);
114 for (
int mm = m_lo; mm <= m_hi; ++mm) {
115 const int j = I + mm - 1;
116 if (j < I + v_mob)
continue;
119 if (m - 1 >= 1 + v_mob) add(r, I + m - 2);
120 if (m + 1 <= V) add(r, I + m);
125 for (
int r = he_off; r < he_off + n_he; ++r) {
126 for (
int j = I; j < I + V; ++j) add(r, j);
127 for (
int j = he_off; j < he_off + n_he; ++j) add(r, j);
133 for (
int r = cons_off; r < cons_off + 5; ++r) {
134 for (
int j = 0; j < I; ++j) add(r, j);
135 for (
int j = I; j < I + V; ++j) add(r, j);
136 for (
int j = he_off; j < he_off + n_he; ++j) add(r, j);
147 if (P.loop_conversion) {
148 const int s0 = P.sia100_off;
149 const int i_mob_c = std::min(i_mob, I);
150 for (
int r = 0; r < I; ++r) {
151 const int r100 = s0 + r;
153 if (r - 1 >= 0) add(r100, s0 + (r - 1));
154 if (r + 1 < I) add(r100, s0 + (r + 1));
155 for (
int n = 1; n <= i_mob && r - n >= 0; ++n)
156 add(r100, s0 + (r - n));
163 for (
int n = 0; n < i_mob_c; ++n) add(n, r100);
164 for (
int rc = cons_off; rc < cons_off + 5; ++rc) add(rc, r100);
169 for (
int j = 0; j < N_eq; ++j) add(j, j);
174 for (
int j = 0; j < N_eq; ++j) {
175 auto& v = col_rows[j];
176 std::sort(v.begin(), v.end());
177 v.erase(std::unique(v.begin(), v.end()), v.end());
178 nnz +=
static_cast<int>(v.size());
182 P.jac_col_ptr.assign(N_eq + 1, 0);
183 P.jac_row_idx.assign(nnz, 0);
185 for (
int j = 0; j < N_eq; ++j) {
186 P.jac_col_ptr[j] = pos;
187 for (
int r : col_rows[j]) P.jac_row_idx[pos++] = r;
189 P.jac_col_ptr[N_eq] = pos;
201 const int N =
static_cast<int>(P.jac_col_ptr.size()) - 1;
202 P.jac_colors.assign(N, -1);
205 int nnz = P.jac_col_ptr[N];
206 std::vector<int> row_count(N, 0);
207 for (
int k = 0; k < nnz; ++k) row_count[P.jac_row_idx[k]]++;
208 std::vector<int> row_ptr(N + 1, 0);
209 for (
int i = 0; i < N; ++i) row_ptr[i + 1] = row_ptr[i] + row_count[i];
210 std::vector<int> row_cols(nnz);
211 std::vector<int> row_fill(N, 0);
212 for (
int j = 0; j < N; ++j) {
213 for (
int k = P.jac_col_ptr[j]; k < P.jac_col_ptr[j + 1]; ++k) {
214 int i = P.jac_row_idx[k];
215 row_cols[row_ptr[i] + row_fill[i]++] = j;
221 std::vector<int> order(N);
222 for (
int j = 0; j < N; ++j) order[j] = j;
223 std::sort(order.begin(), order.end(), [&](
int a,
int b) {
224 int da = P.jac_col_ptr[a + 1] - P.jac_col_ptr[a];
225 int db = P.jac_col_ptr[b + 1] - P.jac_col_ptr[b];
229 std::vector<int> forbidden;
231 for (
int j : order) {
232 forbidden.assign(n_colors, 0);
233 for (
int k = P.jac_col_ptr[j]; k < P.jac_col_ptr[j + 1]; ++k) {
234 int i = P.jac_row_idx[k];
237 for (
int p = row_ptr[i]; p < row_ptr[i + 1]; ++p) {
238 int jj = row_cols[p];
239 int c = P.jac_colors[jj];
241 if (c >=
static_cast<int>(forbidden.size()))
242 forbidden.resize(c + 1, 0);
248 for (
int c = 0; c < static_cast<int>(forbidden.size()); ++c)
249 if (!forbidden[c]) { chosen = c;
break; }
250 if (chosen < 0) chosen = n_colors++;
251 P.jac_colors[j] = chosen;
252 if (chosen >= n_colors) n_colors = chosen + 1;
254 P.jac_n_colors = n_colors;
284 SUNMatrix Jac,
void* user_data,
285 N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
289 const int N = P.N_eq;
291 double* y_p = N_VGetArrayPointer(y);
292 double* f0 = N_VGetArrayPointer(fy);
293 double* y_pert = N_VGetArrayPointer(tmp1);
294 double* f1 = N_VGetArrayPointer(tmp2);
295 double* delta = N_VGetArrayPointer(tmp3);
299 sunindextype* col_ptr = SUNSparseMatrix_IndexPointers(Jac);
300 sunindextype* row_idx = SUNSparseMatrix_IndexValues (Jac);
301 sunrealtype* data = SUNSparseMatrix_Data (Jac);
306 const double sqrt_eps = std::sqrt(std::numeric_limits<double>::epsilon());
308 for (
int c = 0; c < P.jac_n_colors; ++c) {
310 std::fill(delta, delta + N, 0.0);
317 const int g_lo = P.jac_color_offsets[c];
318 const int g_hi = P.jac_color_offsets[c + 1];
319 for (
int g = g_lo; g < g_hi; ++g) {
320 int j = P.jac_color_groups[g];
321 double scale = std::max(std::abs(y_p[j]),
322 std::max(P.atol, 1e-30));
323 delta[j] = sqrt_eps * scale;
327 for (
int i = 0; i < N; ++i) y_pert[i] = y_p[i] + delta[i];
330 N_Vector y_pert_vec = tmp1;
331 N_Vector f1_vec = tmp2;
332 if (ud->
rhs_fn(0.0, y_pert_vec, f1_vec, user_data) != 0)
336 for (
int g = g_lo; g < g_hi; ++g) {
337 int j = P.jac_color_groups[g];
338 double inv_d = 1.0 / delta[j];
339 for (sunindextype k = col_ptr[j]; k < col_ptr[j + 1]; ++k) {
340 int i =
static_cast<int>(row_idx[k]);
341 data[k] = (f1[i] - f0[i]) * inv_d;