diff --git a/R/Aaaa.R b/R/Aaaa.R index 8821d8b8..f3886224 100644 --- a/R/Aaaa.R +++ b/R/Aaaa.R @@ -106,7 +106,8 @@ Reserved_cvar <- c("SOLVERTIME","table","ETA","EPS", "AMT", "CMT", "NEWIND", "DONE", "CFONSTOP", "DXDTZERO", "CFONSTOP","INITSOLV","_F", "_R","_ALAG", "SETINIT", "report", "_VARS_", "VARS", - "SS_ADVANCE", "END_OF_INFUSION", "CHECK_MODELED_INFUSIONS") + "SS_ADVANCE", "END_OF_INFUSION", "CHECK_MODELED_INFUSIONS", + "FINAL_ROW", "FINAL_IROW") Reserved <- c("ID", "amt", "cmt", "ii", "ss", "evid", "addl", "rate","time", Reserved_cvar, diff --git a/inst/base/modelheader.h b/inst/base/modelheader.h index ced854e5..ce7ffb63 100644 --- a/inst/base/modelheader.h +++ b/inst/base/modelheader.h @@ -92,6 +92,10 @@ typedef double capture; #define THETA(a) THETA##a // Should modeled infusion parameters get checked #define CHECK_MODELED_INFUSIONS _check_modeled_infusions +// Check for final record of the simulation +#define FINAL_ROW (self.rown == (self.nrow-1)) +// Check for final record of current individual +#define FINAL_IROW (self.irown == (self.inrow-1)) // NMVARS #ifdef _MRGSOLVE_USING_NM_VARS_ diff --git a/inst/maintenance/unit/test-rown-nrow.R b/inst/maintenance/unit/test-rown-nrow.R index ba13507f..275d1d69 100644 --- a/inst/maintenance/unit/test-rown-nrow.R +++ b/inst/maintenance/unit/test-rown-nrow.R @@ -234,19 +234,33 @@ test_that("individual row counters work with PRED model", { # https://github.com/metrumresearchgroup/mrgsolve/pull/1323 code_counter_update_on_output <- ' -$preamble capture total1 = 0; capture total2 = 0; -$main self.mtime(12); +$preamble +capture total1 = 0; capture total2 = 0; +capture total3 = 0; capture total4 = 0; +capture total5 = 0; + +$main +self.mtime(1.2); self.mtime(2.9); +self.mtime(11); self.mtime(12); self.mtime(24); + $table if(self.rown+1==self.nrow) ++total1; if(self.nid==self.idn+1 && self.irown+1 == self.inrow) ++total2; + +if(FINAL_ROW) ++total3; +if(FINAL_IROW) ++total4; + +if(self.irown+1==self.inrow) ++total5; + capture rown = self.rown; capture nrow = self.nrow; capture irown = self.irown; capture inrow = self.inrow; ' +mod <- mcode("counter-update-on-output", code_counter_update_on_output) + test_that("row counters are only updated on output records gh-1323", { - mod <- mcode("counter-update-on-output", code_counter_update_on_output) data <- expand.ev(amt = 0, cmt = 0, ID = 1:2) out <- mrgsim(mod, data = data, end = 24, delta = 24) expect_equal(nrow(out), 6) @@ -263,7 +277,47 @@ test_that("row counters are only updated on output records gh-1323", { expect_equal(out$total1[6], 1) expect_equal(out$total2[6], 1); + # Macros + expect_equal(out$total1, out$total3) + expect_equal(out$total4, out$total4) +}) + +test_that("more row counter macros gh-1327", { + data1 <- ev(amt = 0, cmt = 1, ID = 1) + data2 <- ev(amt = 0, cmt = 1, ID = 2) + + data1 <- expand_observations(data1, times = 1:5) + data2 <- expand_observations(data2, times = 1:8) + + data <- rbind(data1, data2) + data$cmt <- 0 + + out <- mrgsim_df(mod, data = data) + expect_equal(nrow(out), nrow(data)) + + out1 <- subset(out, ID==1) + + expect_equal(nrow(out1), 6) + expect_true(all(out1$inrow==6)) + expect_equal(out1$rown, out1$irown) + expect_equal(out1$total4[6], 1) + expect_equal(out1$total4, out1$total5) + expect_equal(out1$irown, seq(6)-1) + + expect_true(all(out1$total1==0)) + expect_true(all(out1$total3==0)) + + out2 <- subset(out, ID==2) + expect_equal(nrow(out2), 9) + expect_true(all(out2$inrow==9)) + expect_equal(out2$rown-6, out2$irown) + expect_equal(out2$total3[9], 1) + expect_equal(out2$total4, out2$total5) + expect_equal(out2$irown, seq(9)-1) + + expect_true(all(out2$total4[1:8]==1)) }) +rm(mod) rm(code_test_rown_nrow, code_test_rown_nrow_pred) rm(code_counter_update_on_output) diff --git a/src/devtran.cpp b/src/devtran.cpp index cb861e35..11a61861 100644 --- a/src/devtran.cpp +++ b/src/devtran.cpp @@ -427,7 +427,9 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, double tfrom = a[i].front()->time(); double tto = tfrom; - double maxtime = a[i].back()->time(); + + const double maxtime = a[i].back()->time(); + const int NNI = dat.inrow(i); for(int k=0; k < neta; ++k) prob.eta(k,eta(i,k)); for(int k=0; k < neps; ++k) prob.eps(k,eps(crow,k)); @@ -459,18 +461,22 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, Rcpp::checkUserInterrupt(); ic = prob.interrupt; } + + rec_ptr this_rec = a[i][j]; - if(crow == NN) continue; + this_rec->id(id); + tto = this_rec->time(); + + // TODO: simplify + if(icrow==NNI || crow==NN || tto > maxtime) { + continue; + } - rec_ptr this_rec = a[i][j]; - // Only update row counters on output records if(this_rec->output()) { prob.irown(icrow); prob.rown(crow); - } - - this_rec->id(id); + } if(prob.systemoff()) { // This starts a loop that will finish the remaining records @@ -483,8 +489,8 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, if(status==999) CRUMP("999 sent from the model."); if(this_rec->output()) { if(status==1) { - ans(crow,0) = this_rec->id(); - ans(crow,1) = this_rec->time(); + ans(crow,0) = id; + ans(crow,1) = tto; for(unsigned int k=0; k < n_capture; ++k) { ans(crow,(k+capture_start)) = prob.capture(capture[k]); } @@ -511,9 +517,7 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, &prob ); } - - tto = this_rec->time(); - + double dt = (tto-tfrom)/(tfrom == 0.0 ? 1.0 : tfrom); if((dt > 0.0) && (dt < mindt)) {