コード例 #1
0
int
main (int argc, char **argv)
{
  int ch;
  int errflg=0,i,j;
  double l,c,ctot,r=0.0,g=0.0,k=0.0,lm=0.0,cm=0.0,len;
  unsigned gotl=0,gotc=0,gotr=0,gotg=0,gotk=0,gotcm=0,gotlen=0;
  unsigned gotname=0, gotnum=0;
  char *name = "";
  double **matrix, **inverse;
  double *tpeigenvalues, *gammaj;
  char *options;
  int num, node;
  char **pname, *s;
  int use_opt;
  char *optarg;

  pname = argv;
  argv++;
  argc--;

  ch = 0;
  while (argc > 0) {
    s = *argv++;
    argc--;
    while ((ch = *s++)) {
      if (*s)
	optarg = s;
      else if (argc)
	optarg = *argv;
      else
	optarg = NULL;
      use_opt = 0;

      switch (ch) {
      case 'o':
	name = (char *) tmalloc((unsigned) (strlen(optarg)*sizeof(char)));
	(void) strcpy(name,optarg);
	gotname=1;
	use_opt = 1;
	break;
      case 'l':
	sscanf(optarg,"%lf",&l);
	gotl=1;
	use_opt = 1;
	break;
      case 'c':
	sscanf(optarg,"%lf",&c);
	gotc=1;
	use_opt = 1;
	break;
      case 'r':
	sscanf(optarg,"%lf",&r);
	use_opt = 1;
	gotr=1;
	break;
      case 'g':
	sscanf(optarg,"%lf",&g);
	use_opt = 1;
	gotg=1;
	break;
      case 'k':
	sscanf(optarg,"%lf",&k);
	use_opt = 1;
	gotk=1;
	break;
      case 'x':
	sscanf(optarg,"%lf",&cm);
	use_opt = 1;
	gotcm=1;
	break;
      case 'L':
	sscanf(optarg,"%lf",&len);
	use_opt = 1;
	gotlen=1;
	break;
      case 'n':
	sscanf(optarg,"%d",&num);
	use_opt = 1;
	gotnum=1;
	break;
      case 'h':
	usage(pname);
	exit(1);
	break;
      case '-':
	break;
      default:
	usage(pname);
	exit(2);
	break;
      }
      if (use_opt) {
	if (optarg == s)
	  s += strlen(s);
	else if (optarg) {
	  argc--;
	  argv++;
	}
      }
    }
  }

  if (errflg) {
    usage(argv);
    exit (2);
  }

  if (gotl + gotc + gotname + gotnum + gotlen < 5) {
    fprintf(stderr,"l, c, model_name, number_of_conductors and length must be specified.\n");
    fprintf(stderr,"%s -u for details.\n",pname[0]);
    fflush(stdout);
    exit(1);
  }

  if ( (k<0.0?-k:k) >=1.0 ) {
    fprintf(stderr,"Error: |k| must be less than 1.0\n");
    fflush(stderr);
    exit(1);
  }

  if (num == 1) {
    fprintf(stdout,"* single conductor line\n");
    fflush(stdout);
    exit(1);
  }

  lm = l*k;
  switch(num) {

  case 1: ctot = c; break;
  case 2: ctot = c + cm; break;
  default: ctot = c + 2*cm; break;
  }

  comments(r,l,g,c,ctot,cm,lm,k,name,num,len);

  matrix = (double **) tmalloc((unsigned) (sizeof(double*)*(num+1)));
  inverse = (double **) tmalloc((unsigned) (sizeof(double*)*(num+1)));
  tpeigenvalues = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));

  for (i=1;i<=num;i++) {
    matrix[i] = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));
    inverse[i] = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));
  }

  for (i=1;i<=num;i++) {
    tpeigenvalues[i] = -2.0 * cos(M_PI*i/(num+1));
  }

  for (i=1;i<=num;i++) {
    for (j=1;j<=num;j++) {
      matrix[i][j] = phi(i-1,tpeigenvalues[j]);
    }
  }
  gammaj = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));

  for (j=1;j<=num;j++) {
    gammaj[j] = 0.0;
    for (i=1;i<=num;i++) {
      gammaj[j] += matrix[i][j] * matrix[i][j];
    }
    gammaj[j] = sqrt(gammaj[j]);
  }

  for (j=1;j<=num;j++) {
    for (i=1;i<=num; i++) {
      matrix[i][j] /= gammaj[j];
    }
  }

  tfree(gammaj);

  /* matrix = M set up */

  {
    MatrixPtr othermatrix;
    double *rhs, *solution;
    double *irhs, *isolution;
    int errflg, err, singular_row, singular_col;
    double *elptr;

    rhs = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));
    irhs = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));
    solution = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));
    isolution = (double *) tmalloc((unsigned) (sizeof(double)*(num+1)));

    othermatrix = spCreate(num,0,&errflg);

    for (i=1;i<=num;i++) {
      for (j=1; j<=num; j++) {
	elptr = spGetElement(othermatrix,i,j);
	*elptr = matrix[i][j];
      }
    }

