Пример #1
0
void getBoundary(Atmosphere *atmos, Geometry *geometry)
{
  int  result, Nspect = Nlambda;

  /* --- Read boundary conditions and irradiation. First VERTICAL
         boundary conditions --                            --------- */

  switch (geometry->bvalue[TOP]) {
  case IRRADIATED:
    geometry->Itop = matrix_double(Nspect, geometry->Nx);
    result = xdr_vector(&xdrs, (char *) geometry->Itop[0],
			Nspect*geometry->Nx,
			sizeof(double), (xdrproc_t) xdr_double);
    break;
  default:
    geometry->Itop = NULL;
    break;
  }

  switch (geometry->bvalue[BOTTOM]) {
  case IRRADIATED:
    geometry->Ibottom = matrix_double(Nspect, geometry->Nx);
    result = xdr_vector(&xdrs, (char *) geometry->Ibottom[0],
			Nspect*geometry->Nx,
			sizeof(double), (xdrproc_t) xdr_double);
    break;
  default:
    geometry->Ibottom = NULL;
    break;
  }

  /* --- Get the HORIZONTAL boundary conditions --        ----------- */

  switch (geometry->hboundary) {
  case FIXED:
    geometry->Ileft = matrix_double(Nspect, geometry->Nz);
    result = xdr_vector(&xdrs, (char *) geometry->Ileft[0],
			Nspect*geometry->Nz,
                        sizeof(double), (xdrproc_t) xdr_double);
    geometry->Iright = matrix_double(Nspect, geometry->Nz);
    result = xdr_vector(&xdrs, (char *) geometry->Iright[0],
			Nspect*geometry->Nz,
                        sizeof(double), (xdrproc_t) xdr_double);
    break;
  case PERIODIC:
    geometry->Ileft  = NULL;
    geometry->Iright = NULL;
    break;
  default:
    break;
  }
}
Пример #2
0
void LTEmolecule(Molecule *molecule)
{
    /* --- Calculate partition functions for each molecular vibrational
           state v of the molecule. LTE populations are then given by:

           nv^*[k] = molecule->n * pfv[v][k] / pf[k].

     Note: The actual LTE populations are calculated (in initSolution)
           only after chemical equilibrium has been established.
           --                                            -------------- */

    register int k, v, J, kr;

    char    labelStr[MAX_LINE_SIZE];
    double  kT, gJ, **E;
    MolecularLine *mrt;

    if (!molecule->active) {
        sprintf(messageStr, "Molecule must be active: %s\n", molecule->ID);
        Error(ERROR_LEVEL_2, "LTEmolecule", messageStr);
    }
    /* --- Fill energy matrix --                         -------------- */

    E = matrix_double(molecule->Nv, molecule->NJ);
    for (kr = 0;  kr < molecule->Nrt;  kr++) {
        mrt = molecule->mrt + kr;

        E[mrt->vi][(int) (mrt->gi - 1)/2] = mrt->Ei;
        E[mrt->vj][(int) (mrt->gj - 1)/2] = mrt->Ej;
    }

    for (k = 0;  k < atmos.Nspace;  k++)
        molecule->pf[k] = 0.0;

    for (v = 0;  v < molecule->Nv;  v++) {
        for (J = 0;  J < molecule->NJ;  J++) {
            gJ = 2*J + 1;
            for (k = 0;  k < atmos.Nspace;  k++)
                molecule->pfv[v][k] +=
                    gJ * exp(-E[v][J] / (KBOLTZMANN * atmos.T[k]));
        }
        /*  --- Also store the total partition function here -- --------- */

        for (k = 0;  k < atmos.Nspace;  k++)
            molecule->pf[k] += molecule->pfv[v][k];
    }

    freeMatrix((void **) E);

    sprintf(labelStr, "LTEpops %3s", molecule->ID);
    getCPU(4, TIME_POLL, labelStr);
}
Пример #3
0
/**
Returns the diagonal matrix of singular values.
@return     S
 */
MatrixDouble svd_getS() {

    int i, j;

    if (S_matrix != NULL)
        free_matrix_double(S_matrix, num_columns, num_columns);
    S_matrix = matrix_double(num_columns, num_columns);
    for (i = 0; i < num_columns; i++) {
        for (j = 0; j < num_columns; j++) {
            S_matrix[i][j] = 0.0;
        }
        S_matrix[i][i] = singular_values[i];
    }
    return (S_matrix);
}
Пример #4
0
void readAtmos_ncdf(int xi, int yi, Atmosphere *atmos, Geometry *geometry,
		    NCDF_Atmos_file *infile)
