/**********
Copyright 1990 Regents of the University of California.  All rights reserved.
Author: 1985 Thomas L. Quarles
**********/

#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/smpdefs.h"
#include "ngspice/sperror.h"
#include "ngspice/devdefs.h"


int
CKTic(CKTcircuit *ckt)
{
    int error;
    int size;
    int i;
    int nskipped = 0, iskipped = 0;
    CKTnode *node;

    size = SMPmatSize(ckt->CKTmatrix);
    for (i=0;i<=size;i++) {
        ckt->CKTrhs[i]=0;
    }

    for(node = ckt->CKTnodes;node != NULL; node = node->next) {
        if(node->nsGiven) {
            int applicable = 1;

#ifdef KLU
            if (ckt->CKTkluMODE) {
                node->ptr = (double *) SMPfindElt (ckt->CKTmatrix, node->number, node->number, 0) ;
                if (node->ptr == NULL) {
                    /* Nothing stamps a diagonal for this node -- e.g. its only
                       element was removed by CKTtopologyReduce -- and KLU, unlike
                       SPARSE, cannot create one.  A .nodeset is a HINT, not a
                       requirement: skip this one and carry on.  Returning E_NOMEM
                       here aborted the whole analysis and surfaced as a bogus
                       "doAnalyses: out of memory", losing a solve that would
                       otherwise have succeeded. */
                    /* clear the flag as well: cktload() walks nsGiven nodes and
                       dereferences node->ptr for the 1e10 keeper, so leaving it
                       set would segfault on every load. */
                    node->nsGiven = 0;
                    nskipped++;
                    applicable = 0;
                }
            } else {
#endif

                node->ptr = SMPmakeElt(ckt->CKTmatrix,node->number,node->number);
                /* SPARSE can always create the element, so a failure here really
                   is out of memory. */
                if(node->ptr == NULL) return(E_NOMEM);

#ifdef KLU
            }
#endif

            if(applicable) {
                ckt->CKThadNodeset = 1;
                ckt->CKTrhsOld[node->number] = ckt->CKTrhs[node->number] = node->nodeset;
            }
        }
        if(node->icGiven) {
            if(! ( node->ptr)) {

#ifdef KLU
                if (ckt->CKTkluMODE) {
                    node->ptr = (double *) SMPfindElt (ckt->CKTmatrix, node->number, node->number, 0) ;
                    if (node->ptr == NULL) {
                        node->icGiven = 0;   /* see the .nodeset case above */
                        iskipped++;
                    }
                } else {
#endif

                    node->ptr = SMPmakeElt(ckt->CKTmatrix,node->number, node->number);
                    if(node->ptr == NULL) return(E_NOMEM);

#ifdef KLU
                }
#endif

            }
            if(node->ptr)
                ckt->CKTrhsOld[node->number] = ckt->CKTrhs[node->number] = node->ic;
        }
    }

    if(nskipped || iskipped)
        SPfrontEnd->IFerrorf(ERR_INFO,
            "%d .nodeset and %d .ic entry(s) skipped: those nodes have no matrix "
            "element (KLU cannot create one); the analysis continues without them",
            nskipped, iskipped);

    if(ckt->CKTmode & MODEUIC) {
        for (i=0;i<DEVmaxnum;i++) {
            if( DEVices[i] && DEVices[i]->DEVsetic && ckt->CKThead[i] ) {
                error = DEVices[i]->DEVsetic (ckt->CKThead[i], ckt);
                if(error) return(error);
            }
        }
    }

    return(OK);
}
