This is a kind of related to another issue: https://sourceforge.net/p/ngspice/patches/127/, According to the explaination there, CKTbreaks will have a minial size of 2, with both value to be CKTfinalTime.
if(ckt->CKTbreakSize >2) {
...
} else {
ckt->CKTbreaks[0] = ckt->CKTbreaks[1];
ckt->CKTbreaks[1] = ckt->CKTfinalTime;
}
In this case, if a new breakpoint is inserted and it is very close to CKTfinalTime, e.g. CKTfinalTime - a few ULPs, then in CKTsetBreak func, it will be inserted successfully, and the breakpoints will be {CKTfinalTime - a few ULPs, CKTfinalTime}.
for(i=0;i<ckt->CKTbreakSize;i++) {
if(ckt->CKTbreaks[i]>time) { /* passed */
if((ckt->CKTbreaks[i]-time) <= ckt->CKTminBreak) {
/* very close together - take earlier point */
ckt->CKTbreaks[i] = time;
return(OK);
}
If so, ckt->CKTbreaks[1] - ckt->CKTbreaks[0] = a few ULPs, and jt could cause ckt->CKTdelta to be set to 0.1 * the ULPs delta in Dctran and then leads simulation abort (see more details in https://sourceforge.net/p/ngspice/patches/127/).
A simple fix is to add a check to see if ckt->CKTbreaks[i] == ckt->CKTfinalTime. Please have a look on the patch.