def modify_x0_for_ic(circ, x0): """Modifies a supplied x0. """ if isinstance(x0, results.op_solution): x0 = x0.asmatrix() return_obj = True else: return_obj = False nv = len(circ.nodes_dict) # number of voltage variables voltage_defined_elements = [ x for x in circ if circuit.is_elem_voltage_defined(x) ] # setup voltages this may _not_ work properly for elem in circ: if isinstance(elem, devices.Capacitor) and elem.ic or \ isinstance(elem, diode.diode) and elem.ic: x0[elem.n1 - 1, 0] = x0[elem.n2 - 1, 0] + elem.ic # setup the currents for elem in voltage_defined_elements: if isinstance(elem, devices.Inductor) and elem.ic: x0[nv - 1 + voltage_defined_elements.index(elem), 0] = elem.ic if return_obj: xnew = results.op_solution(x=x0, \ error=numpy.mat(numpy.zeros(x0.shape)), circ=circ, outfile=None) xnew.netlist_file = None xnew.netlist_title = "Self-generated OP to be used as tran IC" else: xnew = x0 return xnew
def modify_x0_for_ic(circ, x0): """Modifies a supplied x0. """ if isinstance(x0, results.op_solution): x0 = x0.asmatrix() return_obj = True else: return_obj = False nv = len(circ.nodes_dict) # number of voltage variables voltage_defined_elements = [x for x in circ.elements if circuit.is_elem_voltage_defined(x)] # setup voltages this may _not_ work properly for elem in circ.elements: if isinstance(elem, devices.capacitor) and elem.ic or isinstance(elem, devices.diode) and elem.ic: x0[elem.n1 - 1, 0] = x0[elem.n2 - 1, 0] + elem.ic # setup the currents for elem in voltage_defined_elements: if isinstance(elem, devices.inductor) and elem.ic: x0[nv - 1 + voltage_defined_elements.index(elem), 0] = elem.ic if return_obj: xnew = results.op_solution(x=x0, error=numpy.mat(numpy.zeros(x0.shape)), circ=circ, outfile=None) xnew.netlist_file = None xnew.netlist_title = "Self-generated OP to be used as tran IC" else: xnew = x0 return xnew
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \ D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3): """Performs a transient analysis of the circuit described by circ. Important parameters: - tstep is the maximum step to be allowed during simulation. - print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first element of x will be printed out to step_and_lte.graph in the current directory. """ if data_filename == "stdout": verbose = 0 _debug = False if _debug: print_step_and_lte = True else: print_step_and_lte = False HMAX = tstep #check parameters if tstart > tstop: printing.print_general_error("tstart > tstop") sys.exit(1) if tstep < 0: printing.print_general_error("tstep < 0") sys.exit(1) if verbose > 4: tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \ (options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin) printing.print_info_line((tmpstr, 5), verbose) locked_nodes = circ.get_locked_nodes() if print_step_and_lte: flte = open("step_and_lte.graph", "w") flte.write("#T\tStep\tLTE\n") printing.print_info_line(("Starting transient analysis: ", 3), verbose) printing.print_info_line(("Selected method: %s" % (method,), 3), verbose) #It's a good idea to call transient with prebuilt MNA and N matrix #the analysis will be slightly faster (long netlists). if mna is None or N is None: (mna, N) = dc_analysis.generate_mna_and_N(circ) mna = utilities.remove_row_and_col(mna) N = utilities.remove_row(N, rrow=0) elif not mna.shape[0] == N.shape[0]: printing.print_general_error("mna matrix and N vector have different number of columns.") sys.exit(0) if D is None: # if you do more than one tran analysis, output streams should be changed... # this needs to be fixed D = generate_D(circ, [mna.shape[0], mna.shape[0]]) D = utilities.remove_row_and_col(D) # setup x0 if x0 is None: printing.print_info_line(("Generating x(t=%g) = 0" % (tstart,), 5), verbose) x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1))) opsol = results.op_solution(x=x0, error=x0, circ=circ, outfile=None) else: if isinstance(x0, results.op_solution): opsol = x0 x0 = x0.asmatrix() else: opsol = results.op_solution(x=x0, error=numpy.matrix(numpy.zeros((mna.shape[0], 1))), circ=circ, outfile=None) printing.print_info_line(("Using the supplied op as x(t=%g)." % (tstart,), 5), verbose) if verbose > 4: print "x0:" opsol.print_short() # setup the df method printing.print_info_line(("Selecting the appropriate DF ("+method+")... ", 5), verbose, print_nl=False) if method == IMPLICIT_EULER: import implicit_euler as df elif method == TRAP: import trap as df elif method == GEAR1: import gear as df df.order = 1 elif method == GEAR2: import gear as df df.order = 2 elif method == GEAR3: import gear as df df.order = 3 elif method == GEAR4: import gear as df df.order = 4 elif method == GEAR5: import gear as df df.order = 5 elif method == GEAR6: import gear as df df.order = 6 else: df = import_custom_df_module(method, print_out=(data_filename != "stdout")) # df is none if module is not found if df is None: sys.exit(23) if not df.has_ff() and use_step_control: printing.print_warning("The chosen DF does not support step control. Turning off the feature.") use_step_control = False #use_aposteriori_step_control = False printing.print_info_line(("done.", 5), verbose) # setup the data buffer # if you use the step control, the buffer has to be one point longer. # That's because the excess point is used by a FF in the df module to predict the next value. printing.print_info_line(("Setting up the buffer... ", 5), verbose, print_nl=False) ((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values() if max_x is None and max_dx is None: printing.print_general_error("df doesn't need any value?") sys.exit(1) if use_step_control: thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1, width=3) else: thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3) thebuffer.add((tstart, x0, None)) #setup the first values printing.print_info_line(("done.", 5), verbose) #FIXME #setup the output buffer if return_req_dict: output_buffer = dfbuffer(length=return_req_dict["points"], width=1) output_buffer.add((x0,)) else: output_buffer = None # import implicit_euler to be used in the first iterations # this is because we don't have any dx when we start, nor any past point value if (max_x is not None and max_x > 0) or max_dx is not None: import implicit_euler printing.print_info_line(("MNA (reduced):", 5), verbose) printing.print_info_line((str(mna), 5), verbose) printing.print_info_line(("D (reduced):", 5), verbose) printing.print_info_line((str(D), 5), verbose) # setup the initial values to start the iteration: x = None time = tstart nv = len(circ.nodes_dict) Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose) # lo step viene generato automaticamente, ma non superare mai quello fornito. if use_step_control: #tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin) tstep = min((tstop-tstart)/9999.0, HMAX) printing.print_info_line(("Initial step: %g"% (tstep,), 5), verbose) if max_dx is None: max_dx_plus_1 = None else: max_dx_plus_1 = max_dx +1 if pmax_dx is None: pmax_dx_plus_1 = None else: pmax_dx_plus_1 = pmax_dx +1 # setup error vectors aerror = numpy.mat(numpy.zeros((x0.shape[0], 1))) aerror[:nv-1, 0] = options.vea aerror[nv-1:, 0] = options.vea rerror = numpy.mat(numpy.zeros((x0.shape[0], 1))) rerror[:nv-1, 0] = options.ver rerror[nv-1:, 0] = options.ier iter_n = 0 # contatore d'iterazione lte = None sol = results.tran_solution(circ, tstart, tstop, op=x0, method=method, outfile=data_filename) printing.print_info_line(("Solving... ", 3), verbose, print_nl=False) tick = ticker.ticker(increments_for_step=1) tick.display(verbose > 1) while time < tstop: if iter_n < max(max_x, max_dx_plus_1): x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \ implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \ predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1)))) else: [x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \ df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control) if options.transient_prediction_as_x0 and use_step_control and prediction is not None: x0 = prediction elif x is not None: x0 = x (x1, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)) , Ndc=N, Ntran=D*const, circ=circ, Gmin=Gmin_matrix, x0=x0, time=(time + tstep), locked_nodes=locked_nodes, MAXIT=options.transient_max_nr_iter, verbose=0) if solved: old_step = tstep #we will modify it, if we're using step control otherwise it's the same # step control (yeah) if use_step_control: if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None: # this is the Local Truncation Error :) lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) * (prediction - x1)) # it should NEVER happen that new_step > 2*tstep, for stability new_step_coeff = 2 for index in xrange(x.shape[0]): if lte[index, 0] != 0: new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \ ** (1.0 / (df.order+1)) if new_value < new_step_coeff: new_step_coeff = new_value #print new_value new_step = tstep * new_step_coeff if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep: #don't recalculate a x for a small change tstep = check_step(new_step, time, tstop, HMAX) #print "Apost. (reducing) step = "+str(tstep) continue tstep = check_step(new_step, time, tstop, HMAX) # used in the next iteration #print "Apriori tstep = "+str(tstep) else: #print "LTE not calculated." lte = None if print_step_and_lte and lte is not None: #if you wish to look at the step. We print just a lte flte.write(str(time)+"\t"+str(old_step)+"\t"+str(lte.max())+"\n") # if we get here, either aposteriori_step_control is # disabled, or it's enabled and the error is small # enough. Anyway, the result is GOOD, STORE IT. time = time + old_step x = x1 iter_n = iter_n + 1 sol.add_line(time, x) dxdt = numpy.multiply(x_coeff, x) + const thebuffer.add((time, x, dxdt)) if output_buffer is not None: output_buffer.add((x, )) tick.step(verbose > 1) else: # If we get here, Newton failed to converge. We need to reduce the step... if use_step_control: tstep = tstep/5.0 tstep = check_step(tstep, time, tstop, HMAX) printing.print_info_line(("At %g s reducing step: %g s (convergence failed)" % (time, tstep), 5), verbose) else: #we can't reduce the step printing.print_general_error("Can't converge with step "+str(tstep)+".") printing.print_general_error("Try setting --t-max-nr to a higher value or set step to a lower one.") solved = False break if options.transient_max_time_iter and iter_n == options.transient_max_time_iter: printing.print_general_error("MAX_TIME_ITER exceeded ("+str(options.transient_max_time_iter)+"), iteration halted.") solved = False break if print_step_and_lte: flte.close() tick.hide(verbose > 1) if solved: printing.print_info_line(("done.", 3), verbose) printing.print_info_line(("Average time step: %g" % ((tstop - tstart)/iter_n,), 3), verbose) if output_buffer: ret_value = output_buffer.get_as_matrix() else: ret_value = sol else: print "failed." ret_value = None return ret_value
def op_analysis(circ, x0=None, guess=True, outfile=None, verbose=3): """Runs an Operating Point (OP) analysis circ: the circuit instance on which the simulation is run x0: is the initial guess to be used to start the NR mdn_solver guess: if set to True and x0 is None, it will generate a 'smart' guess verbose: verbosity level from 0 (silent) to 6 (debug). Returns a Operation Point result, if successful, None otherwise. """ if outfile == 'stdout': verbose = 0 # silent mode, print out results only. if not options.dc_use_guess: guess = False (mna, N) = generate_mna_and_N(circ, verbose=verbose) printing.print_info_line(("MNA matrix and constant term (complete):", 4), verbose) printing.print_info_line((str(mna), 4), verbose) printing.print_info_line((str(N), 4), verbose) # lets trash the unneeded col & row printing.print_info_line(("Removing unneeded row and column...", 4), verbose) mna = utilities.remove_row_and_col(mna) N = utilities.remove_row(N, rrow=0) printing.print_info_line(("Starting op analysis:", 2), verbose) if x0 is None and guess: x0 = dc_guess.get_dc_guess(circ, verbose=verbose) # if x0 is not None, use that printing.print_info_line(("Solving with Gmin:", 4), verbose) Gmin_matrix = build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose - 2) (x1, error1, solved1, n_iter1) = dc_solve(mna, N, circ, Gmin=Gmin_matrix, x0=x0, verbose=verbose) # We'll check the results now. Recalculate them without Gmin (using previsious solution as initial guess) # and check that differences on nodes and current do not exceed the # tolerances. if solved1: op1 = results.op_solution(x1, error1, circ, outfile=outfile, iterations=n_iter1) printing.print_info_line(("Solving without Gmin:", 4), verbose) (x2, error2, solved2, n_iter2) = dc_solve(mna, N, circ, Gmin=None, x0=x1, verbose=verbose) else: solved2 = False if solved1 and not solved2: printing.print_general_error("Can't solve without Gmin.") if verbose: print "Displaying latest valid results." op1.write_to_file(filename='stdout') opsolution = op1 elif solved1 and solved2: op2 = results.op_solution(x2, error2, circ, outfile=outfile, iterations=n_iter1 + n_iter2) op2.gmin = 0 badvars = results.op_solution.gmin_check(op2, op1) printing.print_result_check(badvars, verbose=verbose) check_ok = not (len(badvars) > 0) if not check_ok and verbose: print "Solution with Gmin:" op1.write_to_file(filename='stdout') print "Solution without Gmin:" op2.write_to_file(filename='stdout') opsolution = op2 else: # not solved1 printing.print_general_error("Couldn't solve the circuit. Giving up.") opsolution = None if opsolution and outfile != 'stdout' and outfile is not None: opsolution.write_to_file() if opsolution and verbose > 2 and options.cli: opsolution.write_to_file(filename='stdout') return opsolution
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \ D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3): """Performs a transient analysis of the circuit described by circ. Important parameters: - tstep is the maximum step to be allowed during simulation. - print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first element of x will be printed out to step_and_lte.graph in the current directory. """ if data_filename == "stdout": verbose = 0 _debug = False if _debug: print_step_and_lte = True else: print_step_and_lte = False HMAX = tstep #check parameters if tstart > tstop: printing.print_general_error("tstart > tstop") sys.exit(1) if tstep < 0: printing.print_general_error("tstep < 0") sys.exit(1) if verbose > 4: tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \ (options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin) printing.print_info_line((tmpstr, 5), verbose) locked_nodes = circ.get_locked_nodes() if print_step_and_lte: flte = open("step_and_lte.graph", "w") flte.write("#T\tStep\tLTE\n") printing.print_info_line(("Starting transient analysis: ", 3), verbose) printing.print_info_line(("Selected method: %s" % (method, ), 3), verbose) #It's a good idea to call transient with prebuilt MNA and N matrix #the analysis will be slightly faster (long netlists). if mna is None or N is None: (mna, N) = dc_analysis.generate_mna_and_N(circ) mna = utilities.remove_row_and_col(mna) N = utilities.remove_row(N, rrow=0) elif not mna.shape[0] == N.shape[0]: printing.print_general_error( "mna matrix and N vector have different number of columns.") sys.exit(0) if D is None: # if you do more than one tran analysis, output streams should be changed... # this needs to be fixed D = generate_D(circ, [mna.shape[0], mna.shape[0]]) D = utilities.remove_row_and_col(D) # setup x0 if x0 is None: printing.print_info_line(("Generating x(t=%g) = 0" % (tstart, ), 5), verbose) x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1))) opsol = results.op_solution(x=x0, error=x0, circ=circ, outfile=None) else: if isinstance(x0, results.op_solution): opsol = x0 x0 = x0.asmatrix() else: opsol = results.op_solution(x=x0, error=numpy.matrix( numpy.zeros((mna.shape[0], 1))), circ=circ, outfile=None) printing.print_info_line( ("Using the supplied op as x(t=%g)." % (tstart, ), 5), verbose) if verbose > 4: print "x0:" opsol.print_short() # setup the df method printing.print_info_line( ("Selecting the appropriate DF (" + method + ")... ", 5), verbose, print_nl=False) if method == IMPLICIT_EULER: import implicit_euler as df elif method == TRAP: import trap as df elif method == GEAR1: import gear as df df.order = 1 elif method == GEAR2: import gear as df df.order = 2 elif method == GEAR3: import gear as df df.order = 3 elif method == GEAR4: import gear as df df.order = 4 elif method == GEAR5: import gear as df df.order = 5 elif method == GEAR6: import gear as df df.order = 6 else: df = import_custom_df_module(method, print_out=(data_filename != "stdout")) # df is none if module is not found if df is None: sys.exit(23) if not df.has_ff() and use_step_control: printing.print_warning( "The chosen DF does not support step control. Turning off the feature." ) use_step_control = False #use_aposteriori_step_control = False printing.print_info_line(("done.", 5), verbose) # setup the data buffer # if you use the step control, the buffer has to be one point longer. # That's because the excess point is used by a FF in the df module to predict the next value. printing.print_info_line(("Setting up the buffer... ", 5), verbose, print_nl=False) ((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values() if max_x is None and max_dx is None: printing.print_general_error("df doesn't need any value?") sys.exit(1) if use_step_control: thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1, width=3) else: thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3) thebuffer.add((tstart, x0, None)) #setup the first values printing.print_info_line(("done.", 5), verbose) #FIXME #setup the output buffer if return_req_dict: output_buffer = dfbuffer(length=return_req_dict["points"], width=1) output_buffer.add((x0, )) else: output_buffer = None # import implicit_euler to be used in the first iterations # this is because we don't have any dx when we start, nor any past point value if (max_x is not None and max_x > 0) or max_dx is not None: import implicit_euler printing.print_info_line(("MNA (reduced):", 5), verbose) printing.print_info_line((str(mna), 5), verbose) printing.print_info_line(("D (reduced):", 5), verbose) printing.print_info_line((str(D), 5), verbose) # setup the initial values to start the iteration: x = None time = tstart nv = len(circ.nodes_dict) Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose) # lo step viene generato automaticamente, ma non superare mai quello fornito. if use_step_control: #tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin) tstep = min((tstop - tstart) / 9999.0, HMAX) printing.print_info_line(("Initial step: %g" % (tstep, ), 5), verbose) if max_dx is None: max_dx_plus_1 = None else: max_dx_plus_1 = max_dx + 1 if pmax_dx is None: pmax_dx_plus_1 = None else: pmax_dx_plus_1 = pmax_dx + 1 # setup error vectors aerror = numpy.mat(numpy.zeros((x0.shape[0], 1))) aerror[:nv - 1, 0] = options.vea aerror[nv - 1:, 0] = options.vea rerror = numpy.mat(numpy.zeros((x0.shape[0], 1))) rerror[:nv - 1, 0] = options.ver rerror[nv - 1:, 0] = options.ier iter_n = 0 # contatore d'iterazione lte = None sol = results.tran_solution(circ, tstart, tstop, op=x0, method=method, outfile=data_filename) printing.print_info_line(("Solving... ", 3), verbose, print_nl=False) tick = ticker.ticker(increments_for_step=1) tick.display(verbose > 1) while time < tstop: if iter_n < max(max_x, max_dx_plus_1): x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \ implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \ predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1)))) else: [x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \ df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control) if options.transient_prediction_as_x0 and use_step_control and prediction is not None: x0 = prediction elif x is not None: x0 = x (x1, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)), Ndc=N, Ntran=D * const, circ=circ, Gmin=Gmin_matrix, x0=x0, time=(time + tstep), locked_nodes=locked_nodes, MAXIT=options.transient_max_nr_iter, verbose=0) if solved: old_step = tstep #we will modify it, if we're using step control otherwise it's the same # step control (yeah) if use_step_control: if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None: # this is the Local Truncation Error :) lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) * (prediction - x1)) # it should NEVER happen that new_step > 2*tstep, for stability new_step_coeff = 2 for index in xrange(x.shape[0]): if lte[index, 0] != 0: new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \ ** (1.0 / (df.order+1)) if new_value < new_step_coeff: new_step_coeff = new_value #print new_value new_step = tstep * new_step_coeff if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep: #don't recalculate a x for a small change tstep = check_step(new_step, time, tstop, HMAX) #print "Apost. (reducing) step = "+str(tstep) continue tstep = check_step(new_step, time, tstop, HMAX) # used in the next iteration #print "Apriori tstep = "+str(tstep) else: #print "LTE not calculated." lte = None if print_step_and_lte and lte is not None: #if you wish to look at the step. We print just a lte flte.write( str(time) + "\t" + str(old_step) + "\t" + str(lte.max()) + "\n") # if we get here, either aposteriori_step_control is # disabled, or it's enabled and the error is small # enough. Anyway, the result is GOOD, STORE IT. time = time + old_step x = x1 iter_n = iter_n + 1 sol.add_line(time, x) dxdt = numpy.multiply(x_coeff, x) + const thebuffer.add((time, x, dxdt)) if output_buffer is not None: output_buffer.add((x, )) tick.step(verbose > 1) else: # If we get here, Newton failed to converge. We need to reduce the step... if use_step_control: tstep = tstep / 5.0 tstep = check_step(tstep, time, tstop, HMAX) printing.print_info_line( ("At %g s reducing step: %g s (convergence failed)" % (time, tstep), 5), verbose) else: #we can't reduce the step printing.print_general_error("Can't converge with step " + str(tstep) + ".") printing.print_general_error( "Try setting --t-max-nr to a higher value or set step to a lower one." ) solved = False break if options.transient_max_time_iter and iter_n == options.transient_max_time_iter: printing.print_general_error("MAX_TIME_ITER exceeded (" + str(options.transient_max_time_iter) + "), iteration halted.") solved = False break if print_step_and_lte: flte.close() tick.hide(verbose > 1) if solved: printing.print_info_line(("done.", 3), verbose) printing.print_info_line( ("Average time step: %g" % ((tstop - tstart) / iter_n, ), 3), verbose) if output_buffer: ret_value = output_buffer.get_as_matrix() else: ret_value = sol else: print "failed." ret_value = None return ret_value
def op_analysis(circ, x0=None, guess=True, data_filename=None, verbose=3): """Runs an Operating Point (OP) analysis circ: the circuit instance on which the simulation is run x0: is the initial guess to be used to start the NR mdn_solver guess: if set to True and x0 is None, it will generate a 'smart' guess verbose: verbosity level from 0 (silent) to 6 (debug). Returns a Operation Point result, if successful, None otherwise. """ # use_gmin = True # solved=False # x0 = numpy.mat(numpy.zeros((1,2))) (mna, N) = generate_mna_and_N(circ) printing.print_info_line(("MNA matrix and constant term (complete):", 4), verbose) printing.print_info_line((str(mna), 4), verbose) printing.print_info_line((str(N), 4), verbose) # lets trash the unneeded col & row printing.print_info_line(("Removing unneeded row and column...", 4), verbose) mna = utilities.remove_row_and_col(mna) N = utilities.remove_row(N, rrow=0) printing.print_info_line(("Starting op analysis:", 2), verbose) if x0 is None and guess: x0 = dc_guess.get_dc_guess(circ, verbose=verbose) # if x0 is not None, use that printing.print_info_line(("Solving with Gmin:", 4), verbose) Gmin_matrix = build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose - 2) (x1, error1, solved1, n_iter1) = dc_solve(mna, N, circ, Gmin=Gmin_matrix, x0=x0, verbose=verbose) # We'll check the results now. Recalculate them without Gmin (using previsious solution as initial guess) # and check that differences on nodes and current do not exceed the tolerances. if solved1: op1 = results.op_solution(x1, error1, circ, outfile=data_filename, iterations=n_iter1) printing.print_info_line(("Solving without Gmin:", 4), verbose) (x2, error2, solved2, n_iter2) = dc_solve(mna, N, circ, Gmin=None, x0=x1, verbose=verbose) if not solved2: printing.print_general_error("Can't solve without Gmin.") if verbose: print "Displaying latest valid results." op1.write_to_file(filename="stdout") opsolution = op1 else: op2 = results.op_solution(x2, error2, circ, outfile=data_filename, iterations=n_iter1 + n_iter2) op2.gmin = 0 badvars = results.op_solution.gmin_check(op2, op1) printing.print_result_check(badvars, verbose=verbose) check_ok = not (len(badvars) > 0) if not check_ok and verbose: print "Solution with Gmin:" op1.write_to_file(filename="stdout") print "Solution without Gmin:" if verbose: op2.write_to_file(filename="stdout") opsolution = op2 if data_filename != "stdout" and data_filename is not None: opsolution.write_to_file() else: printing.print_general_error("Couldn't solve the circuit. Giving up.") opsolution = None return opsolution