/* Reads the variables T, ne, vel, nh for a given (xi,yi) pair */ 
{
  const char routineName[] = "readAtmos_ncdf";
  size_t     start[]    = {0, 0, 0, 0}; /* starting values */
  size_t     count[]    = {1, 1, 1, 1};
  size_t     start_nh[] = {0, 0, 0, 0, 0};
  size_t     count_nh[] = {1, 1, 1, 1, 1};
  int        ncid, ierror, i, j, z_varid;
  bool_t     old_moving;
  double    *Bx, *By, *Bz;

  ncid = infile->ncid;

  atmos->Nspace = geometry->Ndep = infile->nz;

  /* read full T column, to see where to zcut */
  start[0] = input.p15d_nt; count[0] = 1;
  start[1] = (size_t) xi;   count[1] = 1;
  start[2] = (size_t) yi;   count[2] = 1;
  start[3] = 0;             count[3] = infile->nz;
  
  atmos->T = (double *) realloc(atmos->T, infile->nz * sizeof(double)); 

  if ((ierror = nc_get_vara_double(ncid, infile->T_varid,  start, count, atmos->T)))
    ERR(ierror,routineName);

  /* Finds z value for Tmax cut, redefines Nspace, reallocates arrays */
  /* Tiago: not using this at the moment, only z cut in depth_refine */
  if (input.p15d_zcut) {
    setTcut(atmos, geometry, input.p15d_tmax);
  } else {
    mpi.zcut = 0;
  }

  /* Get z again */
  start[0] = input.p15d_nt; count[0] = 1;
  start[1] = mpi.zcut;      count[1] = atmos->Nspace;

  if ((ierror=nc_inq_varid(ncid, "z",  &z_varid)))          
    ERR(ierror,routineName);
  if ((ierror = nc_get_vara_double(ncid, z_varid, start, count, geometry->height))) 
    ERR(ierror,routineName);
 

  start[0] = input.p15d_nt; count[0] = 1;
  start[1] = (size_t) xi;   count[1] = 1;
  start[2] = (size_t) yi;   count[2] = 1;
  start[3] = mpi.zcut;      count[3] = atmos->Nspace;

   /* read variables */
  if ((ierror = nc_get_vara_double(ncid, infile->T_varid,  start, count, atmos->T)))
    ERR(ierror,routineName);
  if ((ierror = nc_get_vara_double(ncid, infile->ne_varid, start, count, atmos->ne)))
    ERR(ierror,routineName);
  if ((ierror = nc_get_vara_double(ncid, infile->vz_varid, start, count, geometry->vel)))
    ERR(ierror,routineName);
  /* vturb, if available */   
  if (infile->vturb_varid != -1) {
    if ((ierror = nc_get_vara_double(ncid, infile->vturb_varid, &start[3], &count[3],
				     atmos->vturb))) ERR(ierror,routineName);
  }

  /* Read magnetic field */
  if (atmos->Stokes) {
    Bx = (double *) malloc(atmos->Nspace * sizeof(double));
    By = (double *) malloc(atmos->Nspace * sizeof(double));
    Bz = (double *) malloc(atmos->Nspace * sizeof(double));
    /* Read in cartesian coordinates */
    if ((ierror = nc_get_vara_double(ncid, infile->Bx_varid,  start, count,
				     Bx))) ERR(ierror,routineName);
    if ((ierror = nc_get_vara_double(ncid, infile->By_varid,  start, count,
				     By))) ERR(ierror,routineName);
    if ((ierror = nc_get_vara_double(ncid, infile->Bz_varid,  start, count,
				     Bz))) ERR(ierror,routineName);
    
    /* Convert to spherical coordinates */
    for (j = 0; j < atmos->Nspace; j++) {
      atmos->B[j]       = sqrt(SQ(Bx[j]) + SQ(By[j]) + SQ(Bz[j]));
      atmos->gamma_B[j] = acos(Bz[j]/atmos->B[j]);
      atmos->chi_B[j]   = atan(By[j]/Bx[j]);
      
      /* Protect from undefined cases */
      if ((Bx[j] == 0) && (By[j] == 0) && (Bz[j] == 0))
	atmos->gamma_B[j] = 0.0;
      
      if ((Bx[j] == 0) && (By[j] == 0))
	atmos->chi_B[j]   = 1.0;
    }

    free(Bx); free(By); free(Bz);
  }
  


  /* allocate and zero nHtot */
  atmos->nH = matrix_double(atmos->NHydr, atmos->Nspace);  
  for (j = 0; j < atmos->Nspace; j++) atmos->nHtot[j] = 0.0; 

  /* read nH, all at once */
  start_nh[0] = input.p15d_nt; count_nh[0] = 1;
  start_nh[1] = 0;             count_nh[1] = atmos->NHydr;
  start_nh[2] = (size_t) xi;   count_nh[2] = 1;
  start_nh[3] = (size_t) yi;   count_nh[3] = 1;
  start_nh[4] = mpi.zcut;      count_nh[4] = atmos->Nspace;
  if ((ierror = nc_get_vara_double(ncid, infile->nh_varid, start_nh, count_nh, 
				   atmos->nH[0]))) ERR(ierror,routineName);

  /* Depth grid refinement */
  if (input.p15d_refine)
    depth_refine(atmos, geometry, input.p15d_tmax);
  
  /* Fix vturb: remove zeros, use multiplier and add */
  for (i = 0; i < atmos->Nspace; i++) {
    if (atmos->vturb[i] < 0.0) atmos->vturb[i] = 0.0;
    atmos->vturb[i] = atmos->vturb[i] * input.vturb_mult + input.vturb_add;
  }

  /* Sum to get nHtot */
  for (i = 0; i < atmos->NHydr; i++){
    for (j = 0; j < atmos->Nspace; j++) atmos->nHtot[j] += atmos->nH[i][j];
  }
  
  /* Some other housekeeping */
  old_moving = atmos->moving;
  atmos->moving = FALSE;
  for (i = 0;  i < atmos->Nspace;  i++) {
    if (fabs(geometry->vel[i]) >= atmos->vmacro_tresh) {
      atmos->moving = TRUE;
      /* old_moving should only be false*/
      if ((old_moving == FALSE) & (atmos->moving == TRUE)) {
	sprintf(messageStr,
		"Moving atmosphere detected when the previous column\n"
		" (or column [0,0] in file) was not. This will cause problems\n"
		" and the code will abort.\n"
		" To prevent this situation one can force all columns\n"
		" to be moving by setting VMACRO_TRESH = 0 in keyword.input\n");
	Error(ERROR_LEVEL_2, routineName, messageStr);
      }
      break;
    }
  }

  return;
}
Пример #5
0
Ellipsoid3D CalcErrorEllipsoid(Mtrx3D *pcov, double del_chi_2) {
    int ndx, iSwitched;
    MatrixDouble A_matrix, V_matrix;
    VectorDouble W_vector;
    double wtemp, vtemp;
    Ellipsoid3D ell;

    int ierr = 0;


    /* allocate A mtrx */
    A_matrix = matrix_double(3, 3);

    /* load A matrix in NumRec format */
    A_matrix[0][0] = pcov->xx;
    A_matrix[0][1] = A_matrix[1][0] = pcov->xy;
    A_matrix[0][2] = A_matrix[2][0] = pcov->xz;
    A_matrix[1][1] = pcov->yy;
    A_matrix[1][2] = A_matrix[2][1] = pcov->yz;
    A_matrix[2][2] = pcov->zz;


    /* allocate V mtrx and W vector */
    V_matrix = matrix_double(3, 3);
    W_vector = vector_double(3);

    /* do SVD */
    //if ((istat = nll_svdcmp0(A_matrix, 3, 3, W_vector, V_matrix)) < 0) {
    svd_helper(A_matrix, 3, 3, W_vector, V_matrix);
    if (W_vector[0] < SMALL_DOUBLE || W_vector[1] < SMALL_DOUBLE || W_vector[2] < SMALL_DOUBLE) {
        fprintf(stderr, "ERROR: invalid SVD singular value for confidence ellipsoids.");
        ierr = 1;
    } else {

        /* sort by singular values W */
        iSwitched = 1;
        while (iSwitched) {
            iSwitched = 0;
            for (ndx = 0; ndx < 2; ndx++) {
                if (W_vector[ndx] > W_vector[ndx + 1]) {
                    wtemp = W_vector[ndx];
                    W_vector[ndx] = W_vector[ndx + 1];
                    W_vector[ndx + 1] = wtemp;
                    vtemp = V_matrix[0][ndx];
                    V_matrix[0][ndx] = V_matrix[0][ndx + 1];
                    V_matrix[0][ndx + 1] = vtemp;
                    vtemp = V_matrix[1][ndx];
                    V_matrix[1][ndx] = V_matrix[1][ndx + 1];
                    V_matrix[1][ndx + 1] = vtemp;
                    vtemp = V_matrix[2][ndx];
                    V_matrix[2][ndx] = V_matrix[2][ndx + 1];
                    V_matrix[2][ndx + 1] = vtemp;
                    iSwitched = 1;
                }
            }
        }


        /* calculate ellipsoid axes */
        /* length: w in Num Rec, 2nd ed, fig 15.6.5 must be replaced
                by 1/sqrt(w) since we are using SVD of Cov mtrx and not
                SVD of A mtrx (compare eqns 2.6.1  & 15.6.10) */

        ell.az1 = atan2(V_matrix[0][0], V_matrix[1][0]) * RA2DE;
        if (ell.az1 < 0.0)
            ell.az1 += 360.0;
        ell.dip1 = asin(V_matrix[2][0]) * RA2DE;
        ell.len1 = sqrt(del_chi_2) / sqrt(1.0 / W_vector[0]);
        ell.az2 = atan2(V_matrix[0][1], V_matrix[1][1]) * RA2DE;
        if (ell.az2 < 0.0)
            ell.az2 += 360.0;
        ell.dip2 = asin(V_matrix[2][1]) * RA2DE;
        ell.len2 = sqrt(del_chi_2) / sqrt(1.0 / W_vector[1]);
        ell.len3 = sqrt(del_chi_2) / sqrt(1.0 / W_vector[2]);

    }

    free_matrix_double(A_matrix, 3, 3);
    free_matrix_double(V_matrix, 3, 3);
    free_vector_double(W_vector);

    if (ierr) {
        Ellipsoid3D EllipsoidNULL = {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0};
        return (EllipsoidNULL);
    }

    return (ell);

}
Пример #6
0
Файл: escape.c Проект: kouui/rh
/* ------- begin ----------------------------- Escape ------------------- */
void Escape(Atom *atom) {
    /*
      
      Calculates radiative rates using the escape probability approximation

      
      Notes: Escape is inserted in an atom loop. Whatever takes place here should be at
             atom-only level. Why? Because different atoms can have different starting solutions.
             Calling Opacity directly is probably overkill, as it does its own loops, and
             works per wavelength, not per atom.
             
              The line opacity has to be per transition, and thus averaged in wavelength.
              For bound-bound the procedure is the following:
                 
              1. Loop over wavelength to calculate opacity at all wavelengths. Keep an
                 array for each transition, accumulate there the opacity * wla for each
                 transition. (this opacity is depth-dependent as well)
                    
              2. Loop over transitions (and not wavelength!), calculate tau by integrating
                 over depth for each transition
                    
              3. Once we have tau for each transition, add to the gamma of each transition
                 (in the same loop) the nrb recipe.
                    
              For bound-free the procedure is the following:
              
              1. Calculate intensity only for the relevant wavelenths.
              
              2. Using intensity, calculate proper radiative rates and add them to rate matrix.
              
              
    Notes for continuum:

          * To see how rates are added, look at fillgamma.addtoRates or fillgamma.addtoGamma
          * For a simplified version of how to calculate intensity and update rates, look
            at formal.c:233 (the angle-independent case). They could be calculated by a single
            call of Formal, but there is too much rubbish in the main routine, and it could
            call opacity and readbackground more than once -- duplicating many tasks.
      
      
    */
    
    
    const char routineName[] = "Escape";
    register int     n, k, kr, i, ij, ji, nspect;
    int              la, j, nt,  mu, nact;
    double         **opa, *chi, *I, *S, *Psi, *Jdag, *J, tau, wlambda, hc_4PI, twohc,
                     twohnu3_c2, wmu, wlamu, Ieff;
    bool_t           initialize, to_obs;
    ActiveSet       *as;
    AtomicLine      *line;
    AtomicContinuum *continuum;
    
    
    /* --- Some useful constants --                        -------------- */
    hc_4PI = HPLANCK * CLIGHT / (4.0 * PI);
    twohc = 2.0*HPLANCK*CLIGHT / CUBE(NM_TO_M);
    

    opa  = matrix_double(atom->Nline, atmos.Nspace);
    Jdag = (double *) malloc(atmos.Nspace * sizeof(double));
    Psi  = (double *) malloc(atmos.Nspace * sizeof(double));
    chi  = (double *) malloc(atmos.Nspace * sizeof(double));
    I    = (double *) malloc(atmos.Nspace * sizeof(double));
    S    = (double *) malloc(atmos.Nspace * sizeof(double));


    nact = atom->activeindex;
    
    /* Calculate opacities */
    for (nspect = 0;  nspect < spectrum.Nspect;  nspect++) { 
        as = spectrum.as + nspect;
        alloc_as(nspect, FALSE);
        
        nt = nspect % input.Nthreads;

        /* Get line and background opacity */
        Opacity(nspect, 0, to_obs=TRUE, initialize=TRUE); 

	if (input.backgr_in_mem) {
	  loadBackground(nspect, 0, to_obs=TRUE);
	} else {
	  readBackground(nspect, 0, to_obs=TRUE);
	}
        
        /* --- For bound-bound: store opacity in array, per transition -- */
        for (kr = 0; kr < atom->Nline; kr++) {
            line = atom->line + kr;
            la = nspect - line->Nblue;
            
            if (la == 0)
                wlambda = getwlambda_line(line, la);
                
            if ((la >= 0) && (la < line->Nlambda)) {
                /* increment opacities with each wavelength, multiplying by the
                   integration weights */
                for (k = 0 ; k < atmos.Nspace; k++) 
                    opa[kr][k] += (as->chi[k] + as->chi_c[k]) * (wlambda * line->wphi[k] /
                                                                    hc_4PI);
            }
        }
        
        /* --- For bound-free: calculate intensity and update rates ----- */        
        for (n = 0;  n < as->Nactiveatomrt[nact];  n++) {      
            if (as->art[nact][n].type == ATOMIC_CONTINUUM) {
                
                continuum = as->art[nact][n].ptype.continuum;
                la = nspect - continuum->Nblue;
                i = continuum->i;
                j = continuum->j;
                ij = i*atom->Nlevel + j;
                ji = j*atom->Nlevel + i;
                
                twohnu3_c2 = twohc / CUBE(spectrum.lambda[nspect]);
                
                /* Use old J and zero new array */
                if (input.limit_memory) {
                    J = (double *) malloc(atmos.Nspace *sizeof(double));
                    //readJlambda_single(nspect, Jdag);
                } else {
                    J = spectrum.J[nspect];
                    for (k = 0;  k < atmos.Nspace;  k++) Jdag[k] = J[k];
                }
                for (k = 0;  k < atmos.Nspace;  k++) J[k] = 0.0;
                
                for (mu = 0; mu < atmos.Nrays; mu++) {
                    wmu = 0.5 * geometry.wmu[mu];
                        
                    for (k = 0;  k < atmos.Nspace;  k++) {
                        chi[k] = as->chi[k] + as->chi_c[k];
                        S[k]   = (as->eta[k] +
                            as->eta_c[k] + as->sca_c[k]*Jdag[k]) / chi[k];
                    } 
                     
                    /* Get intensity */
                    Piecewise_1D(nspect, mu, to_obs=TRUE, chi, S, I, Psi);
                    
                    /* Update rates */
                    for (k = 0;  k < atmos.Nspace;  k++) {
                        
                        Ieff = I[k] - Psi[k] * atom->rhth[nt].eta[k];
                        wlamu = atom->rhth[nt].Vij[n][k] * atom->rhth[nt].wla[n][k] * wmu;
                        
                        atom->Gamma[ji][k] += Ieff * wlamu;
                        atom->Gamma[ij][k] += (twohnu3_c2 + Ieff) * atom->rhth[nt].gij[n][k] * wlamu;
                        
                        /*  Accumulate mean intensity */
                        J[k] += wmu * I[k];
                    }                    
                }
                if (input.limit_memory) free(J);
            }
        }
        
        free_as(nspect, FALSE);
    }  

    /* Bound-bound: calculate optical depth and add approximation to rates */  
    for (kr = 0; kr < atom->Nline; kr++) {
        line = atom->line + kr;
        i  = line->i;
        j  = line->j;
        ij = i*atom->Nlevel + j;

        tau = 0.0;
        
        for (k = 0; k < atmos.Nspace ; k++) {
            if (k > 0) {
                tau += 0.5*(opa[kr][k-1] + opa[kr][k]) *
                    (geometry.height[k-1] - geometry.height[k]);
            }
            
            /* add escape probability approximation to the rates matrix */
            atom->Gamma[ij][k] += line->Aji * Pesc(tau);   
        }

    }
    
    freeMatrix((void **) opa);
    free(Jdag);
    free(chi);
    free(Psi);
    free(I);
    free(S);
}
Пример #7
0
void SolveLongStokes(Geometry *geometry, Longchar *lc,
		     int nspect, int k, int l, int m,
		     double *chi, double **S, double **I,
		     double *I_uw)
{
  register int ls, n, j;

  int    local;
  double c1, c2, dtau_dw, dS_uw[4], dS_dw[4], w[3],
         chi_loc, S_loc[4], dtau_uw, chi_uw, S_uw[4], chi_dw, S_dw[4],
         P[4], Q[4][4], **R, K[4][4], K_uw[4][4];

  R = matrix_double(4, 4);

  /* --- The first point is the intersection with the horizontal
         grid line --                                  -------------- */

  chi_uw = Interpolate_3D(chi, geometry, &lc->stencil[0], l, m);
  StokesK_3D(nspect, geometry, &lc->stencil[0], l, m, chi_uw, K_uw);
  for (n = 0;  n < 4;  n++) {
    S_uw[n]  = Interpolate_3D(S[n], geometry, &lc->stencil[0], l, m);
    I_uw[n]  = Interpolate_3D(I[n], geometry, &lc->stencil[0], l, m);
  }

  chi_loc = Interpolate_3D(chi, geometry, &lc->stencil[1], l, m);
  dtau_uw = 0.5 * (chi_uw + chi_loc) * lc->stencil[0].ds;
  StokesK_3D(nspect, geometry, &lc->stencil[1], l, m, chi_loc, K);
  for (n = 0;  n < 4;  n++)
    S_loc[n] = Interpolate_3D(S[n], geometry, &lc->stencil[1], l, m);

  for (ls = 2;  ls < lc->Nst;  ls++) {
    if (ls == lc->Nst-1) {

      /* --- The last point is the the endpoint for which the non-local
             contribution is needed. --                -------------- */

      local  = k*geometry->Nplane + m*geometry->Nx + l;
      chi_dw = chi[local];
      for (n = 0;  n < 4;  n++) S_dw[n] = S[n][local];
    } else {
      chi_dw = Interpolate_3D(chi, geometry, &lc->stencil[ls], l, m);
      for (n = 0;  n < 4;  n++)
	S_dw[n] = Interpolate_3D(S[n], geometry, &lc->stencil[ls], l, m);
    }
    dtau_dw = 0.5 * (chi_loc + chi_dw) * lc->stencil[ls-1].ds;
    w3(dtau_uw, w);

    for (n = 0;  n < 4;  n++) {
      dS_uw[n] = (S_uw[n] - S_loc[n]) / dtau_uw;
      dS_dw[n] = (S_loc[n] - S_dw[n]) / dtau_dw;
      c1 = dS_uw[n]*dtau_dw + dS_dw[n]*dtau_uw;
      c2 = dS_uw[n] - dS_dw[n];
      P[n] = w[0]*S_loc[n] + (w[1]*c1 + w[2]*c2) / (dtau_uw + dtau_dw);
    }
    for (n = 0;  n < 4;  n++) {
      for (j = 0;  j < 4;  j++) {
	Q[n][j] = -w[1]/dtau_uw * K_uw[n][j];
	R[n][j] = (w[0] - w[1]/dtau_uw) * K[n][j];
      }
      Q[n][n] = 1.0 - w[0];
      R[n][n] = 1.0;
    }
    for (n = 0;  n < 4;  n++) {
      for (j = 0;  j < 4;  j++) 
	P[n] += Q[n][j] * I_uw[j];
    }
    /* --- Solve linear equations for I --             -------------- */

    SolveLinearEq(4, R, P, TRUE);

    /* --- Store results for the upwind Stokes vector -- ------------ */
    
    for (n = 0;  n < 4;  n++) I_uw[n] = P[n];

    /* --- Reuse upwind quantities --                  -------------- */

    if (ls < lc->Nst-1) {
      chi_uw  = chi_loc;
      chi_loc = chi_dw;
      dtau_uw = dtau_dw;

      for (n = 0;  n < 4;  n++) {
	S_uw[n]  = S_loc[n];
	S_loc[n] = S_dw[n];
	for (j = 0;  j < 4;  j++) K_uw[n][j] = K[n][j];
      }
      StokesK_3D(nspect, geometry, &lc->stencil[ls], l, m, chi_dw, K);
    }
  }
  freeMatrix((void **) R);
}
Пример #8
0
void MULTIatmos(Atmosphere *atmos, Geometry *geometry)
{
  const char routineName[] = "MULTIatmos";
  register int k, n, mu;

  char    scaleStr[20], inputLine[MAX_LINE_SIZE], *filename;
  bool_t  exit_on_EOF, enhanced_atmos_ID = FALSE;
  int     Nread, Ndep, Nrequired, checkPoint;
  double *dscale, turbpress, turbelecpress, nbaryon, meanweight;
  struct  stat statBuffer;

  getCPU(2, TIME_START, NULL);

  /* --- Get abundances of background elements --        ------------ */
 
  readAbundance(atmos);

  /* --- Open the input file for model atmosphere in MULTI format - - */

  if ((atmos->fp_atmos = fopen(input.atmos_input, "r")) == NULL) {
    sprintf(messageStr, "Unable to open inputfile %s", input.atmos_input);
    Error(ERROR_LEVEL_2, routineName, messageStr);
  } else {
    sprintf(messageStr, "\n -- reading input file: %s\n\n",
	    input.atmos_input);
    Error(MESSAGE, NULL, messageStr);
  }

  atmos->NHydr = N_HYDROGEN_MULTI;

  /* --- Boundary condition at TOP of atmosphere --      ------------ */

  if (strcmp(input.Itop, "none"))
    geometry->vboundary[TOP] = IRRADIATED;
  else 
    geometry->vboundary[TOP] = ZERO;

  /* --- Boundary condition at BOTTOM of atmosphere --   ------------ */

  geometry->vboundary[BOTTOM] = THERMALIZED;

  /* --- Read atmos ID, scale type, gravity, and number of depth
         points --                                       ------------ */
 
  getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine, exit_on_EOF=TRUE);
  if (enhanced_atmos_ID) {

    /* --- Construct atmosID from filename and last modification date */

    stat(input.atmos_input, &statBuffer);
    if ((filename = strrchr(input.atmos_input, '/')) != NULL)
      filename++;
    else
      filename = input.atmos_input;
    sprintf(atmos->ID, "%s (%.24s)", filename,
	    asctime(localtime(&statBuffer.st_mtime)));
    Nread = 1;
  } else
    Nread = sscanf(inputLine, "%s", atmos->ID);

  getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine, exit_on_EOF=TRUE);
  Nread += sscanf(inputLine, "%20s", scaleStr);
  getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine, exit_on_EOF=TRUE);
  Nread += sscanf(inputLine, "%lf", &atmos->gravity);
  getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine, exit_on_EOF=TRUE);
  Nread += sscanf(inputLine, "%d", &geometry->Ndep);
  checkNread(Nread, Nrequired=4, routineName, checkPoint=1);

  /* --- Keep duplicates of some of the geometrical quantities in
         Atmos structure --                            -------------- */

  atmos->Ndim = 1;
  atmos->N = (int *) malloc(atmos->Ndim * sizeof(int));
  atmos->Nspace = Ndep = geometry->Ndep;
  atmos->N[0] = Ndep;

  atmos->gravity = POW10(atmos->gravity) * CM_TO_M;

  /* --- Allocate space for arrays that define structure -- --------- */

  geometry->tau_ref = (double *) malloc(Ndep * sizeof(double));
  geometry->cmass   = (double *) malloc(Ndep * sizeof(double));
  geometry->height  = (double *) malloc(Ndep * sizeof(double));
  atmos->T      = (double *) malloc(Ndep * sizeof(double));
  atmos->ne     = (double *) malloc(Ndep * sizeof(double));
  atmos->vturb  = (double *) malloc(Ndep * sizeof(double));
  geometry->vel = (double *) malloc(Ndep * sizeof(double));

  dscale = (double *) malloc(Ndep * sizeof(double));
  for (k = 0;  k < Ndep;  k++) {
    getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine, exit_on_EOF=TRUE);
    Nread = sscanf(inputLine, "%lf %lf %lf %lf %lf",
		   &dscale[k], &atmos->T[k], &atmos->ne[k],
		   &geometry->vel[k], &atmos->vturb[k]);
    checkNread(Nread, Nrequired=5, routineName, checkPoint=2);
  }

  switch(toupper(scaleStr[0])) {
  case 'M':
    geometry->scale = COLUMN_MASS;
    for (k = 0;  k < Ndep;  k++)
      geometry->cmass[k] = POW10(dscale[k]) * (G_TO_KG / SQ(CM_TO_M));
    break;
  case 'T':
    geometry->scale = TAU500;
    for (k = 0;  k < Ndep;  k++) geometry->tau_ref[k] = POW10(dscale[k]);
    break;
  case 'H':
    geometry->scale = GEOMETRIC;
    for (k = 0;  k < Ndep;  k++) geometry->height[k] = dscale[k] * KM_TO_M;
    break;
  default:
    sprintf(messageStr, "Unknown depth scale string in file %s: %s",
	    input.atmos_input, scaleStr);
    Error(ERROR_LEVEL_2, routineName, messageStr);
  }
  free(dscale);

  for (k = 0;  k < Ndep;  k++) {
    geometry->vel[k] *= KM_TO_M;
    atmos->vturb[k]  *= KM_TO_M;
    atmos->ne[k]     /= CUBE(CM_TO_M);
  }
  atmos->moving = FALSE;
  for (k = 0;  k < Ndep;  k++) {
    if (fabs(geometry->vel[k]) >= atmos->vmacro_tresh) {
      atmos->moving = TRUE;
      break;
    }
  }
  /* --- Get angle-quadrature and copy geometry independent quantity
         wmu to atmos structure. --                    -------------- */

  getAngleQuad(geometry);
  atmos->wmu = geometry->wmu;

  /* --- Magnetic field is read here. --               -------------- */

  atmos->Stokes = readB(atmos);

  /* --- Read Hydrogen populations if present --       -------------- */

  atmos->nH = matrix_double(atmos->NHydr, Ndep);
  for (k = 0;  k < Ndep;  k++) {
    if (getLine(atmos->fp_atmos, MULTI_COMMENT_CHAR, inputLine,
		exit_on_EOF=FALSE) == EOF) break;
    Nread = sscanf(inputLine, "%lf %lf %lf %lf %lf %lf",
		   &atmos->nH[0][k], &atmos->nH[1][k], &atmos->nH[2][k],
		   &atmos->nH[3][k], &atmos->nH[4][k], &atmos->nH[5][k]);
    checkNread(Nread, Nrequired=6, routineName, checkPoint=3);
  }
  if (k > 0  &&  k < Ndep) {
    sprintf(messageStr,
	    "Reached end of input file %s before all data was read",
	    input.atmos_input);
    Error(ERROR_LEVEL_2, routineName, messageStr);
  } else if (k == 0) {

    /* --- No hydrogen populations supplied: use LTE populations
           like MULTI does --                          -------------- */

    if (geometry->scale != COLUMN_MASS) {
      sprintf(messageStr,
	      "Height scale should be COLUMNMASS when nH not supplied: "
	      "File %s", input.atmos_input);
      Error(ERROR_LEVEL_2, routineName, messageStr);
    }
    atmos->nHtot = (double *) calloc(Ndep, sizeof(double));

    atmos->H_LTE = TRUE;
    meanweight = atmos->avgMolWght * AMU;
    for (k = 0;  k < Ndep;  k++) {
      turbpress     = 0.5 * meanweight * SQ(atmos->vturb[k]);
      turbelecpress = 0.5 * M_ELECTRON * SQ(atmos->vturb[k]);

      nbaryon =
	(atmos->gravity * geometry->cmass[k] -
	 atmos->ne[k] *(KBOLTZMANN * atmos->T[k] + turbelecpress));

      atmos->nHtot[k] =	nbaryon / 
	(atmos->totalAbund * (KBOLTZMANN * atmos->T[k] + turbpress));
    }
  } else if (k == Ndep) {
    atmos->nHtot = (double *) calloc(Ndep, sizeof(double));
    for (n = 0;  n < atmos->NHydr;  n++) {
      for (k = 0;  k < Ndep;  k++) {
	atmos->nH[n][k] /= CUBE(CM_TO_M);
	atmos->nHtot[k] += atmos->nH[n][k];
      }
    }
  }

  getCPU(2, TIME_POLL, "Read Atmosphere");
}
Пример #9
0
Файл: barklem.c Проект: kouui/rh
bool_t readBarklemTable(enum Barklemtype type, Barklemstruct *bs)
{
  register int n, i, j;
  const char routineName[] = "readBarklemTable";

  char    filename[MAX_LINE_SIZE], inputLine[MAX_LINE_SIZE], *charptr;
  int     nread;
  double  neff1_0, neff2_0;
  FILE   *fp_Barklem;

  switch (type) {
  case SP:
    strcpy(filename, BARKLEM_SP_DATA);
    bs->N1 = BARKLEM_SP_NS;
    bs->N2 = BARKLEM_SP_NP;

    neff1_0 = BARKLEM_SP_NEFF1;
    neff2_0 = BARKLEM_SP_NEFF2;
    break;

  case PD:
    strcpy(filename, BARKLEM_PD_DATA);
    bs->N1 = BARKLEM_PD_NP;
    bs->N2 = BARKLEM_PD_ND;

    neff1_0 = BARKLEM_PD_NEFF1;
    neff2_0 = BARKLEM_PD_NEFF2;
    break;

  case DF:
    strcpy(filename, BARKLEM_DF_DATA);
    bs->N1 = BARKLEM_DF_ND;
    bs->N2 = BARKLEM_DF_NF;

    neff1_0 = BARKLEM_DF_NEFF1;
    neff2_0 = BARKLEM_DF_NEFF2;
    break;
  }

  if ((fp_Barklem = fopen(filename, "r")) == NULL) {
    sprintf(messageStr, "Unable to open input file %s", filename);
    Error(ERROR_LEVEL_1, routineName, messageStr);
    return FALSE;
  }

  bs->neff1 = (double *) malloc(bs->N1 * sizeof(double));
  for (n = 0;  n < bs->N1;  n++)
    bs->neff1[n] = neff1_0 + n * BARKLEM_DELTA_NEFF;

  bs->neff2 = (double *) malloc(bs->N2 * sizeof(double));
  for (n = 0;  n < bs->N2;  n++)
    bs->neff2[n] = neff2_0 + n * BARKLEM_DELTA_NEFF;

  bs->cross = matrix_double(bs->N1, bs->N2);
  bs->alpha = matrix_double(bs->N1, bs->N2);

  for (n = 0;  n < 3;  n++)
    charptr = fgets(inputLine, MAX_LINE_SIZE, fp_Barklem);

  for (i = 0;  i < bs->N1;  i++)
    for (j = 0;  j < bs->N2;  j++) {
      nread = fscanf(fp_Barklem, "%lf", &bs->cross[i][j]);
  }
  for (n = 0;  n < 2;  n++)
    charptr = fgets(inputLine, MAX_LINE_SIZE, fp_Barklem);

  for (i = 0;  i < bs->N1;  i++)
    for (j = 0;  j < bs->N2;  j++) {
      nread = fscanf(fp_Barklem, "%lf", &bs->alpha[i][j]);
  }

  fclose(fp_Barklem);
  return TRUE;
}
Пример #10
0
void statEquil(Atom *atom, int isum)
{
  register int i, j, ij, k;

  int    i_eliminate, Nlevel;
  double GamDiag, nmax_k, *n_k, **Gamma_k;

  getCPU(3, TIME_START, NULL);

  Nlevel = atom->Nlevel;

  /* --- Need temporary storage because Gamma has to be solved spatial
         point by spatial point while depth is normally the fastest
         running index --                              -------------- */

  n_k     = (double *) malloc(Nlevel * sizeof(double));
  Gamma_k = matrix_double(Nlevel, Nlevel);

  for (k = 0;  k < atmos.Nspace;  k++) {
    for (i = 0, ij = 0;  i < Nlevel;  i++) {
      n_k[i] = atom->n[i][k];
      for (j = 0;  j < Nlevel;  j++, ij++)
	Gamma_k[i][j] = atom->Gamma[ij][k];
    }

    if (isum == -1) {
      i_eliminate  = 0;
      nmax_k = 0.0;
      for (i = 0;  i < Nlevel;  i++) {
	if (n_k[i] > nmax_k) {
	  nmax_k = n_k[i];
	  i_eliminate = i;
	}
      }
    } else
      i_eliminate = isum;

    /* --- For each column i sum over rows to get diagonal elements - */

    for (i = 0;  i < Nlevel;  i++) {
      GamDiag = 0.0;
      Gamma_k[i][i] = 0.0;
      n_k[i] = 0.0;

      for (j = 0;  j < Nlevel;  j++) GamDiag += Gamma_k[j][i];
      Gamma_k[i][i] = -GamDiag;
    }
    /* --- Close homogeneous set with particle conservation-- ------- */

    n_k[i_eliminate] = atom->ntotal[k];
    for (j = 0;  j < Nlevel;  j++) Gamma_k[i_eliminate][j] = 1.0;

    /* --- Solve for new population numbers at location k -- -------- */

    SolveLinearEq(Nlevel, Gamma_k, n_k, TRUE);
    if (mpi.stop) {
      free(n_k);
      freeMatrix((void **) Gamma_k);
      return; /* Get out if there is a singular matrix */
    }

    for (i = 0;  i < Nlevel;  i++) atom->n[i][k] = n_k[i];
  }

  free(n_k);
  freeMatrix((void **) Gamma_k);

  getCPU(3, TIME_POLL, "Stat Equil");
}
Пример #11
0
void ASENSOR::VoltsDoubleToColumnVector( double v[], matrix &V )
{
    V.dim(1,DAQ_ChannelCount);
    matrix_double(v,V);
}
Пример #12
0
void SolveShortStokes(Geometry *geometry, Stencil *st_uw, Stencil *st_dw,
		      int nspect, int k, int kend, int l, int m,
		      double *I_uw,
		      double *chi, double **S, double **I, double *Psi)
{
  /* --- Piecewise integration of the coupled Stokes transfer equations
         in two dimensions. Method is quasi-parabolic DELO method.

    See: - D. E. Rees, G. A. Murphy and C. J. Durrant 1989, ApJ 339,
           1093-1106.

         - H. Socas Navarro, J. Trujillo Bueno and B. Ruiz Cobo 2000,
           "Non-LTE Inversion of Stokes Profiles", ApJ 530, 977.
      --                                               -------------- */

  register int n, j;

  int    local;
  double chi_uw, chi_dw, S_uw[4], S_dw[4], dS_dw[4], dS_uw[4],
         dtau_uw, dtau_dw, w[3], c1, c2, P[4], Q[4][4], **R,
         K[4][4], K_uw[4][4]; 

  R = matrix_double(4, 4);

  local = k*geometry->Nplane + m*geometry->Nx + l;

  /* --- The upwind quantities --                      -------------- */

  chi_uw  = Interpolate_3D(chi, geometry, st_uw, l, m);
  dtau_uw = 0.5 * (chi_uw + chi[local]) * st_uw->ds;
  StokesK_3D(nspect, geometry, st_uw, l, m, chi_uw, K_uw);

  for (n = 0;  n < 4;  n++) {
    S_uw[n]  = Interpolate_3D(S[n], geometry, st_uw, l, m);
    dS_uw[n] = (S_uw[n] - S[n][local]) / dtau_uw;
  }
  StokesK(nspect, local, chi[local], K);

  if (k == kend) {
    w2(dtau_uw, w);

    /* --- Piecewise linear integration in last layer -- ------------ */

    for (n = 0;  n < 4;  n++) {
      c1 = (S_uw[n] - S[n][local]) / dtau_uw;
      P[n] = w[0]*S[n][local] + w[1]*dS_uw[n];
    }
    if (Psi) Psi[local] = w[0] - w[1]/dtau_uw;
  } else {
    w3(dtau_uw, w);

    /* --- The downwind quantities --                  -------------- */

    chi_dw  = Interpolate_3D(chi, geometry, st_dw, l, m);
    dtau_dw = 0.5 * (chi[local] + chi_dw) * st_dw->ds;

    /* --- Piecewise quadratic integration --          -------------- */

    for (n = 0;  n < 4;  n++) {
      S_dw[n]  = Interpolate_3D(S[n], geometry, st_dw, l, m);
      dS_dw[n] = (S[n][local] - S_dw[n]) / dtau_dw;
      c1 = dS_uw[n]*dtau_dw + dS_dw[n]*dtau_uw;
      c2 = dS_uw[n] - dS_dw[n];
      P[n] = w[0]*S[n][local] + (w[1]*c1 + w[2]*c2) /
	(dtau_uw + dtau_dw);
    }
    if (Psi) {
      c1 = dtau_uw - dtau_dw;
      Psi[local] = w[0] + (w[1]*c1 - w[2]) / (dtau_uw * dtau_dw);
    }
  }
  for (n = 0;  n < 4;  n++) {
    for (j = 0;  j < 4;  j++) {
      Q[n][j] = -w[1]/dtau_uw * K_uw[n][j];
      R[n][j] = (w[0] - w[1]/dtau_uw) * K[n][j];
    }
    Q[n][n] = 1.0 - w[0];
    R[n][n] = 1.0;
  }
  for (n = 0;  n < 4;  n++) {
    for (j = 0;  j < 4;  j++) 
      P[n] += Q[n][j] * I_uw[j];
  }
  /* --- Solve linear equations for I --               -------------- */
      
  SolveLinearEq(4, R, P, TRUE);
      
  /* --- Store results for Stokes vector --            -------------- */
      
  for (n = 0;  n < 4;  n++) I[n][local] = P[n];

  freeMatrix((void **) R);
}
Пример #13
0
/**
Constructs and returns a new singular value decomposition object;
The decomposed matrices can be retrieved via instance methods of the returned decomposition object.
@param A    A rectangular matrix.
@return     A decomposition object to access <tt>U</tt>, <tt>S</tt> and <tt>V</tt>.
@throws IllegalArgumentException if <tt>A.rows() < A.columns()</tt>.
 */
