Program Code for Ion Densities in Chemical Equilibrium


/******************************************************************************
*   This PL/1 subroutine calculates the ion densities in local chemical 
*   equilibrium for an arbitray number of constituents under consideration 
*   of ionization, recombination and charge exchange processes.
*   The program is based on the equilibrium condition for the production and 
*   loss rates for the ion species i
*   
*   qi +Σl(≠i)ΣmΣp ki,l,m,p.nl.Nm  = αi.ni.(ni +Σl(≠i)nl) + ni.ΣmΣp ki,m,p.Nm  
*   where
*
*   qi : primary ion production rate for species i
*   αi : recombination coefficient for ion i
*   Nm : neutral density of species m
*   ki,m,p: rate coefficent for charge exchange of ion i with neutral m
*   ki,l,m,p: rate coefficient for reaction of ion l and neutral m resulting in ion i
*
*   (for the charge exchange reactions, the index l sums over all ionized 
*   constituents,  the index m over all corresponding neutral constituents, 
*   and the index p sums over  possible multiple reaction channels (e.g. 
*   N++O2 → N+O2+  and N++O2 → O+NO+) ).
*
*   This is a quadratic equation for the ion density ni which can be 
*   readily solved to yield
*
*   ni = -Ai/2 +[Ai2/4 +qii +1/αi.Σl(≠i)ΣmΣp ki,l,m,p.nl.Nm ]  , 
*
*   where
*
*   Ai = Σl(≠i)nl + 1/αi.ΣmΣp ki,m,p.Nm .
*
*   As this solution is a function of the other ion densities nl, this 
*   constitutes a system of M (the number of constituents) equations 
*   that can be solved by iteration (which is what this program does).
*
*   It is recommended that this program uses internally an extended 
*   numerical accuracy, because of the possibility that near equal numbers 
*   are being subtracted from each other.
*
*
*  Input parameters are:
*    NC:  number of constituents
*    NMC: maximum number of charge exchange channels for any constituent
*    EPSI: desired relative accuracy
*    NEUDEN: neutral gas densities (in cm-3) (vector of length NC)
*    QP: ionization rates (in cm-3sec-1) (vector of length NC)
*             (note that the original vector content is modified in the program)
*    AL: recombination coefficient (in cm3sec-1) (vector of length NC)
*    KR: charge exchange coefficients (in cm3sec-1)(array of dimension NC*NC*NMC)
*    KRL: reaction channels for the production by charge exchange 
*       (=1: reaction is taken into account; otherwise =0) (array of dimension NC*NC*NC*NMC)
*
*  Output parameter is:
*    IONDEN: ion densities (in cm-3) (vector of length NC)
*
*    (other units can be used, but must obviously be consistent).
*
*   This program has worked well and correct for me in the past (using IBM PL/1 compilers),  
*   but I can't guarantee this for all compilers, especially if the code is translated
*   into a different language.
*
*   If there are any problems, please let me know and I mention the issue here.
*   (for contact details see  http://www.plasmaphysics.org.uk/feedback.htm ).
*
*                                               Thomas Smid, April 2007
*********************************************************************************/

 IONDENS:PROCEDURE(NC,NMC,EPSI,NEUDEN,QP,AL,KR,KRL,IONDEN) ;
 DEFAULT RANGE(A:Z) FLOAT DECIMAL VALUE (DEC FLOAT(33)) ;
 DCL (DEN(*),L(*),NREL(*),QN(*),NDEN(*)) CTL DEC FLOAT(33) ;
 DCL (NQN(*),ID(*)) CTL DEC FIXED(7,0) ;
 DCL (NEUDEN(*),QP(*),AL(*),KR(*,*,*)) CTL DEC FLOAT(16) ;
 DCL KRL(*,*,*,*) CTL DEC FIXED(3,0) ;
 DCL (I,J,K,M,N,NC,DI,NMC,SNQN,NUMIT) DEC FIXED(7,0) ;
 DCL IONDEN(*) CTL DEC FLOAT(16) ;
 ON UNDERFLOW ; 


 ALLOCATE L(NC),NREL(NC),NQN(NC),DEN(NC),NDEN(NC) ;
 DEN=0; IONDEN=0; NDEN=0;
 LLIM=1E-33/EPSI ;   /* 1E-33 should be changed to the available precision if different */


 /* Determination of total number of charge exchange gain reactions */
 NQN=0 ;  
 DO M=1 TO NC ;    
 DO I=1 TO NC ; 
 DO J=1 TO NC ; 
 DO K=1 TO NMC ;
 NQN(M)=NQN(M)+KRL(M,I,J,K) ;  
 END ;
 END ;
 END ;
 END ;
 SNQN=SUM(NQN) ;
 ALLOCATE QN(SNQN),ID(SNQN) ;


 /* Calculation of charge exchange loss rates and initial ion densities */
 L=0 ;
 DO I=1 TO NC ; 
 DO J=1 TO NC ; 
 DO K=1 TO NMC ;
 L(I)=L(I)+KR(I,J,K)*NEUDEN(J) ;
 END ;
 END ;
 L(I)=L(I)/2/AL(I)     ;
 QP(I)=QP(I)/AL(I) ;
 DEN(I)=-L(I)+SQRT(QP(I)+L(I)**2);
 IF L(I)>0 THEN DO ;
 QPS=QP(I)/L(I)**2 ;
 IF QPS<LLIM|DEN(I)<LLIM THEN CALL ERPRINT ;
 END ;
 END ;

  /* Calculation of charge exchange gain rates */
 N=1; QN=0; ID=0;
 DO M=1 TO NC ; 
 DO I=1 TO NC ; 
 DO J=1 TO NC ; 
 DO K=1 TO NMC ;
 IF KRL(M,I,J,K)=1 THEN DO ;
 QN(N)=KR(I,J,K)*NEUDEN(J)/AL(M);
 ID(N)=I ;
 N=N+1 ;
 END ;
 END ;
 END ;
 END ;
 END ;

 NDEN=DEN; NUMIT=0;


 SDEV=1; JJ=0; DI=1;
 ITER: DO WHILE(SDEV>=EPSI) ;     /* Iteration loop */
 NUMIT=NUMIT+1; JJ=JJ+1; NDEN=0;
 ELDEN=SUM(DEN) ;
 N=1;
 DO I=1 TO NC ; 
 DO J=1 TO NQN(I) ;
 NDEN(I)=NDEN(I)+QN(N)*DEN(ID(N)) ;
 N=N+1 ;
 END ;
 SQA=-(ELDEN-DEN(I))/2-L(I) ;
 QPN=QP(I)+NDEN(I) ;
 SQAN=SQRT(QPN+SQA**2) ;
 NDEN(I)=SQA+SQAN ;
 IF SQA<0 THEN DO ;
 QPS=QPN/SQA**2 ;
 IF QPS<LLIM|NDEN(I)<LLIM THEN CALL ERPRINT ;
 END ;
 END ;


 DO I=1 TO NC ; 
 IF DEN(I)=0 THEN GO TO CONT1 ; 
 NREL(I)=NDEN(I)/DEN(I) ;
 CONT1:END ;


 SDEV=ABS(NREL(1)-1) ;
 DO I=2 TO NC ; 
 SDEV=MAX(SDEV,ABS(NREL(I)-1)) ;  /* check for convergence */
 END ;
 SDEV=SDEV*JJ ; 
 DEN=NDEN ;

 END ITER ;     /* End 'Iteration loop' */



 IF DI=1 THEN DO ;
 DI=-1; SDEV=1; 
 GO TO ITER ;    /* Additional test iteration after convergence is achieved */
 END ;

 IONDEN=NDEN ;

 FREE DEN,NDEN,L,QN,NREL,ID,NQN ;



 ERPRINT: PROCEDURE ;
 PUT EDIT('DESIRED ACCURACY CAN NOT BE REACHED') (A(35)) ;
 IONDEN=1E50 ;
 GO TO ENDE ;
 END ERPRINT ;



 ENDE:END IONDENS ;


Programs Home

Home