#ifdef DEBUG_LEVEL1
    (void) spPrint(othermatrix,0,1,0);
#endif

    for (i=1;i<=num;i++) rhs[i] = 0.0;
    rhs[1]=1.0;

    err =
      spOrderAndFactor(othermatrix,rhs,THRSH,ABS_THRSH,DIAG_PIVOTING);

    spErrorMessage(othermatrix,stderr,NULL);

    switch(err) {

    case spNO_MEMORY:
      fprintf(stderr,"No memory in spOrderAndFactor\n");
      fflush(stderr);
      exit(1);
    case spSINGULAR:
      (void)
	spWhereSingular(othermatrix,&singular_row,&singular_col);
      fprintf(stderr,"Singular matrix: problem in row %d and col %d\n", singular_row, singular_col);
      fflush(stderr);
      exit(1);
    default: break;
    }

    for (i=1;i<=num;i++) {
      for (j=1;j<=num;j++) {
	rhs[j] = (j==i?1.0:0.0);
	irhs[j] = 0.0;
      }
      (void) spSolveTransposed(othermatrix,rhs,solution, irhs, isolution);
      for (j=1;j<=num;j++) {
	inverse[i][j] = solution[j];
      }
    }

    tfree(rhs);
    tfree(solution);
  }

  /* inverse = M^{-1} set up */

  fprintf(stdout,"\n");
  fprintf(stdout,"* Lossy line models\n");

  options = (char *) tmalloc((unsigned) 256);
  (void) strcpy(options,"rel=1.2 nocontrol");
  for (i=1;i<=num;i++) {
    fprintf(stdout,".model mod%d_%s ltra %s r=%0.12g l=%0.12g g=%0.12g c=%0.12g len=%0.12g\n",
	    i,name,options,r,l+tpeigenvalues[i]*lm,g,ctot-tpeigenvalues[i]*cm,len);
    /*i,name,options,r,l+tpeigenvalues[i]*lm,g,ctot+tpeigenvalues[i]*cm,len);*/
  }


  fprintf(stdout,"\n");
  fprintf(stdout,"* subcircuit m_%s - modal transformation network for %s\n",name,name);
  fprintf(stdout,".subckt m_%s", name);
  for (i=1;i<= 2*num; i++) {
    fprintf(stdout," %d",i);
  }
  fprintf(stdout,"\n");
  for (j=1;j<=num;j++) fprintf(stdout,"v%d %d 0 0v\n",j,j+2*num);

  for (j=1;j<=num;j++) {
    for (i=1; i<=num; i++) {
      fprintf(stdout,"f%d 0 %d v%d %0.12g\n",
	      (j-1)*num+i,num+j,i,inverse[j][i]);
    }
  }

  node = 3*num+1;
  for (j=1;j<=num;j++) {
    fprintf(stdout,"e%d %d %d %d 0 %0.12g\n", (j-1)*num+1,
	    node, 2*num+j, num+1, matrix[j][1]);
    node++;
    for (i=2; i<num; i++) {
      fprintf(stdout,"e%d %d %d %d 0 %0.12g\n", (j-1)*num+i,
	      node,node-1,num+i,matrix[j][i]);
      node++;
    }
    fprintf(stdout,"e%d %d %d %d 0 %0.12g\n", j*num,j,node-1,
	    2*num,matrix[j][num]);
  }
  fprintf(stdout,".ends m_%s\n",name);

  fprintf(stdout,"\n");
  fprintf(stdout,"* Subckt %s\n", name);
  fprintf(stdout,".subckt %s",name);
  for (i=1;i<=2*num;i++) {
    fprintf(stdout," %d",i);
  }
  fprintf(stdout,"\n");

  fprintf(stdout,"x1");
  for (i=1;i<=num;i++)  fprintf(stdout," %d", i);
  for (i=1;i<=num;i++)  fprintf(stdout," %d", 2*num+i);
  fprintf(stdout," m_%s\n",name);

  for (i=1;i<=num;i++) 
    fprintf(stdout,"o%d %d 0 %d 0 mod%d_%s\n",i,2*num+i,3*num+i,i,name);

  fprintf(stdout,"x2");
  for (i=1;i<=num;i++)  fprintf(stdout," %d", num+i);
  for (i=1;i<=num;i++)  fprintf(stdout," %d", 3*num+i);
  fprintf(stdout," m_%s\n",name);

  fprintf(stdout,".ends %s\n",name);

  tfree(tpeigenvalues);
  for (i=1;i<=num;i++) {
    tfree(matrix[i]);
    tfree(inverse[i]);
  }
  tfree(matrix);
  tfree(inverse);
  tfree(name);
  tfree(options);

  return EXIT_NORMAL; 
}
コード例 #2
0
ファイル: spsmp.c プロジェクト: aesop972/ngspice-gss
/*
 * SMPgetError()
 */
