/* This is the DC netlist solver. It prepares the circuit list and solves it then. */ int dcsolver::solve (void) { // fetch simulation properties saveOPs |= !strcmp (getPropertyString ("saveOPs"), "yes") ? SAVE_OPS : 0; saveOPs |= !strcmp (getPropertyString ("saveAll"), "yes") ? SAVE_ALL : 0; char * solver = getPropertyString ("Solver"); // initialize node voltages, first guess for non-linear circuits and // generate extra circuits if necessary init (); setCalculation ((calculate_func_t) &calc); // start the iterative solver solve_pre (); // choose a solver if (!strcmp (solver, "CroutLU")) eqnAlgo = ALGO_LU_DECOMPOSITION_CROUT; else if (!strcmp (solver, "DoolittleLU")) eqnAlgo = ALGO_LU_DECOMPOSITION_DOOLITTLE; else if (!strcmp (solver, "HouseholderQR")) eqnAlgo = ALGO_QR_DECOMPOSITION; else if (!strcmp (solver, "HouseholderLQ")) eqnAlgo = ALGO_QR_DECOMPOSITION_LS; else if (!strcmp (solver, "GolubSVD")) eqnAlgo = ALGO_SV_DECOMPOSITION; // local variables for the fallback thingies int retry = -1, error, fallback = 0, preferred; int helpers[] = { CONV_SourceStepping, CONV_GMinStepping, CONV_SteepestDescent, CONV_LineSearch, CONV_Attenuation, -1 }; // is a certain convergence helper requested? char * helper = getPropertyString ("convHelper"); convHelper = CONV_None; if (!strcmp (helper, "LineSearch")) { convHelper = CONV_LineSearch; } else if (!strcmp (helper, "SteepestDescent")) { convHelper = CONV_SteepestDescent; } else if (!strcmp (helper, "Attenuation")) { convHelper = CONV_Attenuation; } else if (!strcmp (helper, "gMinStepping")) { convHelper = CONV_GMinStepping; } else if (!strcmp (helper, "SourceStepping")) { convHelper = CONV_SourceStepping; } preferred = convHelper; if (!subnet->isNonLinear ()) { // Start the linear solver. convHelper = CONV_None; error = solve_linear (); } else do { // Run the DC solver once. try_running () { applyNodeset (); error = solve_nonlinear (); #if DEBUG if (!error) { logprint (LOG_STATUS, "NOTIFY: %s: convergence reached after %d iterations\n", getName (), iterations); } #endif /* DEBUG */ if (!error) retry = -1; } // Appropriate exception handling. catch_exception () { case EXCEPTION_NO_CONVERGENCE: pop_exception (); if (preferred == helpers[fallback] && preferred) fallback++; convHelper = helpers[fallback++]; if (convHelper != -1) { logprint (LOG_ERROR, "WARNING: %s: %s analysis failed, using fallback " "#%d (%s)\n", getName (), getDescription (), fallback, getHelperDescription ()); retry++; restart (); } else { retry = -1; } break; default: // Otherwise return. estack.print (); error++; break; } } while (retry != -1); // save results and cleanup the solver saveOperatingPoints (); saveResults ("V", "I", saveOPs); solve_post (); return 0; }
// asynchronous step solver int e_trsolver::stepsolve_async(nr_double_t steptime) { // Start to sweep through time. int error = 0; convError = 0; time = steptime; // update the interpolation time of any externally controlled // components which require it. updateExternalInterpTime(time); // make the stored histories for all ircuits that have // requested them at least as long as the next major time // step so we can reject the step later if needed and // restore all the histories to their previous state updateHistoryAges (time - lastasynctime); //delta = (steptime - time) / 10; //if (progress) logprogressbar (i, swp->getSize (), 40); #if DEBUG && 0 messagefcn (LOG_STATUS, "NOTIFY: %s: solving netlist for t = %e\n", getName (), (double) time); #endif do { #if STEPDEBUG if (delta == deltaMin) { messagefcn (LOG_ERROR, "WARNING: %s: minimum delta h = %.3e at t = %.3e\n", getName (), (double) delta, (double) current); } #endif // update the integration coefficients updateCoefficients (delta); // Run predictor to get a start value for the solution vector for // the successive iterative corrector process error += predictor (); // restart Newton iteration if (rejected) { restart (); // restart non-linear devices rejected = 0; } // Run corrector process with appropriate exception handling. // The corrector iterates through the solutions of the integration // process until a certain error tolerance has been reached. try_running () // #defined as: do { { error += corrector (); } catch_exception () // #defined as: } while (0); if (estack.top ()) switch (estack.top()->getCode ()) { case EXCEPTION_NO_CONVERGENCE: pop_exception (); // Reduce step-size (by half) if failed to converge. if (current > 0) current -= delta; delta /= 2; if (delta <= deltaMin) { delta = deltaMin; adjustOrder (1); } if (current > 0) current += delta; // Update statistics. statRejected++; statConvergence++; rejected++; converged = 0; error = 0; // Start using damped Newton-Raphson. convHelper = CONV_SteepestDescent; convError = 2; #if DEBUG messagefcn (LOG_ERROR, "WARNING: delta rejected at t = %.3e, h = %.3e " "(no convergence)\n", (double) saveCurrent, (double) delta); #endif break; default: // Otherwise return. estack.print (); error++; break; } if (error) return -1; if (rejected) continue; // check whether Jacobian matrix is still non-singular if (!A->isFinite ()) { messagefcn (LOG_ERROR, "ERROR: %s: Jacobian singular at t = %.3e, " "aborting %s analysis\n", getName (), (double) current, getDescription ().c_str()); return -1; } // Update statistics and no more damped Newton-Raphson. statIterations += iterations; if (--convError < 0) convHelper = 0; // Now advance in time or not... if (running > 1) { adjustDelta (time); adjustOrder (); } else { fillStates (); nextStates (); rejected = 0; } saveCurrent = current; current += delta; running++; converged++; // Tell integrators to be running. setMode (MODE_NONE); // Initialize or update history. if (running > 1) { updateHistory (saveCurrent); } else { initHistory (saveCurrent); } } while (saveCurrent < time); // Hit a requested time point? return 0; }
int nasolver<nr_type_t>::solve_once (void) { qucs::exception * e; int error = 0, d; // run the calculation function for each circuit calculate (); // generate A matrix and z vector createMatrix (); // solve equation system try_running () { runMNA (); } // appropriate exception handling catch_exception () { case EXCEPTION_PIVOT: case EXCEPTION_WRONG_VOLTAGE: e = new qucs::exception (EXCEPTION_NA_FAILED); d = top_exception()->getData (); pop_exception (); if (d >= countNodes ()) { d -= countNodes (); e->setText ("voltage source `%s' conflicts with some other voltage " "source", findVoltageSource(d)->getName ()); } else { e->setText ("circuit admittance matrix in %s solver is singular at " "node `%s' connected to [%s]", desc.c_str(), nlist->get (d).c_str(), nlist->getNodeString (d).c_str()); } throw_exception (e); error++; break; case EXCEPTION_SINGULAR: do { d = top_exception()->getData (); pop_exception (); if (d < countNodes ()) { logprint (LOG_ERROR, "WARNING: %s: inserted virtual resistance at " "node `%s' connected to [%s]\n", getName (), nlist->get (d).c_str(), nlist->getNodeString (d).c_str()); } } while (top_exception() != NULL && top_exception()->getCode () == EXCEPTION_SINGULAR); break; default: estack.print (); break; } // save results into circuits if (!error) saveSolution (); return error; }
/* synchronous step solver for external ode routine * * This function solves the circuit for a single time delta provided * by an external source. Convergence issues etc. are expected to * be handled by the external solver, as it is in full control of the * time stepping. */ int e_trsolver::stepsolve_sync(nr_double_t synctime) { int error = 0; convError = 0; time = synctime; // update the interpolation time of any externally controlled // components which require it. updateExternalInterpTime(time); // copy the externally chosen time step to delta delta = time - lastsynctime; // get the current solution time //current += delta; // updates the integrator coefficients, and updates the array of prev // 8 deltas with the new delta for this step updateCoefficients (delta); // Run predictor to get a start value for the solution vector for // the successive iterative corrector process error += predictor (); // restart Newton iteration restart (); // restart non-linear devices // Attempt to solve the circuit with the given delta try_running () // #defined as: do { { //error += solve_nonlinear_step (); error += corrector (); } catch_exception () // #defined as: } while (0); if (estack.top ()) switch (estack.top()->getCode ()) { case EXCEPTION_NO_CONVERGENCE: pop_exception (); // Retry using damped Newton-Raphson. this->convHelper = CONV_SteepestDescent; convError = 2; #if DEBUG messagefcn (LOG_ERROR, "WARNING: delta rejected at t = %.3e, h = %.3e " "(no convergence)\n", (double) saveCurrent, (double) delta); #endif try_running () // #defined as: do { { // error += solve_nonlinear_step (); error += solve_nonlinear (); } catch_exception () // #defined as: } while (0); if (estack.top ()) switch (estack.top()->getCode ()) { case EXCEPTION_NO_CONVERGENCE: pop_exception (); // Update statistics. statRejected++; statConvergence++; rejected++; converged = 0; error = 0; break; default: // Otherwise return. estack.print (); error++; break; } // Update statistics and no more damped Newton-Raphson. // statIterations += iterations; // if (--convError < 0) this->convHelper = 0; break; default: // Otherwise return. estack.print (); error++; break; } // if there was an error other than non-convergence, return -1 if (error) return -1; // check whether Jacobian matrix is still non-singular if (!A->isFinite ()) { // messagefcn (LOG_ERROR, "ERROR: %s: Jacobian singular at t = %.3e, " // "aborting %s analysis\n", getName (), (double) current, // getDescription ()); return -1; } return 0; }