void SingularValueDecomposition(MatrixDouble A_matrix_orig, int nrows, int ncolumns) {

    int i, j, k;
    //Property.DEFAULT.checkRectangular(Arg);


    // Derived from LINPACK code.
    // Initialize.
    num_rows = nrows;
    num_columns = ncolumns;

    // make local copy of original A matrix
    MatrixDouble A_matrix = matrix_double(num_rows, num_columns);
    for (i = 0; i < num_rows; i++) {
        for (j = 0; j < num_columns; j++) {
            A_matrix[i][j] = A_matrix_orig[i][j];
        }
    }

    clean_SingularValueDecomposition();

    int nu = Math_min(num_rows, num_columns);
    singular_values = vector_double(Math_min(num_rows + 1, num_columns));
    U_matrix = matrix_double(num_rows, nu);
    V_matrix = matrix_double(num_columns, num_columns);
    double *e = calloc(num_columns, sizeof (double));
    double *work = calloc(num_rows, sizeof (double));

    int wantu = 1;
    int wantv = 1;

    // Reduce A to bidiagonal form, storing the diagonal elements
    // in s and the super-diagonal elements in e.

    int nct = Math_min(num_rows - 1, num_columns);
    int nrt = Math_max(0, Math_min(num_columns - 2, num_rows));
    for (k = 0; k < Math_max(nct, nrt); k++) {
        if (k < nct) {

            // Compute the transformation for the k-th column and
            // place the k-th diagonal in s[k].
            // Compute 2-norm of k-th column without under/overflow.
            singular_values[k] = 0;
            for (i = k; i < num_rows; i++) {
                singular_values[k] = Algebra_hypot(singular_values[k], A_matrix[i][k]);
            }
            if (singular_values[k] != 0.0) {
                if (A_matrix[k][k] < 0.0) {
                    singular_values[k] = -singular_values[k];
                }
                for (i = k; i < num_rows; i++) {
                    A_matrix[i][k] /= singular_values[k];
                }
                A_matrix[k][k] += 1.0;
            }
            singular_values[k] = -singular_values[k];
        }
        for (j = k + 1; j < num_columns; j++) {
            if ((k < nct) & (singular_values[k] != 0.0)) {

                // Apply the transformation.

                double t = 0;
                for (i = k; i < num_rows; i++) {
                    t += A_matrix[i][k] * A_matrix[i][j];
                }
                t = -t / A_matrix[k][k];
                for (i = k; i < num_rows; i++) {
                    A_matrix[i][j] += t * A_matrix[i][k];
                }
            }

            // Place the k-th row of A into e for the
            // subsequent calculation of the row transformation.

            e[j] = A_matrix[k][j];
        }
        if (wantu & (k < nct)) {

            // Place the transformation in U for subsequent back
            // multiplication.

            for (i = k; i < num_rows; i++) {
                U_matrix[i][k] = A_matrix[i][k];
            }
        }
        if (k < nrt) {

            // Compute the k-th row transformation and place the
            // k-th super-diagonal in e[k].
            // Compute 2-norm without under/overflow.
            e[k] = 0;
            for (i = k + 1; i < num_columns; i++) {
                e[k] = Algebra_hypot(e[k], e[i]);
            }
            if (e[k] != 0.0) {
                if (e[k + 1] < 0.0) {
                    e[k] = -e[k];
                }
                for (i = k + 1; i < num_columns; i++) {
                    e[i] /= e[k];
                }
                e[k + 1] += 1.0;
            }
            e[k] = -e[k];
            if ((k + 1 < num_rows) & (e[k] != 0.0)) {

                // Apply the transformation.

                for (i = k + 1; i < num_rows; i++) {
                    work[i] = 0.0;
                }
                for (j = k + 1; j < num_columns; j++) {
                    for (i = k + 1; i < num_rows; i++) {
                        work[i] += e[j] * A_matrix[i][j];
                    }
                }
                for (j = k + 1; j < num_columns; j++) {
                    double t = -e[j] / e[k + 1];
                    for (i = k + 1; i < num_rows; i++) {
                        A_matrix[i][j] += t * work[i];
                    }
                }
            }
            if (wantv) {

                // Place the transformation in V for subsequent
                // back multiplication.

                for (i = k + 1; i < num_columns; i++) {
                    V_matrix[i][k] = e[i];
                }
            }
        }
    }

    // Set up the final bidiagonal matrix or order p.

    int p = Math_min(num_columns, num_rows + 1);
    if (nct < num_columns) {
        singular_values[nct] = A_matrix[nct][nct];
    }
    if (num_rows < p) {
        singular_values[p - 1] = 0.0;
    }
    if (nrt + 1 < p) {
        e[nrt] = A_matrix[nrt][p - 1];
    }
    e[p - 1] = 0.0;

    // If required, generate U.

    if (wantu) {
        for (j = nct; j < nu; j++) {
            for (i = 0; i < num_rows; i++) {
                U_matrix[i][j] = 0.0;
            }
            U_matrix[j][j] = 1.0;
        }
        for (k = nct - 1; k >= 0; k--) {
            if (singular_values[k] != 0.0) {
                for (j = k + 1; j < nu; j++) {
                    double t = 0;
                    for (i = k; i < num_rows; i++) {
                        t += U_matrix[i][k] * U_matrix[i][j];
                    }
                    t = -t / U_matrix[k][k];
                    for (i = k; i < num_rows; i++) {
                        U_matrix[i][j] += t * U_matrix[i][k];
                    }
                }
                for (i = k; i < num_rows; i++) {
                    U_matrix[i][k] = -U_matrix[i][k];
                }
                U_matrix[k][k] = 1.0 + U_matrix[k][k];
                for (i = 0; i < k - 1; i++) {
                    U_matrix[i][k] = 0.0;
                }
            } else {
                for (i = 0; i < num_rows; i++) {
                    U_matrix[i][k] = 0.0;
                }
                U_matrix[k][k] = 1.0;
            }
        }
    }

    // If required, generate V.

    if (wantv) {
        for (k = num_columns - 1; k >= 0; k--) {
            if ((k < nrt) & (e[k] != 0.0)) {
                for (j = k + 1; j < nu; j++) {
                    double t = 0;
                    for (i = k + 1; i < num_columns; i++) {
                        t += V_matrix[i][k] * V_matrix[i][j];
                    }
                    t = -t / V_matrix[k + 1][k];
                    for (i = k + 1; i < num_columns; i++) {
                        V_matrix[i][j] += t * V_matrix[i][k];
                    }
                }
            }
            for (i = 0; i < num_columns; i++) {
                V_matrix[i][k] = 0.0;
            }
            V_matrix[k][k] = 1.0;
        }
    }

    // Main iteration loop for the singular values.

    int pp = p - 1;
    int iter = 0;
    double eps = pow(2.0, -52.0);
    while (p > 0) {
        int k, kase;

        // Here is where a test for too many iterations would go.

        // This section of the program inspects for
        // negligible elements in the s and e arrays.  On
        // completion the variables kase and k are set as follows.

        // kase = 1     if s(p) and e[k-1] are negligible and k<p
        // kase = 2     if s(k) is negligible and k<p
        // kase = 3     if e[k-1] is negligible, k<p, and
        //              s(k), ..., s(p) are not negligible (qr step).
        // kase = 4     if e(p-1) is negligible (convergence).

        for (k = p - 2; k >= -1; k--) {
            if (k == -1) {
                break;
            }
            if (fabs(e[k]) <= eps * (fabs(singular_values[k]) + fabs(singular_values[k + 1]))) {
                e[k] = 0.0;
                break;
            }
        }
        if (k == p - 2) {
            kase = 4;
        } else {
            int ks;
            for (ks = p - 1; ks >= k; ks--) {
                if (ks == k) {
                    break;
                }
                double t = (ks != p ? fabs(e[ks]) : 0.) +
                        (ks != k + 1 ? fabs(e[ks - 1]) : 0.);
                if (fabs(singular_values[ks]) <= eps * t) {
                    singular_values[ks] = 0.0;
                    break;
                }
            }
            if (ks == k) {
                kase = 3;
            } else if (ks == p - 1) {
                kase = 1;
            } else {
                kase = 2;
                k = ks;
            }
        }
        k++;

        // Perform the task indicated by kase.

        switch (kase) {

                // Deflate negligible s(p).

            case 1:
            {
                double f = e[p - 2];
                e[p - 2] = 0.0;
                for (j = p - 2; j >= k; j--) {
                    double t = Algebra_hypot(singular_values[j], f);
                    double cs = singular_values[j] / t;
                    double sn = f / t;
                    singular_values[j] = t;
                    if (j != k) {
                        f = -sn * e[j - 1];
                        e[j - 1] = cs * e[j - 1];
                    }
                    if (wantv) {
                        for (i = 0; i < num_columns; i++) {
                            t = cs * V_matrix[i][j] + sn * V_matrix[i][p - 1];
                            V_matrix[i][p - 1] = -sn * V_matrix[i][j] + cs * V_matrix[i][p - 1];
                            V_matrix[i][j] = t;
                        }
                    }
                }
            }
                break;

                // Split at negligible s(k).

            case 2:
            {
                double f = e[k - 1];
                e[k - 1] = 0.0;
                for (j = k; j < p; j++) {
                    double t = Algebra_hypot(singular_values[j], f);
                    double cs = singular_values[j] / t;
                    double sn = f / t;
                    singular_values[j] = t;
                    f = -sn * e[j];
                    e[j] = cs * e[j];
                    if (wantu) {
                        for (i = 0; i < num_rows; i++) {
                            t = cs * U_matrix[i][j] + sn * U_matrix[i][k - 1];
                            U_matrix[i][k - 1] = -sn * U_matrix[i][j] + cs * U_matrix[i][k - 1];
                            U_matrix[i][j] = t;
                        }
                    }
                }
            }
                break;

                // Perform one qr step.

            case 3:
            {

                // Calculate the shift.

                double scale = Math_max(Math_max(Math_max(Math_max(
                        fabs(singular_values[p - 1]), fabs(singular_values[p - 2])), fabs(e[p - 2])),
                        fabs(singular_values[k])), fabs(e[k]));
                double sp = singular_values[p - 1] / scale;
                double spm1 = singular_values[p - 2] / scale;
                double epm1 = e[p - 2] / scale;
                double sk = singular_values[k] / scale;
                double ek = e[k] / scale;
                double b = ((spm1 + sp)*(spm1 - sp) + epm1 * epm1) / 2.0;
                double c = (sp * epm1)*(sp * epm1);
                double shift = 0.0;
                if ((b != 0.0) | (c != 0.0)) {
                    shift = sqrt(b * b + c);
                    if (b < 0.0) {
                        shift = -shift;
                    }
                    shift = c / (b + shift);
                }
                double f = (sk + sp)*(sk - sp) + shift;
                double g = sk*ek;

                // Chase zeros.

                for (j = k; j < p - 1; j++) {
                    double t = Algebra_hypot(f, g);
                    double cs = f / t;
                    double sn = g / t;
                    if (j != k) {
                        e[j - 1] = t;
                    }
                    f = cs * singular_values[j] + sn * e[j];
                    e[j] = cs * e[j] - sn * singular_values[j];
                    g = sn * singular_values[j + 1];
                    singular_values[j + 1] = cs * singular_values[j + 1];
                    if (wantv) {
                        for (i = 0; i < num_columns; i++) {
                            t = cs * V_matrix[i][j] + sn * V_matrix[i][j + 1];
                            V_matrix[i][j + 1] = -sn * V_matrix[i][j] + cs * V_matrix[i][j + 1];
                            V_matrix[i][j] = t;
                        }
                    }
                    t = Algebra_hypot(f, g);
                    cs = f / t;
                    sn = g / t;
                    singular_values[j] = t;
                    f = cs * e[j] + sn * singular_values[j + 1];
                    singular_values[j + 1] = -sn * e[j] + cs * singular_values[j + 1];
                    g = sn * e[j + 1];
                    e[j + 1] = cs * e[j + 1];
                    if (wantu && (j < num_rows - 1)) {
                        for (i = 0; i < num_rows; i++) {
                            t = cs * U_matrix[i][j] + sn * U_matrix[i][j + 1];
                            U_matrix[i][j + 1] = -sn * U_matrix[i][j] + cs * U_matrix[i][j + 1];
                            U_matrix[i][j] = t;
                        }
                    }
                }
                e[p - 2] = f;
                iter = iter + 1;
            }
                break;

                // Convergence.

            case 4:
            {

                // Make the singular values positive.

                if (singular_values[k] <= 0.0) {
                    singular_values[k] = (singular_values[k] < 0.0 ? -singular_values[k] : 0.0);
                    if (wantv) {
                        for (i = 0; i <= pp; i++) {
                            V_matrix[i][k] = -V_matrix[i][k];
                        }
                    }
                }

                // Order the singular values.

                while (k < pp) {
                    if (singular_values[k] >= singular_values[k + 1]) {
                        break;
                    }
                    double t = singular_values[k];
                    singular_values[k] = singular_values[k + 1];
                    singular_values[k + 1] = t;
                    if (wantv && (k < num_columns - 1)) {
                        for (i = 0; i < num_columns; i++) {
                            t = V_matrix[i][k + 1];
                            V_matrix[i][k + 1] = V_matrix[i][k];
                            V_matrix[i][k] = t;
                        }
                    }
                    if (wantu && (k < num_rows - 1)) {
                        for (i = 0; i < num_rows; i++) {
                            t = U_matrix[i][k + 1];
                            U_matrix[i][k + 1] = U_matrix[i][k];
                            U_matrix[i][k] = t;
                        }
                    }
                    k++;
                }
                iter = 0;
                p--;
            }
                break;
        }
    }


    // clean up
    free(e);
    e = NULL;
    free(work);
    work = NULL;
    free_matrix_double(A_matrix, num_rows, nu);

}
Пример #14
0
void distribute_nH()
{
  const char routineName[] = "distribute_nH";
  register int k, i;

  char    config[4], *ptr;
  int    *quantumNo, iq;
  long    Nspace = atmos.Nspace;
  double *g_total, g_i;

  /* --- Redistribute the hydrogen levels for use in the background
         opacity package.

         Use the following conventions:

         1 -- To save memory:
              - let atmos.np point to atmos.H.n[atmos.H.Nlevel-1]
              - let nH2 point to atmos.molecules[0].n;

         2 -- atmos.nHtot represents the total number of hydrogen
              atoms in neutral atoms, protons, H-, and H2 and H2+
              molecules. So in general atmos.nHtot != atmos.H.ntotal.

         3 -- In case of LTE (set by atmos.H_LTE, see keyword.input)
              let atmos.H.n point to the LTE equivalents atmos.H.nstar.

     --                                                -------------- */

  if (atmos.H_LTE) {
    atmos.H->NLTEpops = FALSE;
    Error(MESSAGE, routineName,
	  "\nUsing LTE hydrogen populations for background opacities\n\n");

    /* --- To save memory space let atmos.H->n point to LTE populations
           atmos.H->nstar --                           -------------- */

    if (!atmos.H->active)
      atmos.H->n = atmos.H->nstar;
    else {
      for (i = 0;  i < atmos.H->Nlevel;  i++) {
	for (k = 0;  k < Nspace;  k++)
	  atmos.H->n[i][k] = atmos.H->nstar[i][k];
      }
    }
  } else {
    atmos.H->NLTEpops = TRUE;
    if (!atmos.H->active)
      atmos.H->n = matrix_double(atmos.H->Nlevel, atmos.Nspace);

    /* --- Find principal quantum number from label --   ------------ */
    
    quantumNo = (int *) malloc((atmos.H->Nlevel - 1) * sizeof(int));
    g_total   = (double *) calloc(atmos.NHydr - 1, sizeof(double));
    
    for (i = 0;  i < atmos.H->Nlevel-1;  i++) {
      sscanf(atmos.H->label[i], "H I %s", config);
      ptr = config;  while (isdigit(*ptr)) ptr++;  *ptr = ' ';
      sscanf(config, "%d", &quantumNo[i]);

      if (quantumNo[i] < atmos.NHydr)
	g_total[quantumNo[i] - 1] += atmos.H->g[i];
    }
    /* --- Now redistribute atmosphere's Hydrogen populations over
           the levels of atom H --                     -------------- */
    
    for (i = 0;  i < atmos.H->Nlevel-1;  i++) {
      if (quantumNo[i] < atmos.NHydr) {
	iq  = quantumNo[i] - 1;
	g_i = atmos.H->g[i] / g_total[iq];
	for (k = 0;  k < Nspace;  k++)
	  atmos.H->n[i][k] = g_i * atmos.nH[iq][k];
      } else {
        sprintf(messageStr, "Too many hydrogen levels (level n = %d)\n"
		" Background opacity additional levels set to zero%s",
		quantumNo[i], (i == atmos.H->Nlevel-2) ? "\n\n" : "");
	Error(WARNING, routineName, messageStr);
      }
    }    
    free(quantumNo);  free(g_total);

    /* --- The protons come last --                    -------------- */

    for (k = 0;  k < Nspace;  k++)
      atmos.H->n[atmos.H->Nlevel-1][k] = atmos.nH[atmos.NHydr-1][k];
  }
  /* --- Free memory for atmospheric populations --    -------------- */

  freeMatrix((void **) atmos.nH);
}
Пример #15
0
int
main( int argc, char *argv[] )
{
	extern void dummy( void * );

	float aa, *a, *b, *c, *x, *y;
	double aad, *ad, *bd, *cd, *xd, *yd;
	int i, j, n;
	int inner = 0;
	int vector = 0;
	int matrix = 0;
	int double_precision = 0;
	int retval = PAPI_OK;
	char papi_event_str[PAPI_MIN_STR_LEN] = "PAPI_FP_OPS";
	int papi_event;
	int EventSet = PAPI_NULL;

/* Parse the input arguments */
	for ( i = 0; i < argc; i++ ) {
		if ( strstr( argv[i], "-i" ) )
			inner = 1;
		else if ( strstr( argv[i], "-v" ) )
			vector = 1;
		else if ( strstr( argv[i], "-m" ) )
			matrix = 1;
		else if ( strstr( argv[i], "-e" ) ) {
			if ( ( argv[i + 1] == NULL ) || ( strlen( argv[i + 1] ) == 0 ) ) {
				print_help( argv );
				exit( 1 );
			}
			strncpy( papi_event_str, argv[i + 1], sizeof ( papi_event_str ) );
			i++;
		} else if ( strstr( argv[i], "-d" ) )
			double_precision = 1;
		else if ( strstr( argv[i], "-h" ) ) {
			print_help( argv );
			exit( 1 );
		}
	}

	/* if no options specified, set all tests to TRUE */
	if ( inner + vector + matrix == 0 )
		inner = vector = matrix = 1;


	tests_quiet( argc, argv );	/* Set TESTS_QUIET variable */

	if ( !TESTS_QUIET )
		printf( "Initializing..." );

	/* Initialize PAPI */
	retval = PAPI_library_init( PAPI_VER_CURRENT );
	if ( retval != PAPI_VER_CURRENT )
		test_fail( __FILE__, __LINE__, "PAPI_library_init", retval );

	/* Translate name */
	retval = PAPI_event_name_to_code( papi_event_str, &papi_event );
	if ( retval != PAPI_OK )
		test_fail( __FILE__, __LINE__, "PAPI_event_name_to_code", retval );

	if ( PAPI_query_event( papi_event ) != PAPI_OK )
		test_skip( __FILE__, __LINE__, "PAPI_query_event", PAPI_ENOEVNT );

	if ( ( retval = PAPI_create_eventset( &EventSet ) ) != PAPI_OK )
		test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval );

	if ( ( retval = PAPI_add_event( EventSet, papi_event ) ) != PAPI_OK )
		test_fail( __FILE__, __LINE__, "PAPI_add_event", retval );

	printf( "\n" );

	retval = PAPI_OK;

	/* Inner Product test */
	if ( inner ) {
		/* Allocate the linear arrays */
	   if (double_precision) {
	        xd = malloc( INDEX5 * sizeof(double) );
	        yd = malloc( INDEX5 * sizeof(double) );
		if ( !( xd && yd ) )
			retval = PAPI_ENOMEM;
	   }
	   else {
	        x = malloc( INDEX5 * sizeof(float) );
		y = malloc( INDEX5 * sizeof(float) );
		if ( !( x && y ) )
			retval = PAPI_ENOMEM;
	   }

		if ( retval == PAPI_OK ) {
			headerlines( "Inner Product Test", TESTS_QUIET );

			/* step through the different array sizes */
			for ( n = 0; n < INDEX5; n++ ) {
				if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) {

					/* Initialize the needed arrays at this size */
					if ( double_precision ) {
						for ( i = 0; i <= n; i++ ) {
							xd[i] = ( double ) rand(  ) * ( double ) 1.1;
							yd[i] = ( double ) rand(  ) * ( double ) 1.1;
						}
					} else {
						for ( i = 0; i <= n; i++ ) {
							x[i] = ( float ) rand(  ) * ( float ) 1.1;
							y[i] = ( float ) rand(  ) * ( float ) 1.1;
						}
					}

					/* reset PAPI flops count */
					reset_flops( "Inner Product Test", EventSet );

					/* do the multiplication */
					if ( double_precision ) {
						aad = inner_double( n, xd, yd );
						dummy( ( void * ) &aad );
					} else {
						aa = inner_single( n, x, y );
						dummy( ( void * ) &aa );
					}
					resultline( n, 1, EventSet );
				}
			}
		}
		if (double_precision) {
			free( xd );
			free( yd );
		} else {
			free( x );
			free( y );
		}
	}

	/* Matrix Vector test */
	if ( vector && retval != PAPI_ENOMEM ) {
		/* Allocate the needed arrays */
	  if (double_precision) {
	        ad = malloc( INDEX5 * INDEX5 * sizeof(double) );
	        xd = malloc( INDEX5 * sizeof(double) );
	        yd = malloc( INDEX5 * sizeof(double) );
		if ( !( ad && xd && yd ) )
			retval = PAPI_ENOMEM;
	  } else {
	        a = malloc( INDEX5 * INDEX5 * sizeof(float) );
	        x = malloc( INDEX5 * sizeof(float) );
	        y = malloc( INDEX5 * sizeof(float) );
		if ( !( a && x && y ) )
			retval = PAPI_ENOMEM;
	  }

		if ( retval == PAPI_OK ) {
			headerlines( "Matrix Vector Test", TESTS_QUIET );

			/* step through the different array sizes */
			for ( n = 0; n < INDEX5; n++ ) {
				if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) {

					/* Initialize the needed arrays at this size */
					if ( double_precision ) {
						for ( i = 0; i <= n; i++ ) {
							yd[i] = 0.0;
							xd[i] = ( double ) rand(  ) * ( double ) 1.1;
							for ( j = 0; j <= n; j++ )
								ad[i * n + j] =
									( double ) rand(  ) * ( double ) 1.1;
						}
					} else {
						for ( i = 0; i <= n; i++ ) {
							y[i] = 0.0;
							x[i] = ( float ) rand(  ) * ( float ) 1.1;
							for ( j = 0; j <= n; j++ )
								a[i * n + j] =
									( float ) rand(  ) * ( float ) 1.1;
						}
					}

					/* reset PAPI flops count */
					reset_flops( "Matrix Vector Test", EventSet );

					/* compute the resultant vector */
					if ( double_precision ) {
						vector_double( n, ad, xd, yd );
						dummy( ( void * ) yd );
					} else {
						vector_single( n, a, x, y );
						dummy( ( void * ) y );
					}
					resultline( n, 2, EventSet );
				}
			}
		}
		if (double_precision) {
			free( ad );
			free( xd );
			free( yd );
		} else {
			free( a );
			free( x );
			free( y );
		}
	}

	/* Matrix Multiply test */
	if ( matrix && retval != PAPI_ENOMEM ) {
		/* Allocate the needed arrays */
	  if (double_precision) {
	        ad = malloc( INDEX5 * INDEX5 * sizeof(double) );
	        bd = malloc( INDEX5 * INDEX5 * sizeof(double) );
	        cd = malloc( INDEX5 * INDEX5 * sizeof(double) );
		if ( !( ad && bd && cd ) )
			retval = PAPI_ENOMEM;
	  } else {
	        a = malloc( INDEX5 * INDEX5 * sizeof(float) );
	        b = malloc( INDEX5 * INDEX5 * sizeof(float) );
	        c = malloc( INDEX5 * INDEX5 * sizeof(float) );
		if ( !( a && b && c ) )
			retval = PAPI_ENOMEM;
	  }


		if ( retval == PAPI_OK ) {
			headerlines( "Matrix Multiply Test", TESTS_QUIET );

			/* step through the different array sizes */
			for ( n = 0; n < INDEX5; n++ ) {
				if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) {

					/* Initialize the needed arrays at this size */
					if ( double_precision ) {
						for ( i = 0; i <= n * n + n; i++ ) {
							cd[i] = 0.0;
							ad[i] = ( double ) rand(  ) * ( double ) 1.1;
							bd[i] = ( double ) rand(  ) * ( double ) 1.1;
						}
					} else {
						for ( i = 0; i <= n * n + n; i++ ) {
							c[i] = 0.0;
							a[i] = ( float ) rand(  ) * ( float ) 1.1;
							b[i] = ( float ) rand(  ) * ( float ) 1.1;
						}
					}

					/* reset PAPI flops count */
					reset_flops( "Matrix Multiply Test", EventSet );

					/* compute the resultant matrix */
					if ( double_precision ) {
						matrix_double( n, cd, ad, bd );
						dummy( ( void * ) c );
					} else {
						matrix_single( n, c, a, b );
						dummy( ( void * ) c );
					}
					resultline( n, 3, EventSet );
				}
			}
		}
		if (double_precision) {
			free( ad );
			free( bd );
			free( cd );
		} else {
			free( a );
			free( b );
			free( c );
		}
	}

	/* exit with status code */
	if ( retval == PAPI_ENOMEM )
		test_fail( __FILE__, __LINE__, "malloc", retval );
	else
		test_pass( __FILE__, NULL, 0 );
	exit( 1 );
}
Пример #16
0
void initSolution(Atom *atom, Molecule *molecule)
{
    const char routineName[] = "initSolution";
    register int k, i, ij, nspect, mu, n, kr, nact;

    char    permission[3];
    bool_t  result, openJfile;
    int     la, j, niter, Nsr, Nplane, index, status, oflag;
    double  gijk, wla, twohnu3_c2, hc_k, twoc, fourPI, *J, *J20;
    ActiveSet *as;
    AtomicLine *line;
    AtomicContinuum *continuum;
    XDR xdrs;
    double cswitch;
    int to_obs,lamuk,sign,ncoef,ilow,Nlamu,lamu;
    long int idx, lc;
    double *lambda,fac,lambda_prv,lambda_gas,lambda_nxt,dl,frac,lag;
    FILE *fp;

    getCPU(2, TIME_START, NULL);

    /* Collisional-radiative switching ? */
    if (input.crsw != 0.0)
        cswitch = input.crsw_ini;
    else
        cswitch = 1.0;

    /* --- Allocate space for angle-averaged mean intensity -- -------- */
    if (!input.limit_memory)
        spectrum.J = matrix_double(spectrum.Nspect, atmos.Nspace);

    /* --- If we do background polarization we need space for the
       anisotropy --                               -------------- */

    if (input.backgr_pol)
        spectrum.J20 = matrix_double(spectrum.Nspect, atmos.Nspace);

    /* --- For the PRD angle approximation  we need to store J in
        the gas frame,                                   -------- */
    if (input.PRD_angle_dep == PRD_ANGLE_APPROX &&  atmos.NPRDactive > 0) {

        spectrum.Jgas  = matrix_double(spectrum.Nspect, atmos.Nspace);
        spectrum.v_los = matrix_double(    atmos.Nrays, atmos.Nspace);

        /* Calculate line of sight velocity */
        for (mu = 0;  mu < atmos.Nrays;  mu++) {
            for (k = 0;  k < atmos.Nspace;  k++) {
                spectrum.v_los[mu][k] = vproject(k, mu); // / vbroad[k];
            }
        }


        /* precompute prd_rho interpolation coefficients if requested */
        if (!input.prdh_limit_mem) {

            for (nact = 0;  nact < atmos.Nactiveatom;  nact++) {

                atom = atmos.activeatoms[nact];

                for (kr = 0;  kr < atom->Nline;  kr++) {

                    line = &atom->line[kr];

                    if (line->PRD) {

                        Nlamu = 2*atmos.Nrays * line->Nlambda;
                        line->frac = matrix_double(Nlamu, atmos.Nspace);
                        line->id0  = matrix_int(Nlamu, atmos.Nspace);
                        line->id1  = matrix_int(Nlamu, atmos.Nspace);

                        for (la = 0;  la < line->Nlambda;  la++) {
                            for (mu = 0;  mu < atmos.Nrays;  mu++) {
                                for (to_obs = 0;  to_obs <= 1;  to_obs++) {
                                    sign = (to_obs) ? 1.0 : -1.0;
                                    lamu = 2*(atmos.Nrays*la + mu) + to_obs;

                                    for (k = 0;  k < atmos.Nspace;  k++) {

                                        // wavelength in local rest frame
                                        lag=line->lambda[la] * (1.+spectrum.v_los[mu][k]*sign/CLIGHT);

                                        if (lag <= line->lambda[0]) {
                                            // out of the lambda table, constant extrapolation
                                            line->frac[lamu][k]=0.0;
                                            line->id0[lamu][k]=0;
                                            line->id1[lamu][k]=1;
                                        } else if (lag >= line->lambda[line->Nlambda-1] ) {
                                            // out of the lambda table, constant extrapolation
                                            line->frac[lamu][k]=1.0;
                                            line->id0[lamu][k]=line->Nlambda-2;
                                            line->id1[lamu][k]=line->Nlambda-1;
                                        } else {
                                            // Locate index of line->lambda of point directly to the left of lag
                                            Locate(line->Nlambda,line->lambda,lag,&ilow);
                                            line->frac[lamu][k] = (lag-line->lambda[ilow])/ (line->lambda[ilow+1]-line->lambda[ilow]);
                                            line->id0[lamu][k]=ilow;
                                            line->id1[lamu][k]=ilow+1;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        /* precompute Jgas interpolation coefficients if requested */
        if (!input.prdh_limit_mem) {

            lambda = spectrum.lambda;

            /* --- keeps track of where to get indices and interpolation
                   coefficients in spectrum.iprhh and spectrum.cprdh --- */
            spectrum.nc=  (int *) malloc( 2*atmos.Nrays*spectrum.Nspect*atmos.Nspace * sizeof(int));

            for (la = 0;  la < spectrum.Nspect;  la++) {
                for (mu = 0;  mu < atmos.Nrays;  mu++) {
                    for (to_obs = 0;  to_obs <= 1;  to_obs++) {

                        sign = (to_obs) ? 1.0 : -1.0;

                        for (k = 0;  k < atmos.Nspace;  k++) {

                            lamuk = la * (atmos.Nrays*2*atmos.Nspace)
                                    + mu     * (2*atmos.Nspace)
                                    + to_obs * (atmos.Nspace)
                                    + k ;

                            ncoef=0;

                            // previous, current and next wavelength shifted to gas rest frame
                            fac = (1.+spectrum.v_los[mu][k]*sign/CLIGHT);
                            lambda_prv = lambda[ MAX(la-1,0)                 ]*fac;
                            lambda_gas = lambda[ la                          ]*fac;
                            lambda_nxt = lambda[ MIN(la+1,spectrum.Nspect-1) ]*fac;

                            // do lambda_prv and lambda_gas bracket lambda points?
                            if (lambda_prv !=  lambda_gas) {
                                dl= lambda_gas - lambda_prv;
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] > lambda_prv && lambda[idx] <= lambda_gas) ncoef=ncoef+1;
                                }
                            } else {
                                // edge case, use constant extrapolation for lambda[idx]<lambda gas
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] <=  lambda_gas) ncoef=ncoef+1;
                                }
                            }

                            // do lambda_gas and lambda_nxt bracket lambda points?
                            if (lambda_gas != lambda_nxt) {
                                dl= lambda_nxt - lambda_gas;
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] > lambda_gas && lambda[idx] < lambda_nxt) ncoef=ncoef+1;
                                }
                            } else {
                                // edge case, use constant extrapolation for lambda[idx]>lambda gas
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] >=  lambda_gas) ncoef=ncoef+1;
                                }
                            }

                            /* --- number of point this lambda contributes to is
                            computed as a difference --- */
                            if (lamuk == 0) {
                                spectrum.nc[lamuk] = ncoef;
                            } else {
                                spectrum.nc[lamuk]=spectrum.nc[lamuk-1]+ncoef;
                            }

                        } // k
                    } // to_obs
                } // mu
            } // la

            /* --- now we know the number of interpolation coefficients,
                   it's stored in the last element of spectrum.nc,
               so allocate space                                     --- */
            idx=spectrum.nc[2*atmos.Nrays*spectrum.Nspect*atmos.Nspace-1];
            spectrum.iprdh= (int *)    malloc( idx * sizeof(int   ));
            spectrum.cprdh= (double *) malloc( idx * sizeof(double));

            /* --- Run through all lamuk points again, and now store indices
                   to lambda array and the corresponding interpolation
                   coefficients                                          --- */
            for (la = 0;  la < spectrum.Nspect;  la++) {
                for (mu = 0;  mu < atmos.Nrays;  mu++) {
                    for (to_obs = 0;  to_obs <= 1;  to_obs++) {

                        sign = (to_obs) ? 1.0 : -1.0;

                        for (k = 0;  k < atmos.Nspace;  k++) {

                            lamuk = la * (atmos.Nrays*2*atmos.Nspace)
                                    + mu     * (2*atmos.Nspace)
                                    + to_obs * (atmos.Nspace)
                                    + k ;

                            // starting index for storage for this lamuk point
                            lc = (lamuk==0) ? 0 : spectrum.nc[lamuk-1];

                            // previous, current and next wavelength shifted to gas rest frame
                            fac = (1.+spectrum.v_los[mu][k]*sign/CLIGHT);
                            lambda_prv = lambda[ MAX(la-1,0)                 ]*fac;
                            lambda_gas = lambda[ la                          ]*fac;
                            lambda_nxt = lambda[ MIN(la+1,spectrum.Nspect-1) ]*fac;

                            // do lambda_prv and lambda_gas bracket lambda points?
                            if (lambda_prv !=  lambda_gas) {
                                dl= lambda_gas - lambda_prv;
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] > lambda_prv && lambda[idx] <= lambda_gas) {
                                        // bracketed point found
                                        spectrum.iprdh[lc]=idx;
                                        spectrum.cprdh[lc]=(lambda[idx]-lambda_prv)/dl;
                                        lc++;
                                    }
                                }
                            } else {
                                // edge case, use constant extrapolation for lambda[idx]<lambda gas
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] <=  lambda_gas)  {
                                        spectrum.iprdh[lc]=idx;
                                        spectrum.cprdh[lc]=1.0;
                                        lc++;
                                    }
                                }
                            }

                            // do lambda_gas and lambda_nxt bracket lambda points?
                            if (lambda_gas != lambda_nxt) {
                                dl= lambda_nxt - lambda_gas;
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] > lambda_gas && lambda[idx] < lambda_nxt) {
                                        // bracketed point found
                                        spectrum.iprdh[lc]=idx;
                                        spectrum.cprdh[lc]=1.0 - (lambda[idx]-lambda_gas)/dl;
                                        lc++;
                                    }
                                }
                            } else {
                                // edge case, use constant extrapolation for lambda[idx]>lambda gas
                                for (idx = 0; idx < spectrum.Nspect ; idx++) {
                                    if (lambda[idx] >=  lambda_gas)  {
                                        spectrum.iprdh[lc]=idx;
                                        spectrum.cprdh[lc]=1.0;
                                        lc++;
                                    }
                                }
                            }

                        } // k
                    } // to_obs
                } // mu
            } // la

        }  //input.prdh_limit_mem if switch
    } // PRD_ANGLE_APPROX if switch

    /* --- Allocate space for the emergent intensity --  -------------- */

    switch (topology) {
    case ONE_D_PLANE:
        spectrum.I = matrix_double(spectrum.Nspect, atmos.Nrays);
        if (atmos.Stokes || input.backgr_pol) {
            spectrum.Stokes_Q = matrix_double(spectrum.Nspect, atmos.Nrays);
            spectrum.Stokes_U = matrix_double(spectrum.Nspect, atmos.Nrays);
            spectrum.Stokes_V = matrix_double(spectrum.Nspect, atmos.Nrays);
        }
        break;
    case TWO_D_PLANE:
        Nsr = spectrum.Nspect * atmos.Nrays;
        spectrum.I = matrix_double(Nsr, atmos.N[0]);
        if (atmos.Stokes || input.backgr_pol) {
            spectrum.Stokes_Q = matrix_double(Nsr, atmos.N[0]);
            spectrum.Stokes_U = matrix_double(Nsr, atmos.N[0]);
            spectrum.Stokes_V = matrix_double(Nsr, atmos.N[0]);
        }
        break;
    case THREE_D_PLANE:
        spectrum.I = matrix_double(spectrum.Nspect * atmos.Nrays,
                                   atmos.N[0] * atmos.N[1]);
        if (atmos.Stokes || input.backgr_pol) {
            Nsr    = spectrum.Nspect * atmos.Nrays;
            Nplane = atmos.N[0] * atmos.N[1];

            spectrum.I = matrix_double(Nsr, Nplane);
            if (atmos.Stokes || input.backgr_pol) {
                spectrum.Stokes_Q = matrix_double(Nsr, Nplane);
                spectrum.Stokes_U = matrix_double(Nsr, Nplane);
                spectrum.Stokes_V = matrix_double(Nsr, Nplane);
            }
        }
        break;
    case SPHERICAL_SYMMETRIC:
        spectrum.I = matrix_double(spectrum.Nspect, atmos.Nrays);
        if (atmos.Stokes) {
            Error(ERROR_LEVEL_2, routineName,
                  "Cannot do a full Stokes solution in spherical geometry");
        }
        break;
    default:
        sprintf(messageStr, "Unknown topology (%d)", topology);
        Error(ERROR_LEVEL_2, routineName, messageStr);
    }
    /* --- Read angle-averaged intensity from previous run if necessary,
           and open file for J in case option for limited memory is set */

    spectrum.fd_J   = -1;
    spectrum.fd_J20 = -1;
    oflag = 0;
    openJfile = FALSE;

    if (input.startJ == OLD_J) {
        if (spectrum.updateJ) {
            strcpy(permission, "r+");
            oflag |= O_RDWR;
        } else {
            strcpy(permission, "r");
            oflag |= O_RDONLY;
        }
        openJfile = TRUE;
    } else {
        if (input.limit_memory) {
            strcpy(permission, "w+");
            oflag |= (O_RDWR | O_CREAT);
            openJfile = TRUE;
        }
    }
    if (openJfile) {
        if ((spectrum.fd_J = open(input.JFile, oflag, PERMISSIONS)) == -1) {
            sprintf(messageStr,
                    "Unable to open input file %s with permission %s",
                    input.JFile, permission);
            Error(ERROR_LEVEL_2, routineName, messageStr);
        }
        if (input.backgr_pol) {
            if ((spectrum.fd_J20 = open(J20_DOT_OUT, oflag,
                                        PERMISSIONS)) == -1) {
                sprintf(messageStr,
                        "Unable to open input file %s with permission %s",
                        J20_DOT_OUT, permission);
                Error(ERROR_LEVEL_2, routineName, messageStr);
            }
        }
    }
    if (input.limit_memory) {
        if (oflag & O_CREAT) {
            J = (double *) malloc(atmos.Nspace * sizeof(double));

            /* --- Initialize J file with zeroes --          -------------- */

            for (k = 0;  k < atmos.Nspace;  k++) J[k] = 0.0;
            for (nspect = 0;  nspect < spectrum.Nspect;  nspect++)
                writeJlambda(nspect, J);

            free(J);

            if (input.backgr_pol) {
                J20 = (double *) malloc(atmos.Nspace * sizeof(double));
                for (k = 0;  k < atmos.Nspace;  k++) J20[k] = 0.0;
                for (nspect = 0;  nspect < spectrum.Nspect;  nspect++)
                    writeJ20lambda(nspect, J20);

                free(J20);
            }
        }
    } else {
        if (input.startJ == OLD_J) {

            /* --- Fill matrix J with old values from previous run ----- -- */

            for (nspect = 0;  nspect < spectrum.Nspect;  nspect++)
                readJlambda(nspect, spectrum.J[nspect]);

            close(spectrum.fd_J);
            spectrum.fd_J = -1;

            if (input.backgr_pol) {
                for (nspect = 0;  nspect < spectrum.Nspect;  nspect++)
                    readJ20lambda(nspect, spectrum.J20[nspect]);

                close(spectrum.fd_J20);
                spectrum.fd_J20 = -1;
            }
        }

        /* --- Look for Jgas and read, otherwise use spectrum.J ----- -- */
        if (atmos.NPRDactive > 0 && input.PRD_angle_dep == PRD_ANGLE_APPROX) {
            fp=fopen("Jgas.dat","r");
            if (fp) {
                // file exists
                fclose(fp);
                readJgas(spectrum.Jgas);
                sprintf(messageStr, "Read spectrum.Jgas from file.");
                Error(MESSAGE, routineName, messageStr);

            } else {
                //file does not exist
                sprintf(messageStr, "Jgas.dat does not exist,setting spectrum.Jgas spectrum.J.");
                Error(WARNING, routineName, messageStr);
                for (k = 0;  k < atmos.Nspace;  k++) {
                    for (nspect = 0;  nspect < spectrum.Nspect;  nspect++) {
                        spectrum.Jgas[nspect][k]=spectrum.J[nspect][k];
                    }
                }
            }
        }

    }
    /* --- Need storage for angle-dependent specific intensities for
           angle-dependent PRD --                        -------------- */

    if (atmos.NPRDactive > 0 && input.PRD_angle_dep == PRD_ANGLE_DEP) {
        oflag = 0;
        if (input.startJ == OLD_J) {
            if (spectrum.updateJ) {
                strcpy(permission, "r+");
                oflag |= O_RDWR;
            } else {
                strcpy(permission, "r");
                oflag |= O_RDONLY;
            }
        } else {
            strcpy(permission, "w+");
            oflag |= (O_RDWR | O_CREAT);
        }
        if ((spectrum.fd_Imu = open(IMU_FILENAME, oflag, PERMISSIONS)) == -1) {
            sprintf(messageStr, "Unable to open %s file %s with permission %s",
                    (spectrum.updateJ) ? "update" : "input",
                    IMU_FILENAME, permission);
            Error(ERROR_LEVEL_2, routineName, messageStr);
        }
        /* --- Fill the index list that keeps track of the location
               of intensity Imu in file spectrum.fd_Imu at wavelength
               corresponding to nspect. --                 -------------- */

        spectrum.PRDindex = (int *) malloc(spectrum.Nspect * sizeof(int));
        index = 0;
        for (nspect = 0;  nspect < spectrum.Nspect;  nspect++) {
            if (containsPRDline(&spectrum.as[nspect])) {
                spectrum.PRDindex[nspect] = index;
                index++;
            }
        }
    }
    for (nact = 0;  nact < atmos.Nactiveatom;  nact++) {
        atom = atmos.activeatoms[nact];

        /* --- Allocate memory for the rate equation matrix -- ---------- */

        atom->Gamma = matrix_double(SQ(atom->Nlevel), atmos.Nspace);

        /* --- Initialize the mutex lock for the operator Gamma if there
               are more than one threads --                -------------- */

        if (input.Nthreads > 0) {
            if ((status = pthread_mutex_init(&atom->Gamma_lock, NULL))) {
                sprintf(messageStr, "Unable to initialize mutex_lock, status = %d",
                        status);
                Error(ERROR_LEVEL_2, routineName, messageStr);
            }
        }

        switch(atom->initial_solution) {
        case LTE_POPULATIONS:
            for (i = 0;  i < atom->Nlevel;  i++) {
                for (k = 0;  k < atmos.Nspace;  k++)
                    atom->n[i][k] = atom->nstar[i][k];
            }
            break;

        case ZERO_RADIATION:
            hc_k   = (HPLANCK * CLIGHT) / (KBOLTZMANN * NM_TO_M);
            twoc   = 2.0*CLIGHT / CUBE(NM_TO_M);
            fourPI = 4.0 * PI;

            initGammaAtom(atom,cswitch);

            /* --- Then add radiative contributions of active transitions --  */

            for (nspect = 0;  nspect < spectrum.Nspect;  nspect++) {
                as = spectrum.as + nspect;

                for (n = 0;  n < as->Nactiveatomrt[nact];  n++) {
                    switch (as->art[nact][n].type) {
                    case ATOMIC_LINE:
                        line = as->art[nact][n].ptype.line;
                        la = nspect - line->Nblue;
                        i  = line->i;
                        j  = line->j;
                        ij = i*atom->Nlevel + j;

                        if (la == 0) {
                            for (k = 0;  k < atmos.Nspace;  k++)
                                atom->Gamma[ij][k] += line->Aji;
                        }
                        break;

                    case ATOMIC_CONTINUUM:
                        continuum = as->art[nact][n].ptype.continuum;
                        la = nspect - continuum->Nblue;
                        i  = continuum->i;
                        j  = continuum->j;
                        ij = i*atom->Nlevel + j;

                        wla = fourPI * getwlambda_cont(continuum, la) /
                              continuum->lambda[la];
                        twohnu3_c2 = twoc / CUBE(continuum->lambda[la]);
                        for (k = 0;  k < atmos.Nspace;  k++) {
                            gijk = atom->nstar[i][k]/atom->nstar[j][k] *
                                   exp(-hc_k/(continuum->lambda[la] * atmos.T[k]));
                            atom->Gamma[ij][k] += gijk * twohnu3_c2 *
                                                  continuum->alpha[la]*wla;
                        }
                        break;
                    default:
                        break;
                    }
                }
            }
            /* --- Solve statistical equilibrium equations --  ------------ */

            statEquil(atom, (input.isum == -1) ? 0 : input.isum);
            break;

        case OLD_POPULATIONS:
            readPopulations(atom);
            break;

        default:
            ;
            break;
        }
    }
    /* --- Now the molecules that are active --          -------------- */

    for (nact = 0;  nact < atmos.Nactivemol;  nact++) {
        molecule = atmos.activemols[nact];

        /* --- Calculate the LTE vibration level populations here. They
               cannot be calculated yet in readMolecule since chemical
               equilibrium has to be established first --  -------------- */

        for (i = 0;  i < molecule->Nv;  i++) {
            for (k = 0;  k < atmos.Nspace;  k++)
                molecule->nvstar[i][k] = molecule->n[k] *
                                         molecule->pfv[i][k] / molecule->pf[k];
        }
        /* --- Allocate memory for the rate equation matrix -- ---------- */

        molecule->Gamma = matrix_double(SQ(molecule->Nv), atmos.Nspace);

        /* --- Initialize the mutex lock for the operator Gamma if there
               are more than one thread --                 -------------- */

        if (input.Nthreads > 0) {
            if ((status = pthread_mutex_init(&molecule->Gamma_lock, NULL))) {
                sprintf(messageStr, "Unable to initialize mutex_lock, status = %d",
                        status);
                Error(ERROR_LEVEL_2, routineName, messageStr);
            }
        }

        switch(molecule->initial_solution) {

        case LTE_POPULATIONS:
            for (i = 0;  i < molecule->Nv;  i++) {
                for (k = 0;  k < atmos.Nspace;  k++)
                    molecule->nv[i][k] = molecule->nvstar[i][k];
            }
            break;

        case OLD_POPULATIONS:
            readMolPops(molecule);
            break;

        default:
            ;
        }

        /* --- Calculate collisions for molecule (must be done here because
               rotation-vibration transitions are dominated by hydrogen and
               H2 collisions for which chemical equilibrium needs to be
               established first --                        -------------- */

        if (strstr(molecule->ID, "CO"))
            COcollisions(molecule);
        else {
            sprintf(messageStr, "Collisions for molecule %s not implemented\n",
                    molecule->ID);
            Error(ERROR_LEVEL_2, routineName, messageStr);
        }
    }
}
Пример #17
0
Файл: kurucz.c Проект: kouui/rh
flags rlk_opacity(double lambda, int nspect, int mu, bool_t to_obs,
                  double *chi, double *eta, double *scatt, double *chip)
{
  register int k, n, kr;

  bool_t contributes, hunt;
  int    Nwhite, Nblue, Nred, NrecStokes;
  double dlamb_wing, *pf, dlamb_char, hc_la, ni_gi, nj_gj, lambda0, kT,
         Bijhc_4PI, twohnu3_c2, hc, fourPI, hc_4PI,
        *eta_Q, *eta_U, *eta_V, eta_l,
        *chi_Q, *chi_U, *chi_V, chi_l, *chip_Q, *chip_U, *chip_V,
         phi, phi_Q, phi_U, phi_V, psi_Q, psi_U, psi_V,
         epsilon, C, C2_atom, C2_ion, C3, dE, x;
  Atom *metal;
  AtomicLine *line;
  Element *element;
  RLK_Line *rlk;
  flags backgrflags;

  /* --- Calculate the LTE opacity at wavelength lambda due to atomic
         transitions stored in atmos.rlk_lines --      -------------- */

  backgrflags.hasline     = FALSE;
  backgrflags.ispolarized = FALSE;

  /* --- If wavelength outside our list return without calculation -- */

  dlamb_char = lambda * Q_WING * (atmos.vmicro_char / CLIGHT);
  if (lambda < atmos.rlk_lines[0].lambda0 - dlamb_char ||
      lambda > atmos.rlk_lines[atmos.Nrlk-1].lambda0 + dlamb_char) {
   return backgrflags;
  }

  hc     = HPLANCK * CLIGHT;
  fourPI = 4.0 * PI;
  hc_4PI = hc / fourPI;

  if (input.rlkscatter) {
    C       = 2 * PI * (Q_ELECTRON/EPSILON_0) *
                (Q_ELECTRON/M_ELECTRON) / CLIGHT;
    C2_atom = 2.15E-6;
    C2_ion  = 3.96E-6;
  }

  pf = (double *) malloc(atmos.Nspace * sizeof(double));

  /* --- locate wavelength lambda in table of lines -- -------------- */

  Nwhite = 0;
  rlk_locate(atmos.Nrlk, atmos.rlk_lines, lambda, &Nwhite);
  Nblue = Nwhite;
  while (atmos.rlk_lines[Nblue].lambda0 + dlamb_char > lambda &&
	 Nblue > 0)  Nblue--;
  Nred = Nwhite;
  while (atmos.rlk_lines[Nred].lambda0 - dlamb_char < lambda &&
	 Nred < atmos.Nrlk-1)  Nred++;

  /* --- Initialize the contribution for this wavelength and angle -- */

  if (Nred >= Nblue) {
    if (atmos.Stokes) {
      NrecStokes = 4;

      /* --- Use pointers to sub-arrays for Q, U, and V -- ---------- */

      chi_Q = chi + atmos.Nspace;
      chi_U = chi + 2*atmos.Nspace;
      chi_V = chi + 3*atmos.Nspace;

      eta_Q = eta + atmos.Nspace;
      eta_U = eta + 2*atmos.Nspace;
      eta_V = eta + 3*atmos.Nspace;

      if (input.magneto_optical) {
        chip_Q = chip;
        chip_U = chip + atmos.Nspace;
        chip_V = chip + 2*atmos.Nspace;

        for (k = 0;  k < 3*atmos.Nspace;  k++) chip[k] = 0.0;
      }
    } else
      NrecStokes = 1;

    for (k = 0;  k < NrecStokes * atmos.Nspace;  k++) {
      chi[k] = 0.0;
      eta[k] = 0.0;
    }
    if (input.rlkscatter) {
      for (k = 0;  k < atmos.Nspace;  k++) scatt[k] = 0.0;
    }
  }
  /* --- Add opacities from lines at this wavelength -- ------------- */

  for (n = Nblue;  n <= Nred;  n++) {
    rlk = &atmos.rlk_lines[n];
    if (fabs(rlk->lambda0 - lambda) <= dlamb_char) {
      element = &atmos.elements[rlk->pt_index - 1];

      /* --- Check whether partition function is present for this
	     stage, and if abundance is set --         -------------- */

      if ((rlk->stage < element->Nstage - 1) && element->abundance_set) {
	contributes = TRUE;
	if ((metal = element->model) != NULL) {

          /* --- If an explicit atomic model is present check that we
	         do not already account for this line in this way - - */

	  for (kr = 0;  kr < metal->Nline;  kr++) {
	    line = metal->line + kr;
	    dlamb_wing = line->lambda0 * line->qwing *
	      (atmos.vmicro_char / CLIGHT);
	    if (fabs(lambda - line->lambda0) <= dlamb_wing &&
		metal->stage[line->i] == rlk->stage) {
	      contributes = FALSE;
	      break;
	    }
	  }
	}
      } else
	contributes = FALSE;

      /* --- Get opacity from line --                  -------------- */

      if (contributes) {
	hc_la      = (HPLANCK * CLIGHT) / (rlk->lambda0 * NM_TO_M);
	Bijhc_4PI  = hc_4PI * rlk->Bij * rlk->isotope_frac *
	  rlk->hyperfine_frac * rlk->gi;
	twohnu3_c2 = rlk->Aji / rlk->Bji;

	if (input.rlkscatter) {
	  if (rlk->stage == 0) {
	    x  = 0.68;
	    C3 = C / (C2_atom * SQ(rlk->lambda0 * NM_TO_M));
	  } else {
	    x  = 0.0;
	    C3 = C / (C2_ion * SQ(rlk->lambda0 * NM_TO_M));
	  }

	  dE = rlk->Ej - rlk->Ei;
	}
        /* --- Set flag that line is present at this wavelength -- -- */

	backgrflags.hasline = TRUE;
	if (rlk->polarizable) {
	  backgrflags.ispolarized = TRUE;
	  if (rlk->zm == NULL) rlk->zm = RLKZeeman(rlk);
	}

        if (element->n == NULL) {
	  element->n = matrix_double(element->Nstage, atmos.Nspace);
	  LTEpops_elem(element);
	}
        Linear(atmos.Npf, atmos.Tpf, element->pf[rlk->stage],
	       atmos.Nspace, atmos.T, pf, hunt=TRUE);

	for (k = 0;  k < atmos.Nspace;  k++) {
	  phi = RLKProfile(rlk, k, mu, to_obs, lambda,
			   &phi_Q, &phi_U, &phi_V,
			   &psi_Q, &psi_U, &psi_V);

	  if (phi){
	    kT    = 1.0 / (KBOLTZMANN * atmos.T[k]);
	    ni_gi = element->n[rlk->stage][k] * exp(-rlk->Ei*kT - pf[k]);
            nj_gj = ni_gi * exp(-hc_la * kT);

	    chi_l = Bijhc_4PI * (ni_gi - nj_gj);
	    eta_l = Bijhc_4PI * twohnu3_c2 * nj_gj;

	    if (input.rlkscatter) {
	      epsilon = 1.0 / (1.0 + C3 * pow(atmos.T[k], 1.5) /
			       (atmos.ne[k] *
				pow(KBOLTZMANN * atmos.T[k] / dE, 1 + x)));

              scatt[k] += (1.0 - epsilon) * chi_l * phi;
	      chi_l    *= epsilon;
              eta_l    *= epsilon;
	    }

	    chi[k] += chi_l * phi;
	    eta[k] += eta_l * phi;

	    if (rlk->zm != NULL && rlk->Grad) {
	      chi_Q[k] += chi_l * phi_Q;
	      chi_U[k] += chi_l * phi_U;
	      chi_V[k] += chi_l * phi_V;

	      eta_Q[k] += eta_l * phi_Q;
	      eta_U[k] += eta_l * phi_U;
	      eta_V[k] += eta_l * phi_V;

	      if (input.magneto_optical) {
		chip_Q[k] += chi_l * psi_Q;
		chip_U[k] += chi_l * psi_U;
		chip_V[k] += chi_l * psi_V;
	      }
	    }
	  }
	}
      }
    }
  }

  free(pf);
  return backgrflags;
}
Пример #18
0
void CollisionRate(struct Atom *atom, FILE *fp_atom)
{
  const char routineName[] = "CollisionRate";
  register int k, n,m;

  char    inputLine[MAX_LINE_SIZE], *keyword, *pointer,
          labelStr[MAX_LINE_SIZE];
  bool_t  hunt, exit_on_EOF;
  int     nitem, i1, i2, i, j, ij, ji, Nlevel = atom->Nlevel, Nitem,
    status;
  long    Nspace = atmos.Nspace, collpos;
  double  dE, C0, *T, *coeff, *C, Cdown, Cup, gij, *np,xj,fac,fxj;
  /* JL additions start */
  double **cdi;
  int    Ncoef,mshell=5;
  double  acolsh,tcolsh,aradsh,xradsh,adish,bdish,t0sh,t1sh,summrs,tg,cdn,cup;
  double  ar85t1,ar85t2,ar85a,ar85b,ar85c,ar85d,t4;
  double de,zz,betab,cbar,dekt,dekti,wlog,wb;
  /* JL additions end */

  getCPU(3, TIME_START, NULL);

  C0 = ((E_RYDBERG/sqrt(M_ELECTRON)) * PI*SQ(RBOHR)) *
    sqrt(8.0/(PI*KBOLTZMANN));

  atom->C = matrix_double(SQ(Nlevel), Nspace);
  for (ij = 0;  ij < SQ(Nlevel);  ij++) {
    for (k = 0;  k < Nspace;  k++) {
      atom->C[ij][k] = 0.0;
    }
  }

  collpos=ftell(fp_atom);

  C = (double *) malloc(Nspace * sizeof(double));

  T = coeff = NULL;
  while ((status = getLine(fp_atom, COMMENT_CHAR,
		  inputLine, exit_on_EOF=FALSE)) != EOF) {
    keyword = strtok(inputLine, " ");

    if (!strcmp(keyword, "TEMP")) {

      /* --- Read temperature grid --                  -------------- */

      Nitem = atoi(strtok(NULL, " "));
      T = (double *) realloc(T, Nitem*sizeof(double));
      for (n = 0, nitem = 0;  n < Nitem;  n++) {
        if ((pointer = strtok(NULL, " ")) == NULL) break;
	nitem += sscanf(pointer, "%lf", T+n);
      }
    } else if (!strcmp(keyword, "OMEGA") || !strcmp(keyword, "CE") ||
	       !strcmp(keyword, "CI")    || !strcmp(keyword, "CP") ||
	       !strcmp(keyword, "CH0")   || !strcmp(keyword, "CH+")||
	       !strcmp(keyword, "CH") ) {

      /* --- Read level indices and collision coefficients -- ------- */

      i1 = atoi(strtok(NULL, " "));
      i2 = atoi(strtok(NULL, " "));
      coeff = (double *) realloc(coeff, Nitem*sizeof(double));
      for (n = 0, nitem = 0;  n < Nitem;  n++) {
        if ((pointer = strtok(NULL, " ")) == NULL) break;
	nitem += sscanf(pointer, "%lf", coeff+n);
      }
      /* --- Transitions i -> j are stored at index ji, transitions
	     j -> i are stored under ij. --            -------------- */

      i  = MIN(i1, i2);
      j  = MAX(i1, i2);
      ij = i*Nlevel + j;
      ji = j*Nlevel + i;

    } else if (!strcmp(keyword, "AR85-CHP") || !strcmp(keyword, "AR85-CHH")) {
      
      i1 = atoi(strtok(NULL, " "));
      i2 = atoi(strtok(NULL, " "));
      
      Nitem=6;
      coeff = (double *) realloc(coeff, Nitem*sizeof(double));
      
      for (n = 0, nitem = 0;  n < Nitem;  n++) {
        if ((pointer = strtok(NULL, " ")) == NULL) break;
	nitem += sscanf(pointer, "%lf", coeff+n);
      }

      i  = MIN(i1, i2);
      j  = MAX(i1, i2);
      ij = i*Nlevel + j;
      ji = j*Nlevel + i;

   } else if (!strcmp(keyword,"AR85-CEA") || !strcmp(keyword, "BURGESS")) {

      i1 = atoi(strtok(NULL, " "));
      i2 = atoi(strtok(NULL, " "));      
      
      nitem=1;
      Nitem=1;
      coeff = (double *) realloc(coeff, Nitem*sizeof(double));
      coeff[0] =   atof(strtok(NULL, " "));    
      
      i  = MIN(i1, i2);
      j  = MAX(i1, i2);
      ij = i*Nlevel + j;
      ji = j*Nlevel + i;

    } else if (!strcmp(keyword, "SHULL82")) {
      
      i1 = atoi(strtok(NULL, " "));
      i2 = atoi(strtok(NULL, " "));
      
      Nitem=8;
      coeff = (double *) realloc(coeff, Nitem*sizeof(double));
      
      for (n = 0, nitem = 0;  n < Nitem;  n++) {
        if ((pointer = strtok(NULL, " ")) == NULL) break;
	nitem += sscanf(pointer, "%lf", coeff+n);
      }
      
      i  = MIN(i1, i2);
      j  = MAX(i1, i2);
      ij = i*Nlevel + j;
      ji = j*Nlevel + i;
      
    } else if (!strcmp(keyword, "AR85-CDI")) {
      
      i1 = atoi(strtok(NULL, " "));
      i2 = atoi(strtok(NULL, " "));
      Ncoef = atoi(strtok(NULL, " "));
      
      if (Ncoef > mshell) {
	sprintf(messageStr, "Ncoef: %i greater than mshell %i",Ncoef, mshell );
	Error(ERROR_LEVEL_2, routineName, messageStr);
      }

      Nitem=5;
      cdi=matrix_double(Ncoef, Nitem);
      
      for (m = 0; m < Ncoef;  m++) {
	
	status=getLine(fp_atom, COMMENT_CHAR,inputLine, exit_on_EOF=FALSE);
	cdi[m][0]  = atof(strtok(inputLine, " "));
	for (n = 1;  n < Nitem;  n++) {
	  cdi[m][n]  = atof(strtok(NULL, " "));
	}
      }

      i  = MIN(i1, i2);
      j  = MAX(i1, i2);
      ij = i*Nlevel + j;
      ji = j*Nlevel + i;

      nitem=5;
      Nitem=5;
      keyword="AR85-CDI"; 

    } else if (!strcmp(keyword, "END")) {
      break;
    } else {
      sprintf(messageStr, "Unknown keyword: %s", keyword);
      Error(ERROR_LEVEL_1, routineName, messageStr);
    }

    if (nitem != Nitem) {
      sprintf(messageStr, "\n Read %d, not %d items (keyword = %s)\n",
	      nitem, Nitem, keyword);
      Error(ERROR_LEVEL_2, routineName, messageStr);
    }
    /* --- Spline interpolation in temperature T for all spatial
           locations. Linear if only 2 interpolation points given - - */

    //    if (strcmp(keyword, "TEMP") != 0) {
    if (!strcmp(keyword, "OMEGA") || !strcmp(keyword, "CE") ||
	!strcmp(keyword, "CI")    || !strcmp(keyword, "CP") ||
	!strcmp(keyword, "CH0")   || !strcmp(keyword, "CH+")||
	!strcmp(keyword, "CH") ) {

      if (Nitem > 2) {
	splineCoef(Nitem, T, coeff);
	splineEval(Nspace, atmos.T, C, hunt=TRUE);
      } else
	Linear(Nitem, T, coeff, Nspace, atmos.T, C, hunt=TRUE);
    }

    if (!strcmp(keyword, "OMEGA")) {

      /* --- Collisional excitation of ions --         -------------- */ 

      for (k = 0;  k < Nspace;  k++) {
        Cdown = C0 * atmos.ne[k] * C[k] /
                                 (atom->g[j] * sqrt(atmos.T[k]));
	atom->C[ij][k] += Cdown;
	atom->C[ji][k] += Cdown * atom->nstar[j][k]/atom->nstar[i][k];
      }
    } else if (!strcmp(keyword, "CE")) {      

      /* --- Collisional excitation of neutrals --     -------------- */ 

      gij = atom->g[i] / atom->g[j];
      for (k = 0;  k < Nspace;  k++) {
        Cdown = C[k] * atmos.ne[k] * gij * sqrt(atmos.T[k]);
	atom->C[ij][k] += Cdown;
	atom->C[ji][k] += Cdown * atom->nstar[j][k]/atom->nstar[i][k];
      }
    } else if (!strcmp(keyword, "CI")) {      

      /* --- Collisional ionization --                 -------------- */

      dE = atom->E[j] - atom->E[i];
      for (k = 0;  k < Nspace;  k++) {
        Cup = C[k] * atmos.ne[k] *
	  exp(-dE/(KBOLTZMANN*atmos.T[k])) * sqrt(atmos.T[k]);
	atom->C[ji][k] += Cup;
	atom->C[ij][k] += Cup * atom->nstar[i][k]/atom->nstar[j][k];
      }
    } else if (!strcmp(keyword, "CP")) {

      /* --- Collisions with protons --                -------------- */

      np = atmos.H->n[atmos.H->Nlevel-1];
      for (k = 0;  k < Nspace;  k++) {
        Cdown = np[k] * C[k];
	atom->C[ij][k] += Cdown;
	atom->C[ji][k] += Cdown * atom->nstar[j][k]/atom->nstar[i][k];
      }
    } else if (!strcmp(keyword, "CH")) {

      /* --- Collisions with neutral hydrogen --       -------------- */

      for (k = 0;  k < Nspace;  k++) {
        Cup = atmos.H->n[0][k] * C[k];
	atom->C[ji][k] += Cup;
	atom->C[ij][k] += Cup * atom->nstar[i][k]/atom->nstar[j][k];
      }
    } else if (!strcmp(keyword, "CH0")) {

      /* --- Charge exchange with neutral hydrogen --  -------------- */

      for (k = 0;  k < Nspace;  k++)
	atom->C[ij][k] += atmos.H->n[0][k] * C[k];

    } else if (!strcmp(keyword, "CH+")) {

      /* --- Charge exchange with protons --           -------------- */

      np = atmos.H->n[atmos.H->Nlevel-1];
      for (k = 0;  k < Nspace;  k++)
	atom->C[ji][k] += np[k] * C[k];

    } else if (!strcmp(keyword, "SHULL82")) {
      
      /*      printf("shull82\n");*/
      
      acolsh=coeff[0];
      tcolsh=coeff[1];
      aradsh=coeff[2];
      xradsh=coeff[3];
      adish =coeff[4];
      bdish =coeff[5];
      t0sh  =coeff[6];
      t1sh  =coeff[7];
      
      for (k = 0;  k < Nspace;  k++) {
	
	summrs=1.0;
	summrs=summers(i,j,atmos.ne[k],atom);
	tg=atmos.T[k];
	
	cdn= aradsh*pow(tg/1.e4,-xradsh)  
	  + summrs * adish /tg/sqrt(tg) * exp(-t0sh/tg) * 
	  (1.0+bdish * (exp(- t1sh/tg)));
	
	cup=acolsh * sqrt(tg) * exp( -tcolsh / tg) / (1.0 + 0.1 * tg / tcolsh);
	
	/* --- Convert coefficient from cm^3 s^-1 to m^3 s^-1 -- ---- */

	cdn *= atmos.ne[k] * CUBE(CM_TO_M);
	cup *= atmos.ne[k] * CUBE(CM_TO_M);

	//	cdn=cdn*atmos.ne[k];
	//cup=cup*atmos.ne[k];

	/* 3-body recombination (high density limit) */
	cdn = cdn + cup * atom->nstar[i][k] / atom->nstar[j][k];
	
	atom->C[ij][k] += cdn;
	atom->C[ji][k] += cup;
	
      }
      
    } else if (!strcmp(keyword, "AR85-CDI")) {
      
      /*      printf("ar85-cdi\n");*/
      
      /* Direct collionisional ionization */
      for (k = 0;  k < Nspace;  k++) {
	
	tg=atmos.T[k];
	cup=0.0;
	
	for (m = 0; m < Ncoef;  m++) {
	  
	  xj=cdi[m][0] * EV/KBOLTZMANN/tg;
	  fac=exp(-xj)*sqrt(xj);
	  
	  fxj= cdi[m][1]+cdi[m][2]*(1.0+xj) 
	    +(cdi[m][3]-xj*(cdi[m][1]+cdi[m][2] 
			    *(2.0+xj)))*fone(xj)+ 
	    cdi[m][4]*xj*ftwo(xj);
	  
	  fxj=fxj*fac;
	  fac = 6.69e-7 / pow(cdi[m][0],1.5);
	  cup = cup + fac*fxj * pow(CM_TO_M,3);
	  
	}
	
	if (cup<0) {
	  printf("warning cup= %e and T= %f\n",cup,tg);
	  cup=0;
	} 
	cup=cup*atmos.ne[k];
	cdn=cup*atom->nstar[i][k]/atom->nstar[j][k];	  
	
	atom->C[ij][k] += cdn;
	atom->C[ji][k] += cup;
	
      }
      
    } else if (!strcmp(keyword,"AR85-CEA") ) {
          
      /* Autoionization */
      for (k = 0;  k < Nspace;  k++) {
	ar85cea(i,j,k,&fac, atom);
	cup=coeff[0]*fac*atmos.ne[k];
	atom->C[ji][k] += cup;
      }	  
      
    } else if (!strcmp(keyword, "AR85-CHP")) {
      
      /* charge transfer with ionized hydrogen */
      ar85t1=coeff[0];
      ar85t2=coeff[1];
      ar85a=coeff[2];
      ar85b=coeff[3];
      ar85c=coeff[4];
      ar85d=coeff[5];
      
      for (k = 0;  k < Nspace;  k++) {
	
	if (atmos.T[k]>=ar85t1 &&  atmos.T[k]<=ar85t2) {
	  
	  t4=atmos.T[k]/1.e4;
	  cup = ar85a * 1e-9 * pow(t4,ar85b) * exp(-ar85c*t4) 
	    * exp(-ar85d*EV/KBOLTZMANN/atmos.T[k])*atmos.H->n[5][k]
	    * pow(CM_TO_M,3);
	  atom->C[ji][k] += cup;
		  
	}
      }

  } else if (!strcmp(keyword, "AR85-CHH")) {
      
      /* charge transfer with neutral hydrogen */
      
      ar85t1=coeff[0];
      ar85t2=coeff[1];
      ar85a=coeff[2];
      ar85b=coeff[3];
      ar85c=coeff[4];
      ar85d=coeff[5];
      
      for (k = 0;  k < Nspace;  k++) {
	
	if (atmos.T[k]>=ar85t1 &&  atmos.T[k]<=ar85t2) {
	  
	  t4=atmos.T[k]/1.e4;
	  cdn = ar85a * 1e-9 * pow(t4,ar85b) * (1+ar85c*exp(ar85d*t4)) 
	    * atmos.H->n[0][k] * pow(CM_TO_M,3);
	  atom->C[ij][k] += cdn;
	  
	}
      }
      
    } else if (!strcmp(keyword, "BURGESS")) {
      
      /* Electron impact ionzation following Burgess & Chidichimo,
	 1982, MNRAS,203,1269-1280 */
      
      de= (atom->E[j]-atom->E[i]) / EV;
      zz=atom->stage[i];
      betab = 0.25 * ( sqrt( (100.0*zz +91.0) / (4.0*zz+3.0) ) -5.0 );
      cbar=2.3;
      
      for (k = 0;  k < Nspace;  k++) {
	
	
	dekt=de*EV/KBOLTZMANN/atmos.T[k];
	dekt=min(500,dekt);
	dekti=1.0/dekt;
        wlog=log(1.0 + dekti);
	wb= pow(wlog,betab/(1.0+dekti));
	cup = 2.1715e-8 * cbar * pow(13.6/de ,1.5) * sqrt(dekt) * E1(dekt) * wb *
	  atmos.ne[k] * pow(CM_TO_M,3);
	
	cup=cup*coeff[0]; //add fudge factor
	
	cdn = cup*atom->nstar[i][k]/atom->nstar[j][k];
	
	atom->C[ji][k] += cup;
	atom->C[ij][k] += cdn;
	
      }
      
    }
  }
  
  if (status == EOF) {
    sprintf(messageStr, "Reached end of datafile before all data was read");
    Error(ERROR_LEVEL_1, routineName, messageStr);
  }
  /* --- Clean up --                                   -------------- */

  free(C);
  free(T);
  free(coeff);

  fsetpos(fp_atom,&collpos);

  sprintf(labelStr, "Collision Rate %2s", atom->ID);
  getCPU(3, TIME_POLL, labelStr);
}
Пример #19
0
void getBoundary(Geometry *geometry)
{
  const char routineName[] = "getBoundary";
  register int la;

  bool_t result = TRUE;
  FILE  *fp_Itop;
  XDR    xdrs;

  switch (geometry->vboundary[TOP]) {
  case ZERO: break;
  case THERMALIZED: break;
  case IRRADIATED:

    sprintf(messageStr, "\n -- reading irradiance input file: %s\n\n",
	    input.Itop);
    Error(MESSAGE, NULL, messageStr);

    geometry->Itop = matrix_double(spectrum.Nspect, geometry->Nrays);

    /* --- Open input file for irradiation at TOP --     -------------- */

    if ((fp_Itop = fopen(input.Itop, "r")) == NULL) {
      sprintf(messageStr, "Unable to open inputfile %s", input.Itop);
      Error(ERROR_LEVEL_2, routineName, messageStr);
    }
    xdrstdio_create(&xdrs, fp_Itop, XDR_DECODE);

    result &= xdr_vector(&xdrs, (char *) geometry->Itop[0],
			 spectrum.Nspect * geometry->Nrays,
                         sizeof(double), (xdrproc_t) xdr_double);
    if (!result) {
      sprintf(messageStr,
	      "Unable to read irradiation data at TOP of atmosphere");
      Error(ERROR_LEVEL_2, routineName, messageStr);
    }
    xdr_destroy(&xdrs);
    fclose(fp_Itop);
    break;
  case REFLECTIVE:
    break;
  default:
    Error(ERROR_LEVEL_2, routineName,
	  "Invalid boundary condition at the TOP of atmosphere");
  }

  switch (geometry->vboundary[BOTTOM]) {
  case ZERO: break;
  case THERMALIZED: break;
  case IRRADIATED:
    geometry->Ibottom = matrix_double(spectrum.Nspect, geometry->Nrays);

    /* --- Infalling intensities at BOTTOM should be read here -- --- */

    Error(ERROR_LEVEL_1, routineName,
	  "Boundary condition IRRADIATED at BOTTOM not yet implemented");
    break;
  case REFLECTIVE:
    break;
  default:
    Error(ERROR_LEVEL_2, routineName,
	  "Invalid boundary condition at the BOTTOM of atmosphere");
  }
}