void
SMPgetError(SMPmatrix *Matrix, int *Col, int *Row)
{
    spWhereSingular( (void *)Matrix, Row, Col );
}
コード例 #3
0
ファイル: twosolve.c プロジェクト: Anastien/ngspice
/* the iteration driving loop and convergence check */
void
TWOdcSolve(TWOdevice *pDevice, int iterationLimit, BOOLEAN newSolver, 
           BOOLEAN tranAnalysis, TWOtranInfo *info)
{
  TWOnode *pNode;
  TWOelem *pElem;
  int size = pDevice->numEqns;
  int index, eIndex, error;
  int timesConverged = 0;
  BOOLEAN quitLoop;
  BOOLEAN debug;
  BOOLEAN negConc = FALSE;
  double *rhs = pDevice->rhs;
  double *solution = pDevice->dcSolution;
  double *delta = pDevice->dcDeltaSolution;
  double poissNorm, contNorm;
  double startTime, totalStartTime;
  double totalTime, loadTime, factorTime, solveTime, updateTime, checkTime;
  double orderTime = 0.0;

  totalTime = loadTime = factorTime = solveTime = updateTime = checkTime = 0.0;
  totalStartTime = SPfrontEnd->IFseconds();

  quitLoop = FALSE;
  debug = (!tranAnalysis && TWOdcDebug) || (tranAnalysis && TWOtranDebug);
  pDevice->iterationNumber = 0;
  pDevice->converged = FALSE;

  if (debug) {
    if (pDevice->poissonOnly) {
      fprintf(stdout, "Equilibrium Solution:\n");
    } else {
      fprintf(stdout, "Bias Solution:\n");
    }
    fprintf(stdout, "Iteration  RHS Norm\n");
  }
  while (!(pDevice->converged || (pDevice->iterationNumber > iterationLimit)
	  || quitLoop)) {
    pDevice->iterationNumber++;

    if ((!pDevice->poissonOnly) && (iterationLimit > 0)
	&&(!tranAnalysis)) {
      TWOjacCheck(pDevice, tranAnalysis, info);
    }

    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    if (pDevice->poissonOnly) {
      TWOQsysLoad(pDevice);
    } else if (!OneCarrier) {
      TWO_sysLoad(pDevice, tranAnalysis, info);
    } else if (OneCarrier == N_TYPE) {
      TWONsysLoad(pDevice, tranAnalysis, info);
    } else if (OneCarrier == P_TYPE) {
      TWOPsysLoad(pDevice, tranAnalysis, info);
    }
    pDevice->rhsNorm = maxNorm(rhs, size);
    loadTime += SPfrontEnd->IFseconds() - startTime;
    if (debug) {
      fprintf(stdout, "%7d   %11.4e%s\n",
	  pDevice->iterationNumber - 1, pDevice->rhsNorm,
	  negConc ? "   negative conc encountered" : "");
      negConc = FALSE;
    }

    /* FACTOR */
    startTime = SPfrontEnd->IFseconds();
    error = spFactor(pDevice->matrix);
    factorTime += SPfrontEnd->IFseconds() - startTime;
    if (newSolver) {
      if (pDevice->iterationNumber == 1) {
	orderTime = factorTime;
      } else if (pDevice->iterationNumber == 2) {
	orderTime -= factorTime - orderTime;
	factorTime -= orderTime;
	if (pDevice->poissonOnly) {
	  pDevice->pStats->orderTime[STAT_SETUP] += orderTime;
	} else {
	  pDevice->pStats->orderTime[STAT_DC] += orderTime;
	}
	newSolver = FALSE;
      }
    }
    if (foundError(error)) {
      if (error == spSINGULAR) {
	int badRow, badCol;
	spWhereSingular(pDevice->matrix, &badRow, &badCol);
	printf("*****  singular at (%d,%d)\n", badRow, badCol);
      }
      pDevice->converged = FALSE;
      quitLoop = TRUE;
      continue;
    }

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    spSolve(pDevice->matrix, rhs, delta, NULL, NULL);
    solveTime += SPfrontEnd->IFseconds() - startTime;

    /* UPDATE */
    startTime = SPfrontEnd->IFseconds();
    /* Use norm reducing Newton method for DC bias solutions only. */
    if ((!pDevice->poissonOnly) && (iterationLimit > 0)
	&& (!tranAnalysis) && (pDevice->rhsNorm > 1e-1)) {
      error = TWOnewDelta(pDevice, tranAnalysis, info);
      if (error) {
	pDevice->converged = FALSE;
	quitLoop = TRUE;
	updateTime += SPfrontEnd->IFseconds() - startTime;
	continue;
      }
    }
    for (index = 1; index <= size; index++) {
      solution[index] += delta[index];
    }
    updateTime += SPfrontEnd->IFseconds() - startTime;

    /* CHECK CONVERGENCE */
    startTime = SPfrontEnd->IFseconds();
    /* Check if updates have gotten sufficiently small. */
    if (pDevice->iterationNumber != 1) {
      pDevice->converged = TWOdeltaConverged(pDevice);
    }
    /* Check if the residual is smaller than abstol. */
    if (pDevice->converged && (!pDevice->poissonOnly)
	&& (!tranAnalysis)) {
      if (!OneCarrier) {
	TWO_rhsLoad(pDevice, tranAnalysis, info);
      } else if (OneCarrier == N_TYPE) {
	TWONrhsLoad(pDevice, tranAnalysis, info);
      } else if (OneCarrier == P_TYPE) {
	TWOPrhsLoad(pDevice, tranAnalysis, info);
      }
      pDevice->rhsNorm = maxNorm(rhs, size);
      if (pDevice->rhsNorm > pDevice->abstol) {
	pDevice->converged = FALSE;
      }
      if ((++timesConverged >= 2)
	  && (pDevice->rhsNorm < 1e3 * pDevice->abstol)) {
	pDevice->converged = TRUE;
      } else if (timesConverged >= 5) {
	pDevice->converged = FALSE;
	quitLoop = TRUE;
	continue;
      }
    } else if (pDevice->converged && pDevice->poissonOnly) {
      TWOQrhsLoad(pDevice);
      pDevice->rhsNorm = maxNorm(rhs, size);
      if (pDevice->rhsNorm > pDevice->abstol) {
	pDevice->converged = FALSE;
      }
      if (++timesConverged >= 5) {
	pDevice->converged = TRUE;
      }
    }
    /* Check if the carrier concentrations are negative. */
    if (pDevice->converged && (!pDevice->poissonOnly)) {
      /* Clear garbage entry since carrier-free elements reference it. */
      solution[0] = 0.0;
      for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
	pElem = pDevice->elements[eIndex];
	for (index = 0; index <= 3; index++) {
	  if (pElem->evalNodes[index]) {
	    pNode = pElem->pNodes[index];
	    if (solution[pNode->nEqn] < 0.0) {
	      pDevice->converged = FALSE;
	      negConc = TRUE;
	      if (tranAnalysis) {
		quitLoop = TRUE;
	      } else {
		solution[pNode->nEqn] = 0.0;
	      }
	    }
	    if (solution[pNode->pEqn] < 0.0) {
	      pDevice->converged = FALSE;
	      negConc = TRUE;
	      if (tranAnalysis) {
		quitLoop = TRUE;
	      } else {
		solution[pNode->pEqn] = 0.0;
	      }
	    }
	  }
	}
      }
      if (!pDevice->converged) {
	if (!OneCarrier) {
	  TWO_rhsLoad(pDevice, tranAnalysis, info);
	} else if (OneCarrier == N_TYPE) {
	  TWONrhsLoad(pDevice, tranAnalysis, info);
	} else if (OneCarrier == P_TYPE) {
	  TWOPrhsLoad(pDevice, tranAnalysis, info);
	}
	pDevice->rhsNorm = maxNorm(rhs, size);
      }
    }
    checkTime += SPfrontEnd->IFseconds() - startTime;
  }
  totalTime += SPfrontEnd->IFseconds() - totalStartTime;

  if (tranAnalysis) {
    pDevice->pStats->loadTime[STAT_TRAN] += loadTime;
    pDevice->pStats->factorTime[STAT_TRAN] += factorTime;
    pDevice->pStats->solveTime[STAT_TRAN] += solveTime;
    pDevice->pStats->updateTime[STAT_TRAN] += updateTime;
    pDevice->pStats->checkTime[STAT_TRAN] += checkTime;
    pDevice->pStats->numIters[STAT_TRAN] += pDevice->iterationNumber;
  } else if (pDevice->poissonOnly) {
    pDevice->pStats->loadTime[STAT_SETUP] += loadTime;
    pDevice->pStats->factorTime[STAT_SETUP] += factorTime;
    pDevice->pStats->solveTime[STAT_SETUP] += solveTime;
    pDevice->pStats->updateTime[STAT_SETUP] += updateTime;
    pDevice->pStats->checkTime[STAT_SETUP] += checkTime;
    pDevice->pStats->numIters[STAT_SETUP] += pDevice->iterationNumber;
  } else {
    pDevice->pStats->loadTime[STAT_DC] += loadTime;
    pDevice->pStats->factorTime[STAT_DC] += factorTime;
    pDevice->pStats->solveTime[STAT_DC] += solveTime;
    pDevice->pStats->updateTime[STAT_DC] += updateTime;
    pDevice->pStats->checkTime[STAT_DC] += checkTime;
    pDevice->pStats->numIters[STAT_DC] += pDevice->iterationNumber;
  }

  if (debug) {
    if (!tranAnalysis) {
      pDevice->rhsNorm = maxNorm(rhs, size);
      fprintf(stdout, "%7d   %11.4e%s\n",
	  pDevice->iterationNumber, pDevice->rhsNorm,
	  negConc ? "   negative conc in solution" : "");
    }
    if (pDevice->converged) {
      if (!pDevice->poissonOnly) {
	poissNorm = contNorm = 0.0;
	rhs[0] = 0.0;		/* Make sure garbage entry is clear. */
	for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
	  pElem = pDevice->elements[eIndex];
	  for (index = 0; index <= 3; index++) {
	    if (pElem->evalNodes[index]) {
	      pNode = pElem->pNodes[index];
	      poissNorm = MAX(poissNorm,ABS(rhs[pNode->psiEqn]));
	      contNorm = MAX(contNorm,ABS(rhs[pNode->nEqn]));
	      contNorm = MAX(contNorm,ABS(rhs[pNode->pEqn]));
	    }
	  }
	}
	fprintf(stdout,
	    "Residual: %11.4e C/um poisson, %11.4e A/um continuity\n",
	    poissNorm * EpsNorm * VNorm * 1e-4,
	    contNorm * JNorm * LNorm * 1e-4);
      } else {
	fprintf(stdout, "Residual: %11.4e C/um poisson\n",
	    pDevice->rhsNorm * EpsNorm * VNorm * 1e-4);
      }
    }
  }
}