Example #1
0
/*
 * SMPcCombine()
 */
void
SMPcCombine(SMPmatrix *Matrix, double RHS[], double Spare[],
	    double iRHS[], double iSpare[])
{
    spSetComplex( (void *)Matrix );
    spCombine( (void *)Matrix, RHS, Spare, iRHS, iSpare );
}
Example #2
0
/*
 * SMPcReorder()
 */
int
SMPcReorder(SMPmatrix *Matrix, double PivTol, double PivRel,
	    int *NumSwaps)
{
    *NumSwaps = 1;
    spSetComplex( (void *)Matrix );
    return spOrderAndFactor( (void *)Matrix, (spREAL*)NULL,
                             (spREAL)PivRel, (spREAL)PivTol, YES );
}
Example #3
0
/*ARGSUSED*/
int
SMPcLUfac(SMPmatrix *Matrix, double PivTol)
{
    spSetComplex( (void *)Matrix );
    return spFactor( (void *)Matrix );
}
Example #4
0
int
NUMOSadmittance(TWOdevice *pDevice, double omega, struct mosAdmittances *yAc)
{
  TWOcontact *pDContact = pDevice->pFirstContact;
  TWOcontact *pGContact = pDevice->pFirstContact->next;
  TWOcontact *pSContact = pDevice->pFirstContact->next->next;
/*  TWOcontact *pBContact = pDevice->pLastContact; */
  TWOnode *pNode;
  TWOelem *pElem;
  int index, eIndex;
  double width = pDevice->width;
  double dxdy;
  double *solnReal, *solnImag;
  double *rhsReal, *rhsImag;
  BOOLEAN SORFailed;
  SPcomplex *y, cOmega;
  double startTime;

  /* Each time we call this counts as one AC iteration. */
  pDevice->pStats->numIters[STAT_AC] += 1;

  pDevice->solverType = SLV_SMSIG;
  rhsReal = pDevice->rhs;
  rhsImag = pDevice->rhsImag;
  solnReal = pDevice->dcDeltaSolution;
  solnImag = pDevice->copiedSolution;

  /* use a normalized radian frequency */
  omega *= TNorm;
  CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega);

  if ((AcAnalysisMethod == SOR) || (AcAnalysisMethod == SOR_ONLY)) {
    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    /* zero the rhs before loading in the new rhs */
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    storeNewRhs(pDevice, pDContact);
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;
    if (SORFailed && AcAnalysisMethod == SOR) {
      AcAnalysisMethod = DIRECT;
      printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",
	  omega / (TWO_PI * TNorm) );
    } else if (SORFailed) {	/* Told to only do SOR, so give up. */
      printf("SOR failed at %g Hz, returning null admittance.\n",
	  omega / (TWO_PI * TNorm) );
      CMPLX_ASSIGN_VALUE(yAc->yIdVdb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIdVsb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIdVgb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIsVdb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIsVsb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIsVgb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIgVdb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 0.0, 0.0);
      CMPLX_ASSIGN_VALUE(yAc->yIgVgb, 0.0, 0.0);
      return (AcAnalysisMethod);
    } else {
      /* MISC */
      startTime = SPfrontEnd->IFseconds();
      y = contactAdmittance(pDevice, pDContact, TRUE,
	  solnReal, solnImag, &cOmega);
      CMPLX_ASSIGN_VALUE(yAc->yIdVdb, y->real, y->imag);
      y = contactAdmittance(pDevice, pSContact, FALSE,
	  solnReal, solnImag, &cOmega);
      CMPLX_ASSIGN_VALUE(yAc->yIsVdb, y->real, y->imag);
      y = GateTypeAdmittance(pDevice, pGContact, FALSE,
	  solnReal, solnImag, &cOmega);
      CMPLX_ASSIGN_VALUE(yAc->yIgVdb, y->real, y->imag);
      pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

      /* LOAD */
      startTime = SPfrontEnd->IFseconds();
      /* load in the source contribution to the rhs */
      for (index = 1; index <= pDevice->numEqns; index++) {
	rhsImag[index] = 0.0;
      }
      storeNewRhs(pDevice, pSContact);
      pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

      /* SOLVE */
      startTime = SPfrontEnd->IFseconds();
      SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);
      pDevice->pStats->solveTime[STAT_AC] +=
	  SPfrontEnd->IFseconds() - startTime;
      if (SORFailed && AcAnalysisMethod == SOR) {
	AcAnalysisMethod = DIRECT;
	printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",
	    omega / (TWO_PI * TNorm) );
      } else if (SORFailed) {	/* Told to only do SOR, so give up. */
	printf("SOR failed at %g Hz, returning null admittance.\n",
	    omega / (TWO_PI * TNorm) );
	CMPLX_ASSIGN_VALUE(yAc->yIdVdb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIdVsb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIdVgb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIsVdb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIsVsb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIsVgb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIgVdb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 0.0, 0.0);
	CMPLX_ASSIGN_VALUE(yAc->yIgVgb, 0.0, 0.0);
	return (AcAnalysisMethod);
      } else {
	/* MISC */
	startTime = SPfrontEnd->IFseconds();
	y = contactAdmittance(pDevice, pDContact, FALSE,
	    solnReal, solnImag, &cOmega);
	CMPLX_ASSIGN_VALUE(yAc->yIdVsb, y->real, y->imag);
	y = contactAdmittance(pDevice, pSContact, TRUE,
	    solnReal, solnImag, &cOmega);
	CMPLX_ASSIGN_VALUE(yAc->yIsVsb, y->real, y->imag);
	y = GateTypeAdmittance(pDevice, pGContact, FALSE,
	    solnReal, solnImag, &cOmega);
	CMPLX_ASSIGN_VALUE(yAc->yIgVsb, y->real, y->imag);
	pDevice->pStats->miscTime[STAT_AC] +=
	    SPfrontEnd->IFseconds() - startTime;

	/* LOAD */
	startTime = SPfrontEnd->IFseconds();
	/* load in the gate contribution to the rhs */
	for (index = 1; index <= pDevice->numEqns; index++) {
	  rhsImag[index] = 0.0;
	}
	storeNewRhs(pDevice, pGContact);
	pDevice->pStats->loadTime[STAT_AC] +=
	    SPfrontEnd->IFseconds() - startTime;

	/* SOLVE */
	startTime = SPfrontEnd->IFseconds();
	SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);
	pDevice->pStats->solveTime[STAT_AC] +=
	    SPfrontEnd->IFseconds() - startTime;
	if (SORFailed && AcAnalysisMethod == SOR) {
	  AcAnalysisMethod = DIRECT;
	  printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",
	      omega / (TWO_PI * TNorm) );
	} else if (SORFailed) {	/* Told to only do SOR, so give up. */
	  printf("SOR failed at %g Hz, returning null admittance.\n",
	      omega / (TWO_PI * TNorm) );
	  CMPLX_ASSIGN_VALUE(yAc->yIdVdb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIdVsb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIdVgb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIsVdb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIsVsb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIsVgb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIgVdb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 0.0, 0.0);
	  CMPLX_ASSIGN_VALUE(yAc->yIgVgb, 0.0, 0.0);
	  return (AcAnalysisMethod);
	}
      }
    }
  }
  if (AcAnalysisMethod == DIRECT) {
    /* solve the system of equations directly */
    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    storeNewRhs(pDevice, pDContact);

    /* Need to load & factor jacobian once. */
    if (!OneCarrier) {
      TWO_jacLoad(pDevice);
    } else if (OneCarrier == N_TYPE) {
      TWONjacLoad(pDevice);
    } else if (OneCarrier == P_TYPE) {
      TWOPjacLoad(pDevice);
    }
    spSetComplex(pDevice->matrix);
    for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
      pElem = pDevice->elements[eIndex];
      if (pElem->elemType == SEMICON) {
	dxdy = 0.25 * pElem->dx * pElem->dy;
	for (index = 0; index <= 3; index++) {
	  pNode = pElem->pNodes[index];
	  if (pNode->nodeType != CONTACT) {
	    if (!OneCarrier) {
	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);
	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);
	    } else if (OneCarrier == N_TYPE) {
	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);
	    } else if (OneCarrier == P_TYPE) {
	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);
	    }
	  }
	}
      }
    }
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* FACTOR */
    startTime = SPfrontEnd->IFseconds();
    spFactor(pDevice->matrix);
    pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* MISC */
    startTime = SPfrontEnd->IFseconds();
    y = contactAdmittance(pDevice, pDContact, TRUE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIdVdb, y->real, y->imag);
    y = contactAdmittance(pDevice, pSContact, FALSE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIsVdb, y->real, y->imag);
    y = GateTypeAdmittance(pDevice, pGContact, FALSE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIgVdb, y->real, y->imag);
    pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    storeNewRhs(pDevice, pSContact);
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* FACTOR: already done, no need to repeat. */

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* MISC */
    startTime = SPfrontEnd->IFseconds();
    y = contactAdmittance(pDevice, pDContact, FALSE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIdVsb, y->real, y->imag);
    y = contactAdmittance(pDevice, pSContact, TRUE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIsVsb, y->real, y->imag);
    y = GateTypeAdmittance(pDevice, pGContact, FALSE,
	solnReal, solnImag, &cOmega);
    CMPLX_ASSIGN_VALUE(yAc->yIgVsb, y->real, y->imag);
    pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    storeNewRhs(pDevice, pGContact);
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* FACTOR: already done, no need to repeat. */

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;
  }
  /* MISC */
  startTime = SPfrontEnd->IFseconds();
  y = contactAdmittance(pDevice, pDContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIdVgb, y->real, y->imag);
  y = contactAdmittance(pDevice, pSContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIsVgb, y->real, y->imag);
  y = GateTypeAdmittance(pDevice, pGContact, TRUE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIgVgb, y->real, y->imag);

  CMPLX_MULT_SELF_SCALAR(yAc->yIdVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIdVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIdVgb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVgb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVgb, GNorm * width * LNorm);
  pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

  return (AcAnalysisMethod);
}
Example #5
0
int
NUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd)
{
  TWOnode *pNode;
  TWOelem *pElem;
  int index, eIndex;
  double dxdy;
  double *solnReal, *solnImag;
  double *rhsReal, *rhsImag;
  SPcomplex yAc, cOmega, *y;
  BOOLEAN deltaVContact = FALSE;
  BOOLEAN SORFailed;
  double startTime;

  /* Each time we call this counts as one AC iteration. */
  pDevice->pStats->numIters[STAT_AC] += 1;

  /*
   * change context names of solution vectors for ac analysis dcDeltaSolution
   * stores the real part and copiedSolution stores the imaginary part of the
   * ac solution vector
   */
  pDevice->solverType = SLV_SMSIG;
  rhsReal = pDevice->rhs;
  rhsImag = pDevice->rhsImag;
  solnReal = pDevice->dcDeltaSolution;
  solnImag = pDevice->copiedSolution;

  /* use a normalized radian frequency */
  omega *= TNorm;
  CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega);

  if ((AcAnalysisMethod == SOR) || (AcAnalysisMethod == SOR_ONLY)) {
    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    /* zero the rhsImag */
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    /* store the new rhs vector */
    storeNewRhs(pDevice, pDevice->pLastContact);
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;
    if (SORFailed && AcAnalysisMethod == SOR) {
      AcAnalysisMethod = DIRECT;
      printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",
	  omega / (TWO_PI * TNorm) );
    } else if (SORFailed) {	/* Told to only do SOR, so give up. */
      printf("SOR failed at %g Hz, returning null admittance.\n",
	  omega / (TWO_PI * TNorm) );
      CMPLX_ASSIGN_VALUE(*yd, 0.0, 0.0);
      return (AcAnalysisMethod);
    }
  }
  if (AcAnalysisMethod == DIRECT) {
    /* LOAD */
    startTime = SPfrontEnd->IFseconds();
    for (index = 1; index <= pDevice->numEqns; index++) {
      rhsImag[index] = 0.0;
    }
    /* solve the system of equations directly */
    if (!OneCarrier) {
      TWO_jacLoad(pDevice);
    } else if (OneCarrier == N_TYPE) {
      TWONjacLoad(pDevice);
    } else if (OneCarrier == P_TYPE) {
      TWOPjacLoad(pDevice);
    }
    storeNewRhs(pDevice, pDevice->pLastContact);

    spSetComplex(pDevice->matrix);
    for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
      pElem = pDevice->elements[eIndex];
      if (pElem->elemType == SEMICON) {
	dxdy = 0.25 * pElem->dx * pElem->dy;
	for (index = 0; index <= 3; index++) {
	  pNode = pElem->pNodes[index];
	  if (pNode->nodeType != CONTACT) {
	    if (!OneCarrier) {
	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);
	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);
	    } else if (OneCarrier == N_TYPE) {
	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);
	    } else if (OneCarrier == P_TYPE) {
	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);
	    }
	  }
	}
      }
    }
    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* FACTOR */
    startTime = SPfrontEnd->IFseconds();
    spFactor(pDevice->matrix);
    pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

    /* SOLVE */
    startTime = SPfrontEnd->IFseconds();
    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;
  }
  /* MISC */
  startTime = SPfrontEnd->IFseconds();
  y = contactAdmittance(pDevice, pDevice->pFirstContact, deltaVContact,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc, -y->real, -y->imag);
  CMPLX_ASSIGN(*yd, yAc);
  CMPLX_MULT_SELF_SCALAR(*yd, GNorm * pDevice->width * LNorm);
  pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;

  return (AcAnalysisMethod);
}
Example #6
0
void
NUMOSys(TWOdevice *pDevice, SPcomplex *s, struct mosAdmittances *yAc)
{
  TWOcontact *pDContact = pDevice->pFirstContact;
  TWOcontact *pGContact = pDevice->pFirstContact->next;
  TWOcontact *pSContact = pDevice->pFirstContact->next->next;
/*  TWOcontact *pBContact = pDevice->pLastContact; */
  TWOnode *pNode;
  TWOelem *pElem;
  int index, eIndex;
  double width = pDevice->width;
  double dxdy;
  double *rhsReal, *rhsImag;
  double *solnReal, *solnImag;
  SPcomplex *y;
  SPcomplex temp, cOmega;

  pDevice->solverType = SLV_SMSIG;
  rhsReal = pDevice->rhs;
  rhsImag = pDevice->rhsImag;
  solnReal = pDevice->dcDeltaSolution;
  solnImag = pDevice->copiedSolution;

  /* use a normalized radian frequency */
  CMPLX_MULT_SCALAR(cOmega, *s, TNorm);
  for (index = 1; index <= pDevice->numEqns; index++) {
    rhsImag[index] = 0.0;
  }
  /* solve the system of equations directly */
  if (!OneCarrier) {
    TWO_jacLoad(pDevice);
  } else if (OneCarrier == N_TYPE) {
    TWONjacLoad(pDevice);
  } else if (OneCarrier == P_TYPE) {
    TWOPjacLoad(pDevice);
  }
  storeNewRhs(pDevice, pDContact);
  spSetComplex(pDevice->matrix);

  for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
    pElem = pDevice->elements[eIndex];
    if (pElem->elemType == SEMICON) {
      dxdy = 0.25 * pElem->dx * pElem->dy;
      for (index = 0; index <= 3; index++) {
	pNode = pElem->pNodes[index];
	if (pNode->nodeType != CONTACT) {
	  if (!OneCarrier) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag);
	    spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag);
	  } else if (OneCarrier == N_TYPE) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag);
	  } else if (OneCarrier == P_TYPE) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag);
	  }
	}
      }
    }
  }

  spFactor(pDevice->matrix);
  spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);

  y = contactAdmittance(pDevice, pDContact, TRUE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIdVdb, y->real, y->imag);
  y = contactAdmittance(pDevice, pSContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIsVdb, y->real, y->imag);
  y = GateTypeAdmittance(pDevice, pGContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIgVdb, y->real, y->imag);

  for (index = 1; index <= pDevice->numEqns; index++) {
    rhsImag[index] = 0.0;
  }
  storeNewRhs(pDevice, pSContact);
  /* don't need to LU factor the jacobian since it exists */
  spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
  y = contactAdmittance(pDevice, pDContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIdVsb, y->real, y->imag);
  y = contactAdmittance(pDevice, pSContact, TRUE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIsVsb, y->real, y->imag);
  y = GateTypeAdmittance(pDevice, pGContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIgVsb, y->real, y->imag);
  for (index = 1; index <= pDevice->numEqns; index++) {
    rhsImag[index] = 0.0;
  }
  storeNewRhs(pDevice, pGContact);
  spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
  y = contactAdmittance(pDevice, pDContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIdVgb, y->real, y->imag);
  y = contactAdmittance(pDevice, pSContact, FALSE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIsVgb, y->real, y->imag);
  y = GateTypeAdmittance(pDevice, pGContact, TRUE,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc->yIgVgb, y->real, y->imag);

  CMPLX_MULT_SELF_SCALAR(yAc->yIdVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIdVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIdVgb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIsVgb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVdb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVsb, GNorm * width * LNorm);
  CMPLX_MULT_SELF_SCALAR(yAc->yIgVgb, GNorm * width * LNorm);
}
Example #7
0
void
NUMD2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIn)
{
  TWOnode *pNode;
  TWOelem *pElem;
  int index, eIndex;
  double dxdy;
  double *solnReal, *solnImag;
  double *rhsReal, *rhsImag;
  SPcomplex yAc, *y;
  BOOLEAN deltaVContact = FALSE;
  SPcomplex temp, cOmega;

  /*
   * change context names of solution vectors for ac analysis dcDeltaSolution
   * stores the real part and copiedSolution stores the imaginary part of the
   * ac solution vector
   */
  pDevice->solverType = SLV_SMSIG;
  rhsReal = pDevice->rhs;
  rhsImag = pDevice->rhsImag;
  solnReal = pDevice->dcDeltaSolution;
  solnImag = pDevice->copiedSolution;

  /* use a normalized radian frequency */
  CMPLX_MULT_SCALAR(cOmega, *s, TNorm);
  for (index = 1; index <= pDevice->numEqns; index++) {
    rhsImag[index] = 0.0;
  }
  /* solve the system of equations directly */
  if (!OneCarrier) {
    TWO_jacLoad(pDevice);
  } else if (OneCarrier == N_TYPE) {
    TWONjacLoad(pDevice);
  } else if (OneCarrier == P_TYPE) {
    TWOPjacLoad(pDevice);
  }
  storeNewRhs(pDevice, pDevice->pLastContact);

  spSetComplex(pDevice->matrix);
  for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {
    pElem = pDevice->elements[eIndex];
    if (pElem->elemType == SEMICON) {
      dxdy = 0.25 * pElem->dx * pElem->dy;
      for (index = 0; index <= 3; index++) {
	pNode = pElem->pNodes[index];
	if (pNode->nodeType != CONTACT) {
	  if (!OneCarrier) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag);
	    spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag);
	  } else if (OneCarrier == N_TYPE) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag);
	  } else if (OneCarrier == P_TYPE) {
	    CMPLX_MULT_SCALAR(temp, cOmega, dxdy);
	    spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag);
	  }
	}
      }
    }
  }

  spFactor(pDevice->matrix);
  spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);
  y = contactAdmittance(pDevice, pDevice->pFirstContact, deltaVContact,
      solnReal, solnImag, &cOmega);
  CMPLX_ASSIGN_VALUE(yAc, y->real, y->imag);
  CMPLX_ASSIGN(*yIn, yAc);
  CMPLX_NEGATE_SELF(*yIn);
  CMPLX_MULT_SELF_SCALAR(*yIn, GNorm * pDevice->width * LNorm);
}