1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1985 Thomas L. Quarles
4 **********/
5 
6     /* CKTsetup(ckt)
7      * this is a driver program to iterate through all the various
8      * setup functions provided for the circuit elements in the
9      * given circuit
10      */
11 
12 #include "ngspice/ngspice.h"
13 #include "ngspice/smpdefs.h"
14 #include "ngspice/cktdefs.h"
15 #include "ngspice/devdefs.h"
16 #include "ngspice/sperror.h"
17 
18 #ifdef XSPICE
19 #include "ngspice/enh.h"
20 #endif
21 
22 #ifdef USE_OMP
23 #include <omp.h>
24 #include "ngspice/cpextern.h"
25 int nthreads;
26 #endif
27 
28 #define CKALLOC(var,size,type) \
29     if(size && ((var = TMALLOC(type, size)) == NULL)){\
30             return(E_NOMEM);\
31 }
32 
33 
34 int
CKTsetup(CKTcircuit * ckt)35 CKTsetup(CKTcircuit *ckt)
36 {
37     int i;
38     int error;
39 #ifdef XSPICE
40  /* gtri - begin - Setup for adding rshunt option resistors */
41     CKTnode *node;
42     int     num_nodes;
43  /* gtri - end - Setup for adding rshunt option resistors */
44 #endif
45     SMPmatrix *matrix;
46     ckt->CKTnumStates=0;
47 
48 #ifdef WANT_SENSE2
49     if(ckt->CKTsenInfo){
50         error = CKTsenSetup(ckt);
51         if (error)
52             return(error);
53     }
54 #endif
55 
56     if (ckt->CKTisSetup)
57         return E_NOCHANGE;
58 
59     error = NIinit(ckt);
60     if (error) return(error);
61     ckt->CKTisSetup = 1;
62 
63     matrix = ckt->CKTmatrix;
64 
65 #ifdef USE_OMP
66     if (!cp_getvar("num_threads", CP_NUM, &nthreads, 0))
67         nthreads = 2;
68 
69     omp_set_num_threads(nthreads);
70 /*    if (nthreads == 1)
71       printf("OpenMP: %d thread is requested in ngspice\n", nthreads);
72     else
73       printf("OpenMP: %d threads are requested in ngspice\n", nthreads);*/
74 #endif
75 
76 #ifdef HAS_PROGREP
77     SetAnalyse("Device Setup", 0);
78 #endif
79 
80     /* preserve CKTlastNode before invoking DEVsetup()
81      * so we can check for incomplete CKTdltNNum() invocations
82      * during DEVunsetup() causing an erronous circuit matrix
83      *   when reinvoking CKTsetup()
84      */
85     ckt->prev_CKTlastNode = ckt->CKTlastNode;
86 
87     for (i=0;i<DEVmaxnum;i++) {
88         if ( DEVices[i] && DEVices[i]->DEVsetup && ckt->CKThead[i] ) {
89             error = DEVices[i]->DEVsetup (matrix, ckt->CKThead[i], ckt,
90                     &ckt->CKTnumStates);
91             if(error) return(error);
92         }
93     }
94     for(i=0;i<=MAX(2,ckt->CKTmaxOrder)+1;i++) { /* dctran needs 3 states as minimum */
95         CKALLOC(ckt->CKTstates[i],ckt->CKTnumStates,double);
96     }
97 #ifdef WANT_SENSE2
98     if(ckt->CKTsenInfo){
99         /* to allocate memory to sensitivity structures if
100          * it is not done before */
101 
102         error = NIsenReinit(ckt);
103         if(error) return(error);
104     }
105 #endif
106     if(ckt->CKTniState & NIUNINITIALIZED) {
107         error = NIreinit(ckt);
108         if(error) return(error);
109     }
110 #ifdef XSPICE
111   /* gtri - begin - Setup for adding rshunt option resistors */
112 
113     if(ckt->enh->rshunt_data.enabled) {
114 
115         /* Count number of voltage nodes in circuit */
116         for(num_nodes = 0, node = ckt->CKTnodes; node; node = node->next)
117             if((node->type == SP_VOLTAGE) && (node->number != 0))
118                 num_nodes++;
119 
120         /* Allocate space for the matrix diagonal data */
121         if(num_nodes > 0) {
122             ckt->enh->rshunt_data.diag =
123                  TMALLOC(double *, num_nodes);
124         }
125 
126         /* Set the number of nodes in the rshunt data */
127         ckt->enh->rshunt_data.num_nodes = num_nodes;
128 
129         /* Get/create matrix diagonal entry following what RESsetup does */
130         for(i = 0, node = ckt->CKTnodes; node; node = node->next) {
131             if((node->type == SP_VOLTAGE) && (node->number != 0)) {
132                 ckt->enh->rshunt_data.diag[i] =
133                       SMPmakeElt(matrix,node->number,node->number);
134                 i++;
135             }
136         }
137 
138     }
139 
140     /* gtri - end - Setup for adding rshunt option resistors */
141 #endif
142     return(OK);
143 }
144 
145 int
CKTunsetup(CKTcircuit * ckt)146 CKTunsetup(CKTcircuit *ckt)
147 {
148     int i, error, e2;
149     CKTnode *node;
150 
151     error = OK;
152     if (!ckt->CKTisSetup)
153         return OK;
154 
155     for(i=0;i<=ckt->CKTmaxOrder+1;i++) {
156         tfree(ckt->CKTstates[i]);
157     }
158 
159     /* added by HT 050802*/
160     for(node=ckt->CKTnodes;node;node=node->next){
161         if(node->icGiven || node->nsGiven) {
162             node->ptr=NULL;
163         }
164     }
165 
166     for (i=0;i<DEVmaxnum;i++) {
167         if ( DEVices[i] && DEVices[i]->DEVunsetup && ckt->CKThead[i] ) {
168             e2 = DEVices[i]->DEVunsetup (ckt->CKThead[i], ckt);
169             if (!error && e2)
170                 error = e2;
171         }
172     }
173 
174     if (ckt->prev_CKTlastNode != ckt->CKTlastNode) {
175         fprintf(stderr, "Internal Error: incomplete CKTunsetup(), this will cause serious problems, please report this issue !\n");
176         controlled_exit(EXIT_FAILURE);
177     }
178     ckt->prev_CKTlastNode = NULL;
179 
180     ckt->CKTisSetup = 0;
181     if(error) return(error);
182 
183     NIdestroy(ckt);
184     /*
185     if (ckt->CKTmatrix)
186         SMPdestroy(ckt->CKTmatrix);
187     ckt->CKTmatrix = NULL;
188     */
189 
190     return OK;
191 }
192