void rawAtom(Atom *atom, char *atomFileName) { const char routineName[] = "rawAtom"; register int kr, kf, la, n; char inputLine[MAX_LINE_SIZE], shapeStr[20], vdWstr[20], nuDepStr[20], errorStr[80], symmStr[20], optionStr[20], *match; bool_t exit_on_EOF; int i, j, Nlevel, Nrad, Nline, Ncont, Nfixed, Nread, Nrequired, checkPoint; double f, C, lambda0, lambdamin, dlamb; FILE *atomFile; AtomicLine *line; AtomicContinuum *continuum; FixedTransition *fixed; /* --- Open the data file for current model atom -- -------------- */ if ((atomFile = fopen(atomFileName, "r")) == NULL) { sprintf(messageStr, "Unable to open input file %s", atomFileName); Error(ERROR_LEVEL_2, routineName, messageStr); } /* --- Read atom ID and convert to uppercase -- -------------- */ getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%2s", atom->ID); checkNread(Nread, Nrequired=1, routineName, checkPoint=1); for (n = 0; n < (int) strlen(atom->ID); n++) atom->ID[n] = toupper(atom->ID[n]); if (strlen(atom->ID) == 1) strcat(atom->ID, " "); /* --- Get the atomic weight -- -------------- */ for (n = 0; n < sizeof(atomweight)/sizeof(struct AtomWeight); n++) { if ((match = strstr(atom->ID, atomweight[n].ID))) { atom->weight = atomweight[n].weight; break; } } if (!match) { sprintf(messageStr, "Found no matching element for %s", atom->ID); Error(ERROR_LEVEL_2, routineName, messageStr); } /* --- Get Number of levels, lines fixed transitions, and continua */ getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%d %d %d %d", &atom->Nlevel, &atom->Nline, &atom->Ncont, &atom->Nfixed); checkNread(Nread, Nrequired=4, routineName, checkPoint=2); Nlevel = atom->Nlevel; Nline = atom->Nline; Ncont = atom->Ncont; Nfixed = atom->Nfixed; Nrad = Nline + Ncont; atom->E = (double *) malloc(Nlevel * sizeof(double)); atom->g = (double *) malloc(Nlevel * sizeof(double)); atom->stage = (int *) malloc(Nlevel * sizeof(int)); atom->label = (char **) malloc(Nlevel * sizeof(char *)); /* --- Read in the level energies, statistical weights, labels, and ionization stage -- -------------- */ for (i = 0; i < Nlevel; i++) { atom->label[i] = (char *) calloc((ATOM_LABEL_WIDTH+1), sizeof(char)); getLine(atomFile, COMMENT_CHAR, inputLine , exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%lf %lf '%20c' %d", &atom->E[i], &atom->g[i], atom->label[i], &atom->stage[i]); checkNread(Nread, Nrequired=4, routineName, checkPoint=3); atom->E[i] *= (HPLANCK * CLIGHT) / CM_TO_M; } if (atom->stage[Nlevel-1] != (atom->stage[Nlevel-2] + 1)) { sprintf(messageStr, "Found no overlying continuum for atom %s", atom->ID); Error(ERROR_LEVEL_2, routineName, messageStr); } C = 2 * PI * (Q_ELECTRON/EPSILON_0) * (Q_ELECTRON/M_ELECTRON) / CLIGHT; /* --- Go through the bound-bound transitions -- -------------- */ atom->Nprd = 0; atom->line = (AtomicLine *) malloc(Nline * sizeof(AtomicLine)); for (kr = 0; kr < Nline; kr++) { line = atom->line + kr; line->atom = atom; line->isotope_frac = 1.0; getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%d %d %lf %s %d %s %lf %lf %s %lf %lf %lf %lf %lf %lf %lf", &j, &i, &f, shapeStr, &line->Nlambda, symmStr, &line->qcore, &line->qwing, vdWstr, &line->cvdWaals[0], &line->cvdWaals[1], &line->cvdWaals[2], &line->cvdWaals[3], &line->Grad, &line->cStark, &line->g_Lande_eff); checkNread(Nread, Nrequired=15, routineName, checkPoint=4); if (Nread == 15) line->g_Lande_eff = 0.0; line->j = MAX(i, j); line->i = MIN(i, j); i = line->i; j = line->j; if (!strstr(shapeStr, "PRD") && !strstr(shapeStr, "VOIGT") && !strstr(shapeStr, "GAUSS")) { sprintf(messageStr, "Invalid value for line-shape string: %s", shapeStr); Error(ERROR_LEVEL_2, routineName, messageStr); } if (strstr(shapeStr, "PRD")) { atom->Nprd++; line->PRD = TRUE; } if (strstr(shapeStr, "GAUSS")) line->Voigt = FALSE; lambda0 = (HPLANCK * CLIGHT) / (atom->E[j] - atom->E[i]); line->Aji = C / SQ(lambda0) * (atom->g[i] / atom->g[j]) * f; line->Bji = CUBE(lambda0) / (2.0 * HPLANCK * CLIGHT) * line->Aji; line->Bij = (atom->g[j] / atom->g[i]) * line->Bji; line->lambda0 = lambda0 / NM_TO_M; if (strstr(vdWstr, "PARAMTR")) line->vdWaals = RIDDER_RENSBERGEN; else { line->vdWaals = UNSOLD; line->cvdWaals[3] = line->cvdWaals[1] = 0.0; } line->symmetric = (strstr(symmStr, "ASYMM")) ? FALSE : TRUE; } /* --- Go through the bound-free transitions -- -------------- */ atom->continuum = (AtomicContinuum *) malloc(Ncont * sizeof(AtomicContinuum)); for (kr = 0; kr < Ncont; kr++) { continuum = atom->continuum + kr; continuum->atom = atom; continuum->isotope_frac = 1.0; getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%d %d %lf %d %s %lf", &j, &i, &continuum->alpha0, &continuum->Nlambda, nuDepStr, &lambdamin); checkNread(Nread, Nrequired=6, routineName, checkPoint=5); continuum->j = MAX(i, j); continuum->i = MIN(i, j); j = continuum->j; i = continuum->i; lambda0 = (HPLANCK * CLIGHT)/(atom->E[j] - atom->E[i]); continuum->lambda0 = lambda0 / NM_TO_M; continuum->lambda = (double *) malloc(continuum->Nlambda * sizeof(double)); continuum->alpha = (double *) malloc(continuum->Nlambda * sizeof(double)); if (strstr(nuDepStr, "EXPLICIT")) { continuum->hydrogenic = FALSE; for (la = continuum->Nlambda-1; la >= 0; la--) { getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%lf %lf", &continuum->lambda[la], &continuum->alpha[la]); checkNread(Nread, Nrequired=2, routineName, checkPoint=6); } for (la = 1; la < continuum->Nlambda; la++) { if (continuum->lambda[la] < continuum->lambda[la-1]) { sprintf(messageStr, "Continuum %d does not have monotonous wavelengths", kr - Nline); Error(ERROR_LEVEL_2, routineName, messageStr); } } } else { continuum->hydrogenic = TRUE; if (lambdamin >= continuum->lambda0) { sprintf(messageStr, "Minimum wavelength for continuum %d too long", kr - Nline); Error(ERROR_LEVEL_2, routineName, messageStr); } dlamb = (continuum->lambda0 - lambdamin) / (continuum->Nlambda - 1); continuum->lambda[0] = lambdamin; for (la = 1; la < continuum->Nlambda; la++) continuum->lambda[la] = continuum->lambda[la-1] + dlamb; } } /* --- Go through fixed transitions -- -------------- */ if (atom->Nfixed > 0) { atom->ft = (FixedTransition *) malloc(Nfixed * sizeof(FixedTransition)); for (kf = 0; kf < Nfixed; kf++) { fixed = atom->ft + kf; getLine(atomFile, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%d %d %lf %lf %s", &j, &i, &fixed->strength, &fixed->Trad, optionStr); checkNread(Nread, Nrequired=5, routineName, checkPoint=7); fixed->j = MAX(i, j); fixed->i = MIN(i, j); j = fixed->j; i = fixed->i; for (kr = 0; kr < Nline; kr++) { line = atom->line + kr; if (line->i == i && line->j == j) { sprintf(messageStr, "Fixed transition j = %d, i = %d duplicates active line", j, i); Error(ERROR_LEVEL_2, routineName, messageStr); } } for (kr = 0; kr < Ncont; kr++) { continuum = atom->continuum + kr; if (continuum->i == i && continuum->j == j) { sprintf(messageStr, "Fixed transition j = %d, i = %d" " duplicates active continuum", j, i); Error(ERROR_LEVEL_2, routineName, messageStr); } } lambda0 = (HPLANCK * CLIGHT) / (atom->E[j] - atom->E[i]); fixed->lambda0 = lambda0 / NM_TO_M; if (atom->stage[j] == atom->stage[i]) fixed->type = FIXED_LINE; else fixed->type = FIXED_CONTINUUM; if (strstr(optionStr, "TRAD_ATMOSPHERIC")) fixed->option = TRAD_ATMOSPHERIC; else if (strstr(optionStr, "TRAD_PHOTOSPHERIC")) fixed->option = TRAD_PHOTOSPHERIC; else if (strstr(optionStr, "TRAD_CHROMOSPHERIC")) fixed->option = TRAD_CHROMOSPHERIC; else { sprintf(messageStr, "Inavlid value for TRAD option: %s", optionStr); Error(ERROR_LEVEL_2, routineName, messageStr); } } } fclose(atomFile); }
void readKuruczLines(char *inputFile) { const char routineName[] = "readKuruczLines"; const double C = 2.0*PI * (Q_ELECTRON/EPSILON_0) * (Q_ELECTRON/M_ELECTRON) / CLIGHT; char inputLine[RLK_RECORD_LENGTH+1], listName[MAX_LINE_SIZE], filename[MAX_LINE_SIZE], Gvalues[18+1], elem_code[7], labeli[RLK_LABEL_LENGTH+1], labelj[RLK_LABEL_LENGTH+1], *commentChar = COMMENT_CHAR; bool_t swap_levels, determined, useBarklem; int Nline, Nread, Nrequired, checkPoint, hfs_i, hfs_j, gL_i, gL_j, iso_dl; double lambda0, Ji, Jj, Grad, GStark, GvdWaals, pti, Ei, Ej, gf, lambda_air; RLK_Line *rlk; Barklemstruct bs_SP, bs_PD, bs_DF; FILE *fp_Kurucz, *fp_linelist; if (!strcmp(inputFile, "none")) return; /* --- Read in the data files for Barklem collisional broadening -- */ readBarklemTable(SP, &bs_SP); readBarklemTable(PD, &bs_PD); readBarklemTable(DF, &bs_DF); labeli[RLK_LABEL_LENGTH] = '\0'; labelj[RLK_LABEL_LENGTH] = '\0'; if ((fp_Kurucz = fopen(inputFile, "r")) == NULL) { sprintf(messageStr, "Unable to open input file %s", inputFile); Error(ERROR_LEVEL_1, routineName, messageStr); return; } /* --- Go through each of the linelist files listed in input file - */ while (getLine(fp_Kurucz, commentChar, listName, FALSE) != EOF) { Nread = sscanf(listName, "%s", filename); if ((fp_linelist = fopen(filename, "r")) == NULL) { sprintf(messageStr, "Unable to open input file %s", filename); Error(ERROR_LEVEL_1, routineName, messageStr); } /* --- Count the number of lines in this file -- -------------- */ Nline = 0; while (fgets(inputLine, RLK_RECORD_LENGTH+1, fp_linelist) != NULL) if (*inputLine != *commentChar) Nline++; rewind(fp_linelist); if (atmos.Nrlk == 0) atmos.rlk_lines = NULL; atmos.rlk_lines = (RLK_Line *) realloc(atmos.rlk_lines, (Nline + atmos.Nrlk) * sizeof(RLK_Line)); /* --- Read lines from file -- -------------- */ rlk = atmos.rlk_lines + atmos.Nrlk; while (fgets(inputLine, RLK_RECORD_LENGTH+1, fp_linelist) != NULL) { if (*inputLine != *commentChar) { initRLK(rlk); Nread = sscanf(inputLine, "%lf %lf %s %lf", &lambda_air, &gf, (char *) &elem_code, &Ei); /* --- Ionization stage and periodic table index -- --------- */ sscanf(elem_code, "%d.%d", &rlk->pt_index, &rlk->stage); Nread += sscanf(inputLine+53, "%lf", &Ej); Ei = fabs(Ei) * (HPLANCK * CLIGHT) / CM_TO_M; Ej = fabs(Ej) * (HPLANCK * CLIGHT) / CM_TO_M; /* --- Beware: the Kurucz linelist has upper and lower levels of a transition in random order. Therefore, we have to check for the lowest energy of the two and use that as lower level -- -------------- */ if (Ej < Ei) { swap_levels = TRUE; rlk->Ei = Ej; rlk->Ej = Ei; strncpy(labeli, inputLine+69, RLK_LABEL_LENGTH); strncpy(labelj, inputLine+41, RLK_LABEL_LENGTH); } else { swap_levels = FALSE; rlk->Ei = Ei; rlk->Ej = Ej; strncpy(labeli, inputLine+41, RLK_LABEL_LENGTH); strncpy(labelj, inputLine+69, RLK_LABEL_LENGTH); } Nread += sscanf(inputLine+35, "%lf", &Ji); Nread += sscanf(inputLine+63, "%lf", &Jj); if (swap_levels) SWAPDOUBLE(Ji, Jj); rlk->gi = 2*Ji + 1; rlk->gj = 2*Jj + 1; lambda0 = (HPLANCK * CLIGHT) / (rlk->Ej - rlk->Ei); rlk->Aji = C / SQ(lambda0) * POW10(gf) / rlk->gj; rlk->Bji = CUBE(lambda0) / (2.0 * HPLANCK * CLIGHT) * rlk->Aji; rlk->Bij = (rlk->gj / rlk->gi) * rlk->Bji; /* --- Store in nm -- -------------- */ rlk->lambda0 = lambda0 / NM_TO_M; /* --- Get quantum numbers for angular momentum and spin -- - */ determined = RLKdeterminate(labeli, labelj, rlk); rlk->polarizable = (atmos.Stokes && determined); /* --- Line broadening -- -------------- */ strncpy(Gvalues, inputLine+79, 18); Nread += sscanf(Gvalues, "%lf %lf %lf", &Grad, &GStark, &GvdWaals); if (GStark != 0.0) rlk->GStark = POW10(GStark) * CUBE(CM_TO_M); else rlk->GStark = 0.0; if (GvdWaals != 0.0) rlk->GvdWaals = POW10(GvdWaals) * CUBE(CM_TO_M); else rlk->GvdWaals = 0.0; /* --- If possible use Barklem formalism -- -------------- */ useBarklem = FALSE; if (determined) { if ((rlk->Li == S_ORBIT && rlk->Lj == P_ORBIT) || (rlk->Li == P_ORBIT && rlk->Lj == S_ORBIT)) { useBarklem = getBarklemcross(&bs_SP, rlk); } else if ((rlk->Li == P_ORBIT && rlk->Lj == D_ORBIT) || (rlk->Li == D_ORBIT && rlk->Lj == P_ORBIT)) { useBarklem = getBarklemcross(&bs_PD, rlk); } else if ((rlk->Li == D_ORBIT && rlk->Lj == F_ORBIT) || (rlk->Li == F_ORBIT && rlk->Lj == D_ORBIT)) { useBarklem = getBarklemcross(&bs_DF, rlk); } } /* --- Else use good old Unsoeld -- -------------- */ if (!useBarklem) { getUnsoldcross(rlk); } /* --- Radiative broadening -- -------------- */ if (Grad != 0.0) { rlk->Grad = POW10(Grad); } else { /* --- Just take the Einstein Aji value, but only if either Stark or vd Waals broadening is in effect -- ------- */ if (GStark != 0.0 || GvdWaals != 0.0) rlk->Grad = rlk->Aji; else { rlk->Grad = 0.0; /* --- In this case the line is not polarizable because there is no way to determine its damping -- ------ */ rlk->polarizable = FALSE; } } /* --- Isotope and hyperfine fractions and slpittings -- ---- */ Nread += sscanf(inputLine+106, "%d", &rlk->isotope); Nread += sscanf(inputLine+108, "%lf", &rlk->isotope_frac); rlk->isotope_frac = POW10(rlk->isotope_frac); Nread += sscanf(inputLine+117, "%lf", &rlk->hyperfine_frac); rlk->hyperfine_frac = POW10(rlk->hyperfine_frac); Nread += sscanf(inputLine+123, "%5d%5d", &hfs_i, &hfs_j); rlk->hfs_i = ((double) hfs_i) * MILLI * KBOLTZMANN; rlk->hfs_j = ((double) hfs_j) * MILLI * KBOLTZMANN; /* --- Effective Lande factors -- -------------- */ Nread += sscanf(inputLine+143, "%5d%5d", &gL_i, &gL_j); rlk->gL_i = gL_i * MILLI; rlk->gL_j = gL_j * MILLI; if (swap_levels) { SWAPDOUBLE(rlk->hfs_i, rlk->hfs_j); SWAPDOUBLE(rlk->gL_i, rlk->gL_j); } /* Nread += sscanf(inputLine+154, "%d", &iso_dl); */ iso_dl = 0; rlk->iso_dl = iso_dl * MILLI * ANGSTROM_TO_NM; checkNread(Nread, Nrequired=17, routineName, checkPoint=1); /* printf(" Line: %f (vacuum), %f (air)\n" " gi, gj: %f, %f\n" " Ei, Ej: %e, %e\n" " Aji: %e\n" " Grad, GStark, GvdWaals: %e, %e, %e\n" " VdWaals: %d\n" " hyperfine_frac, isotope_frac: %f, %f\n" " cross, alpha: %e, %e\n\n", rlk->lambda0, lambda_air, rlk->gi, rlk->gj, rlk->Ei, rlk->Ej, rlk->Aji, rlk->Grad, rlk->GStark, rlk->GvdWaals, rlk->vdwaals, rlk->hyperfine_frac, rlk->isotope_frac, rlk->cross, rlk->alpha); */ rlk++; } } fclose(fp_linelist); sprintf(messageStr, "Read %d Kurucz lines from file %s\n", Nline, listName); Error(MESSAGE, routineName, messageStr); atmos.Nrlk += Nline; } fclose(fp_Kurucz); free_BS(&bs_SP); free_BS(&bs_PD); free_BS(&bs_DF); }
int main(int argc, char *argv[]) { register int n, k; char rayFileName[14], inputLine[MAX_LINE_SIZE]; bool_t result, exit_on_EOF, to_obs, initialize, crosscoupling, analyze_output, equilibria_only; int Nspect, Nread, Nrequired, checkPoint, *wave_index = NULL; double muz, *S, *chi, *J; FILE *fp_out, *fp_ray, *fp_stokes; XDR xdrs; ActiveSet *as; setOptions(argc, argv); getCPU(0, TIME_START, NULL); SetFPEtraps(); /* --- Read input data and initialize -- -------------- */ readInput(); spectrum.updateJ = FALSE; /* --- Read input data for atmosphere -- -------------- */ getCPU(1, TIME_START, NULL); MULTIatmos(&atmos, &geometry); /* --- Read direction cosine for ray -- -------------- */ if ((fp_ray = fopen(RAY_INPUT_FILE, "r")) == NULL) { sprintf(messageStr, "Unable to open inputfile %s", RAY_INPUT_FILE); Error(ERROR_LEVEL_2, argv[0], messageStr); } getLine(fp_ray, COMMENT_CHAR, inputLine, exit_on_EOF=TRUE); Nread = sscanf(inputLine, "%lf", &muz); checkNread(Nread, Nrequired=1, argv[0], checkPoint=1); if (muz <= 0.0 || muz > 1.0) { sprintf(messageStr, "Value of muz = %f does not lie in interval <0.0, 1.0]\n", muz); Error(ERROR_LEVEL_2, argv[0], messageStr); } if (input.StokesMode == FIELD_FREE || input.StokesMode == POLARIZATION_FREE) { input.StokesMode = FULL_STOKES; } /* --- redefine geometry for just this one ray -- -------------- */ atmos.Nrays = geometry.Nrays = 1; geometry.muz[0] = muz; geometry.mux[0] = sqrt(1.0 - SQ(geometry.muz[0])); geometry.muy[0] = 0.0; geometry.wmu[0] = 1.0; if (atmos.Stokes) Bproject(); input.startJ = OLD_J; readAtomicModels(); readMolecularModels(); SortLambda(); getBoundary(&geometry); /* --- Open file with background opacities -- -------------- */ if (atmos.moving || input.StokesMode) { strcpy(input.background_File, "background.ray"); Background(analyze_output=FALSE, equilibria_only=FALSE); } else { Background(analyze_output=FALSE, equilibria_only=TRUE); if ((atmos.fd_background = open(input.background_File, O_RDONLY, 0)) == -1) { sprintf(messageStr, "Unable to open inputfile %s", input.background_File); Error(ERROR_LEVEL_2, argv[0], messageStr); } readBRS(); } convertScales(&atmos, &geometry); getProfiles(); initSolution(); initScatter(); getCPU(1, TIME_POLL, "Total initialize"); /* --- Solve radiative transfer equations -- -------------- */ solveSpectrum(FALSE, FALSE); /* --- Write emergent spectrum to output file -- -------------- */ sprintf(rayFileName, "spectrum_%4.2f", muz); if ((fp_out = fopen(rayFileName, "w" )) == NULL) { sprintf(messageStr, "Unable to open output file %s", rayFileName); Error(ERROR_LEVEL_2, argv[0], messageStr); } xdrstdio_create(&xdrs, fp_out, XDR_ENCODE); result = xdr_double(&xdrs, &muz); result = xdr_vector(&xdrs, (char *) spectrum.I[0], spectrum.Nspect, sizeof(double), (xdrproc_t) xdr_double); /* --- Read wavelength indices for which chi and S are to be written out for the specified direction -- -------------- */ Nread = fscanf(fp_ray, "%d", &Nspect); checkNread(Nread, 1, argv[0], checkPoint=2); if (Nspect > 0) { wave_index = (int *) malloc(Nspect * sizeof(int)); Nread = 0; while (fscanf(fp_ray, "%d", &wave_index[Nread]) != EOF) Nread++; checkNread(Nread, Nspect, argv[0], checkPoint=3); fclose(fp_ray); chi = (double *) malloc(atmos.Nspace * sizeof(double)); if (atmos.Stokes) S = (double *) malloc(4 * atmos.Nspace * sizeof(double)); else S = (double *) malloc(atmos.Nspace * sizeof(double)); } result = xdr_int(&xdrs, &Nspect); /* --- Go through the list of wavelengths -- -------------- */ if (Nspect > 0 && input.limit_memory) J = (double *) malloc(atmos.Nspace * sizeof(double)); for (n = 0; n < Nspect; n++) { if (wave_index[n] < 0 || wave_index[n] >= spectrum.Nspect) { sprintf(messageStr, "Illegal value of wave_index[n]: %4d\n" "Value has to be between 0 and %4d\n", wave_index[n], spectrum.Nspect); Error(ERROR_LEVEL_2, argv[0], messageStr); continue; } sprintf(messageStr, "Processing n = %4d, lambda = %9.3f [nm]\n", wave_index[n], spectrum.lambda[wave_index[n]]); Error(MESSAGE, NULL, messageStr); as = &spectrum.as[wave_index[n]]; alloc_as(wave_index[n], crosscoupling=FALSE); Opacity(wave_index[n], 0, to_obs=TRUE, initialize=TRUE); readBackground(wave_index[n], 0, to_obs=TRUE); if (input.limit_memory) { readJlambda(wave_index[n], J); } else J = spectrum.J[wave_index[n]]; /* --- Add the continuum opacity and emissivity -- -------------- */ 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]*J[k]) / chi[k]; } result = xdr_int(&xdrs, &wave_index[n]); result = xdr_vector(&xdrs, (char *) chi, atmos.Nspace, sizeof(double), (xdrproc_t) xdr_double); result = xdr_vector(&xdrs, (char *) S, atmos.Nspace, sizeof(double), (xdrproc_t) xdr_double); free_as(wave_index[n], crosscoupling=FALSE); } /* --- If magnetic fields are present -- -------------- */ if (atmos.Stokes || input.backgr_pol) { result = xdr_vector(&xdrs, (char *) spectrum.Stokes_Q[0], spectrum.Nspect, sizeof(double), (xdrproc_t) xdr_double); result = xdr_vector(&xdrs, (char *) spectrum.Stokes_U[0], spectrum.Nspect, sizeof(double), (xdrproc_t) xdr_double); result = xdr_vector(&xdrs, (char *) spectrum.Stokes_V[0], spectrum.Nspect, sizeof(double), (xdrproc_t) xdr_double); } if (Nspect > 0 && input.limit_memory) free(J); xdr_destroy(&xdrs); fclose(fp_out); printTotalCPU(); }
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"); }