Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

libcpixe.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005 by Carlos Pascual-Izarra & Miguel A. Reis          *
00003  *   carlos.pascual@itn.pt                                                 *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 
00022 /**\file libcpixe.c
00023 LibCPIXE is a collection of C functions which are useful for Particle
00024 Induced X-ray Emmission (PIXE) data analysis. The main objective is to produce a
00025 publicly available set of functions which can be incorporated in IBA data
00026 analysis codes. 
00027 
00028 News, documentation and latest releases can be found at: http://cpixe.sourceforge.net 
00029 
00030 A number of papers will be published and should be cited if libcpixe is used for producing scientific publications.
00031 
00032 The reference paper for LibCPIXE and CPIXE is:
00033 "LibCPIXE: an open-source library for PIXE simulation and Analysis", Carlos Pascual-Izarra, Nuno P. Barradas and Miguel A. Reis, To be published in Proceedings of the IBA2005 (NIMB)
00034 
00035 A paper showing the integration of LibCPIXE into the Data Furnace code is:
00036 "Simultaneous PIXE and RBS analysis using Bayesian Inference" Carlos Pascual-Izarra, Miguel A. Reis and Nuno P. Barradas, To be published in Proceedings of the IBA2005 (NIMB)
00037 
00038 The seed for this code is on a translation from Pascal to C of
00039 parts of the code writen by M.A. Reis for the DatPixe-v5.3 code. The Pascal code
00040 was initially translated using p2c (an automatic Pascal-to-C free translator)
00041 and afterwards heavily modified.
00042 */
00043 
00044  
00045 #include <stdio.h>
00046 #include <math.h>
00047 #include <string.h>
00048 #include <stdlib.h>
00049 #include "libcpixe.h"
00050 #include "stop96.h"   
00051 #include "compilopt.h"  //here we store variables for the C preprocessor for conditional compiling
00052 
00053 
00054 
00055 
00056 /*Global Constants*/
00057 
00058 /*Physical constants of interest*/
00059 // double m0c2 = 1.503186433e-0010, keV = 1.60621e-0016, uAtmass = 1 / 1822.887,
00060 //        M1sme = 1836.076012, m0pamu = 1.007276470, m0pMeV = 938.3,
00061 //        MeVpamu = 931.52181, v0 = 2.187578544e6, v02 = 4.785499886e12,
00062 //        c2 = 8.98740441e16, cau = 137.03604, pi = 3.141592654,
00063 //        a02 = 2.800283608e-21, Ry = 13.6, Hr = 27.2116, barn = 1.0e-28;
00064 
00065 
00066 
00067 /*Functions*/
00068 
00069 
00070 /**Reads an input file consisting on a series of commands.
00071  * 
00072  * @param InputFileNm (I) Name of the input file (no more than LONGSTRINGLENGTH characters)
00073  * @param pexppar (O) pointer to the experimental parameter structure
00074  * @param pExtraInfo (O) pointer to structure containing misc data read from input file 
00075  * @return Always 0
00076  */
00077 int readINPUT(const char *InputFileNm, EXP_PARAM *pexppar, EXTRAINFO *pExtraInfo)
00078 {
00079   FILE *f;
00080   int i;
00081   char *command,*arg;
00082   char line[LONGSTRINGLENGTH]="";
00083   int flag[16]; /*We use 11 control flags to check that the reading was fine (they must all end with a value different than 0)*/
00084   
00085   
00086   /*Reset control flags*/
00087   for(i=0;i<16;i++)flag[i]=0;
00088   pExtraInfo->WantOutputfile=0;
00089   pExtraInfo->DoCalibration=0;
00090   //set to -1 (which is true) some flags regarding to non-mandatory commands (and set default value for those commands); 
00091   pexppar->simpar.AllowSXFCorr=0;flag[10]=-1; 
00092   pexppar->simpar.AllowXEqCalc=0; flag[11]=-1;
00093   
00094   f = fopen(InputFileNm, "r");
00095   if (f == NULL)
00096     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",InputFileNm);exit(1);}
00097   
00098   /*Skip until "BEGIN_INPUT"*/
00099   for(;!feof(f) && strcasecmp(line, "BEGIN_INPUT");){
00100    fscanf(f,"%255s",line);
00101    flag[0]=1;
00102   }  
00103   
00104   for(;!feof(f);){
00105     //reads an entire line of at much LONGSTRINGLENGTH characters
00106     fgets(line,sizeof(line),f);   
00107     
00108     //Now we parse the line looking for a known command and discarding comments
00109     //fscanf(f,"%255s",command);
00110     command = strtok( line, "\n\t \r" ) ;
00111     if( command != NULL && command[0] != '#' ){
00112       
00113       
00114       
00115       /*"END_INPUT" command just exits the for loop*/
00116       if(!strcmp(command,"END_INPUT")){
00117         flag[1]=1;
00118         break;
00119       }
00120       else if(!strcmp(command,"ION")){
00121         /*Syntax: 
00122         ION symbol   <---"symbol" is the beam ion chem. symbol. The Most abundant isotope will be used by default. */
00123 //         fscanf(f,"%3s",pexppar->ion.symbol);
00124         arg=strtok( NULL,"\n\t \r");
00125         strncpy(pexppar->ion.symbol,arg,3);
00126         ///@todo For the moment, only H ions are supported
00127         if (strncasecmp(pexppar->ion.symbol,"H",3)) 
00128           {fprintf(stderr,"\nERROR: Currently, only H ions are supported\n");exit(1);} 
00129         pexppar->ion.Z=symbol2Z(pexppar->ion.symbol);
00130         pexppar->ion.A=Z2mass(pexppar->ion.Z, &pexppar->ion.IM,'m');
00131         Z2mass(pexppar->ion.Z, &pexppar->ion.M,'n');
00132         flag[2]=1;
00133         //printf("\n\n!!!!!!!!!!!!!!!!!!!!!!!! ION='%s'\n\n",pexppar->ion.symbol);getchar();
00134       }
00135       else if(!strcmp(command,"IONMASS")){
00136         /*Syntax: 
00137         IONMASS mass   <---"mass" is the beam ion weight in amu. This can be used for defining isotopes. */
00138 //         fscanf(f,"%lf", &pexppar->ion.M);
00139         arg=strtok( NULL,"\n\t \r");
00140         pexppar->ion.M=atof(arg);
00141         /*Note that this is an optional command, no flag is changed*/
00142       }
00143       else if(!strcmp(command,"KEV")){
00144         /*Syntax: 
00145         KEV Ebeam   <---"Ebeam" is Beam energy in keV.  */
00146 //         fscanf(f, "%lg", &pexppar->BeamEner); //keV
00147         arg=strtok( NULL,"\n\t \r");
00148         pexppar->BeamEner=atof(arg);
00149         flag[3]=1;
00150       }
00151       else if(!strcmp(command,"INCANG")){
00152         /*Syntax: 
00153         INCANG thetavalue   <---Incience angle: Sample normal to beam*/
00154 //         fscanf(f, "%lg", &pexppar->IncAng);
00155         arg=strtok( NULL,"\n\t \r");
00156         pexppar->IncAng=atof(arg);
00157         pexppar->IncAng *= DEG2RAD;
00158         pexppar->cosInc = cos(pexppar->IncAng);
00159         flag[4]=1;
00160         }
00161       else if(!strcmp(command,"EXITANG")){ 
00162         /*Syntax: 
00163         EXITANG phivalue   <---Exit angle. Sample normal to detector. */
00164 //         fscanf(f, "%lg", &pexppar->DetAng); 
00165         arg=strtok( NULL,"\n\t \r");
00166         pexppar->DetAng=atof(arg);
00167         pexppar->DetAng *= DEG2RAD;
00168         pexppar->cosDet = cos(pexppar->DetAng);
00169         flag[5]=1;
00170       }
00171       else if(!strcmp(command,"BEAMCOL")){ 
00172         /*Syntax: 
00173         BEAMCOL diameter   <--Beam diameter, in mm */
00174 //         fscanf(f, "%lg", &pexppar->BeamCol);
00175         arg=strtok( NULL,"\n\t \r");
00176         pexppar->BeamCol=atof(arg);
00177         pexppar->BeamCross = M_PI * (pexppar->BeamCol*pexppar->BeamCol) / 400;   /* beam cross-section in cm2 */
00178         flag[6]=1;
00179       }
00180       else if(!strcmp(command,"DETCOLFAC")){ 
00181         /*Syntax: 
00182         DETCOLFAC factor   <---Detector colimator factor... really this should be solid angle */
00183         arg=strtok( NULL,"\n\t \r");
00184         pexppar->DetColFac=atof(arg);
00185 //         fscanf(f, "%lg", &pexppar->DetColFac);  
00186         flag[7]=1;
00187       }
00188       else if(!strcmp(command,"CHARGE")){ 
00189         /*Syntax: 
00190         CHARGE ColCharge   <---Collected charge, in uC */
00191         arg=strtok( NULL,"\n\t \r");
00192         pexppar->simpar.ColCharge=atof(arg);
00193 //         fscanf(f, "%lg", &pexppar->simpar.ColCharge);  
00194         flag[8]=1;
00195       }
00196       else if(!strcmp(command,"LIVETIME")){ 
00197         /*Syntax: 
00198         LIVETIME factor   <---Dead time correction (Integrated"Charge"/IntegratedCounts) */
00199         arg=strtok( NULL,"\n\t \r");
00200         pexppar->simpar.DTCC=atof(arg);
00201 //         fscanf(f, "%lg", &pexppar->simpar.DTCC);  
00202         flag[9]=1;
00203       }
00204       else if(!strcmp(command,"ALLOWSXFCORR")){ 
00205         /*Syntax: 
00206         ALLOWSXFCORR flag   <---Flag allowing for calculation of Sec. Fluorescence  */  
00207         arg=strtok( NULL,"\n\t \r"); ///@todo: SXF not supported yet
00208         pexppar->simpar.AllowSXFCorr=atoi(arg);
00209 //        fscanf(f, "%d", &pexppar->simpar.AllowSXFCorr);   
00210         flag[10]=1;
00211       }
00212       else if(!strcmp(command,"ALLOWXEQCALC")){ 
00213         /*Syntax: 
00214         ALLOWXEQCALC flag   <---Deat time correction (Integrated"Charge"/IntegratedCounts) */
00215         arg=strtok( NULL,"\n\t \r"); ///@todo: Xeq calculation not
00216         pexppar->simpar.AllowXEqCalc=atoi(arg);
00217 //        fscanf(f, "%d", &pexppar->simpar.AllowXEqCalc);   
00218         flag[11]=1;
00219       }
00220       else if(!strcmp(command,"CALIBFILE")){
00221         /*Syntax:
00222         CALIBFILE Calfilename     <---Name of the calibration  (XrayYld) file
00223         */
00224         arg=strtok( NULL,"\n\t \r");
00225         strncpy(pExtraInfo->XYldFileNm,arg,LONGSTRINGLENGTH);
00226 //         fscanf(f,"%255s",pExtraInfo->XYldFileNm);
00227         flag[12]=1;
00228         pExtraInfo->DoCalibration=0;
00229       }  
00230       else if(!strcmp(command,"DOCALIBRATION")){
00231         /*Syntax:
00232         DOCALIBRATION flag    <---Flag indicating whether the intention is to simulate (0) or to do a calibration (1)
00233         */
00234         arg=strtok( NULL,"\n\t \r");
00235         pExtraInfo->DoCalibration=atoi(arg);
00236 //         fscanf(f, "%d", &pExtraInfo->DoCalibration);
00237         flag[12]=1;
00238       } 
00239       else if(!strcmp(command,"SAMPLEFILE")){
00240         /*Syntax:
00241         SAMPLEFILE SampleFilename     <---Name of the Sample definition file
00242         */
00243 //         fscanf(f,"%255s",pExtraInfo->SampleFileNm);
00244         arg=strtok( NULL,"\n\t \r");
00245         strncpy(pExtraInfo->SampleFileNm,arg,LONGSTRINGLENGTH);
00246         flag[13]=1;
00247       } 
00248       else if(!strcmp(command,"FILTERFILE")){
00249         /*Syntax:
00250         FILTERFILE Filterfilename     <---Name of the Filter definition file
00251         */
00252 //         fscanf(f,"%255s",pExtraInfo->FilterFileNm);
00253         arg=strtok( NULL,"\n\t \r");
00254         strncpy(pExtraInfo->FilterFileNm,arg,LONGSTRINGLENGTH);
00255         flag[14]=1;
00256       }  
00257       else if(!strcmp(command,"CFLAGSFILE")){
00258         /*Syntax:
00259         CFLAGSFILE CFlagsfilename     <---Name of the Calculation flags definition file
00260         */
00261 //         fscanf(f,"%255s",pExtraInfo->AreasFileNm);
00262         arg=strtok( NULL,"\n\t \r");
00263         strncpy(pExtraInfo->AreasFileNm,arg,LONGSTRINGLENGTH);
00264         pExtraInfo->AreasFormat=1;
00265         flag[15]=1;
00266       }
00267       else if(!strcmp(command,"DTAREASFILE")){
00268         /*Syntax:
00269         DTAREASFILE DTAreasfilename     <---Name of the Areas file (in DATTPIXE format)
00270         */
00271 //         fscanf(f,"%255s",pExtraInfo->AreasFileNm);
00272         arg=strtok( NULL,"\n\t \r");
00273         strncpy(pExtraInfo->AreasFileNm,arg,LONGSTRINGLENGTH);
00274         pExtraInfo->AreasFormat=2;
00275         flag[15]=1;
00276       } 
00277       else if(!strcmp(command,"DBPATH")){
00278         /*Syntax:
00279         DBPATH Path   <---Path to DataBase files (optional)
00280         */
00281 //         fscanf(f,"%255s",pExtraInfo->DBpath);
00282         arg=strtok( NULL,"\n\t \r");
00283         strncpy(pExtraInfo->DBpath,arg,LONGSTRINGLENGTH);
00284       }  
00285       else if(!strcmp(command,"OUTPUTFILE")){
00286         /*Syntax:
00287         OUTPUTFILE Outputfilename   <---Name for the output file
00288         */
00289 //         fscanf(f,"%255s",pExtraInfo->OutputFileNm);
00290         arg=strtok( NULL,"\n\t \r");
00291         strncpy(pExtraInfo->OutputFileNm,arg,LONGSTRINGLENGTH);
00292         pExtraInfo->WantOutputfile=1;
00293         /*note: this command is optional, but a flag indicating if it was used is passed*/
00294       }  
00295       /*If "command" is not valid...*/
00296       else {
00297         fprintf(stderr,"\n ERROR:ReadInput: command '%s' not known. Press <INTRO> to continue ...***\n",command);
00298         getchar();
00299       }
00300     }
00301   }
00302   
00303   //close input file
00304   fclose(f);
00305   
00306   /*check control flags*/  
00307   for(i=0;i<16;i++)if(flag[i]==0){fprintf(stderr,"\n ERROR:ReadInput: Missing command in inputfile (#%i)\n",i);exit(1);}
00308   
00309   pexppar->cosFac = pexppar->cosInc / pexppar->cosDet;
00310   
00311   pexppar->FinalEner = 0.1 * pexppar->BeamEner;  //below this energy no calculations will be done
00312   if(pexppar->FinalEner>100.)pexppar->FinalEner = 100.; 
00313   
00314   return(0); 
00315   
00316 }
00317 
00318 
00319 
00320 
00321 /**Fills an EXP_PARAM struct with data from a file.
00322   The file must have the following format:
00323   ------------------
00324   BeamEner
00325   BeamCol
00326   DetColFac
00327   IncAng
00328   DetAng
00329   ------------------
00330 
00331   * 
00332   * @param ExpParFileNm (I) Name of the file to be read.
00333   * @param pexppar (O) Pointer to struct containing the experimental parameters
00334   * @return Always 0
00335   */
00336  int readEXP_PARAM(char *ExpParFileNm, EXP_PARAM *pexppar)
00337 {
00338   //EXP_PARAM pexppar;
00339   FILE *ExpParFile;
00340     
00341   ExpParFile = fopen(ExpParFileNm, "r");
00342   if (ExpParFile == NULL)
00343     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",ExpParFileNm);exit(1);}
00344   
00345   
00346   strncpy(pexppar->ion.symbol,"H",2);  ///@todo For the moment, only H ions are supported
00347   pexppar->ion.Z=symbol2Z(pexppar->ion.symbol);
00348   pexppar->ion.A=Z2mass(pexppar->ion.Z, &pexppar->ion.IM,'m');
00349   Z2mass(pexppar->ion.Z, &pexppar->ion.M,'n');
00350  
00351   fscanf(ExpParFile, "%lg", &pexppar->BeamEner); //keV
00352   fscanf(ExpParFile, "%lg", &pexppar->BeamCol);  
00353   fscanf(ExpParFile, "%lg", &pexppar->DetColFac); 
00354   fscanf(ExpParFile, "%lg", &pexppar->IncAng);  
00355   fscanf(ExpParFile, "%lg", &pexppar->DetAng);   
00356   
00357   fclose(ExpParFile);
00358   
00359   pexppar->IncAng *= DEG2RAD;
00360   pexppar->cosInc = cos(pexppar->IncAng);
00361   pexppar->DetAng *= DEG2RAD;
00362   pexppar->cosDet = cos(pexppar->DetAng);
00363   pexppar->BeamCross = M_PI * (pexppar->BeamCol*pexppar->BeamCol) / 400;   /* beam cross-section in cm2 */
00364   
00365 
00366   pexppar->cosFac = pexppar->cosInc / pexppar->cosDet;
00367   
00368   pexppar->FinalEner = 0.1 * pexppar->BeamEner;  //below this energy no calculations will be done
00369   if(pexppar->FinalEner>100.)pexppar->FinalEner = 100.; 
00370 
00371       
00372   return(0);
00373 }
00374 
00375 /**Fills a SIM_PARAM struct with data from a file.
00376   The file must have the following format:
00377   ------------------
00378   Samplefilename
00379   absorbertype
00380   AllowSXFCorr
00381   AllowXEqCalc
00382   GenPulNumb
00383   GenInteg
00384   ColCharge
00385   ------------------
00386  * 
00387  * @param SampleParamFileNm (I) Name of the file to be read.
00388  * @param simpar (O) Pointer to struct containing the simulation parameters
00389  * @param IniMatFileNm (O) Name of the file defining sample
00390  * @param FilterFileNm (O) Name of the filter definition file
00391  * @param XYldFileNm (O) Name of the calibration yield file
00392  * @return Always 0
00393  */
00394 int readSIM_PARAM(char *SampleParamFileNm, SIM_PARAM *simpar,char *IniMatFileNm, char *FilterFileNm, char *XYldFileNm)
00395 {
00396   
00397   FILE *SampleParamFile;
00398   char AbsType[6];
00399 //   double GenPulNumb,GenInteg;
00400 //   absorber FilterNul ={ 0, "00000", 1,
00401 //                       { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
00402 //                       { { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
00403 //                         { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
00404 //                         { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } 
00405 //                       },
00406 //                       { 0.0, 0.0, 0.0 }  };
00407   
00408     
00409     
00410   SampleParamFile = fopen(SampleParamFileNm, "r");
00411   if (SampleParamFile == NULL)
00412     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",SampleParamFileNm);exit(1);}
00413 
00414  
00415   fscanf(SampleParamFile,"%255s",IniMatFileNm);  //name of sample file
00416   fscanf(SampleParamFile,"%255s",FilterFileNm);  //name of Filter file
00417   fscanf(SampleParamFile,"%255s",XYldFileNm);  //name of calibration file
00418   fscanf(SampleParamFile, "%5s", AbsType);   // is Char[6]
00419   fscanf(SampleParamFile, "%d",  &simpar->AllowSXFCorr);   //1=true, 0=false
00420   fscanf(SampleParamFile, "%d",  &simpar->AllowXEqCalc);   //1=true, 0=false
00421   fscanf(SampleParamFile, "%lg", &simpar->DTCC); //deadtime correction (Integrated"Charge"/IntegratedCounts)
00422 //   fscanf(SampleParamFile, "%lg", &GenPulNumb);
00423 //   fscanf(SampleParamFile, "%lg", &GenInteg);
00424 //   simpar->DTCC = GenInteg / GenPulNumb;
00425   //simpar->DTCCerr = 2 * sqrt(GenPulNumb - GenInteg) / GenPulNumb;
00426   fscanf(SampleParamFile, "%lg", &simpar->ColCharge); //Colected charge, in ?? uC ??
00427     
00428   fclose(SampleParamFile);
00429   
00430   ///@todo complete here the initialization for the case when a filter is used. UPDATE: this should be managed elsewhere, probably in FilterTrans() or readFilter()
00431   if (strcasecmp(AbsType, "NoAbs")) {
00432     simpar->useFilter=1;
00433     /*
00434     strcpy(FiltersCoefFile.name, FiltersCoefFileNm);
00435     if (*FiltersCoefFile.name != '\0') {
00436       if (FiltersCoefFile.f != NULL)
00437   FiltersCoefFile.f = freopen(FiltersCoefFile.name, "rb",
00438             FiltersCoefFile.f);
00439       else
00440   FiltersCoefFile.f = fopen(FiltersCoefFile.name, "rb");
00441     } else
00442       rewind(FiltersCoefFile.f);
00443     if (FiltersCoefFile.f == NULL)
00444       _EscIO2(FileNotFound, FiltersCoefFile.name);
00445     RESETBUF(FiltersCoefFile.f, absorber);
00446     fseek(FiltersCoefFile.f, (AbsN - 1) * sizeof(absorber), SEEK_SET);
00447     SETUPBUF(FiltersCoefFile.f, absorber);
00448     fread(&Filter, sizeof(absorber), 1, FiltersCoefFile.f);
00449     fclose(FiltersCoefFile.f);
00450     FiltersCoefFile.f = NULL;
00451     strcpy(AbsType, Filter.name);
00452     */
00453   }else {
00454 //     simpar->Filter = FilterNul;
00455     simpar->useFilter=0;
00456   }
00457   return(0);  
00458 }
00459 
00460 
00461 
00462 
00463 /**Returns the atomic number for a certain element (up to Z=109)
00464  * This is a faster version than that of hstoplib.c because it does not access any file.
00465  * 
00466  * @param symbol (I) Chemical symbol of the element (case insensitive)
00467  * @return Atomic Number
00468  */
00469 int symbol2Z(char *symbol){
00470   int Z;
00471   /**Array containing the chemical symbols from H(Z=1) to Mt(Z=109) */
00472   ChemSymb chsymbols[110] = {
00473     "--", "H" , "He", "Li", "Be", "B" , "C" , "N" , "O" , "F" , "Ne", "Na",
00474     "Mg", "Al", "Si", "P" , "S" , "Cl", "Ar", "K" , "Ca", "Sc", "Ti", "V" , 
00475     "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", 
00476     "Kr", "Rb", "Sr", "Y" , "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", 
00477     "Cd", "In", "Sn", "Sb", "Te", "I" , "Xe", "Cs", "Ba", "La", "Ce", "Pr", 
00478     "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", 
00479     "Hf", "Ta", "W" , "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", 
00480     "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U" , "Np", "Pu", "Am", 
00481     "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", 
00482     "Hs", "Mt"
00483   };
00484   for(Z=1;strncasecmp(symbol,chsymbols[Z],3) && Z<=99;Z++);
00485   if(Z<1 || Z> 109) {fprintf(stderr,"\nERROR: Chemical Symbol '%s' not known.\n",symbol);exit(1);}
00486   else return(Z);
00487 }
00488 
00489 
00490 /**Returns mass information for a given element (specified by its atomic number).
00491  * Currently the range is limited from Z=1 (H) to Z=92 (U).
00492  * It provides the Natural (average) weight, Most Abundant Isotope (MAI) weight and
00493  * Most Abundant Isotope number of nucleons
00494  * 
00495  * @param Z (I) Atomic number
00496  * @param mass (O) mass in amu. See also the "option" argument.
00497  * @param option (I) Either 'n' or 'm' to select "Natural" or "MAI" mass, respectively
00498  * @return Number of nucleons of the Most Abundant Isotope
00499  */
00500 int Z2mass(int Z, double *mass, char option)
00501 {
00502   /**Array containing the chemical symbols from H(Z=1) to Es(Z=99) */
00503   int maiAArray[93]={
00504       0 ,       1 ,       4 ,       7 ,       9 ,      11 ,      12 ,      14 ,      
00505      16 ,      19 ,      20 ,      23 ,      24 ,      27 ,      28 ,      31 ,      
00506      32 ,      35 ,      40 ,      39 ,      40 ,      45 ,      48 ,      51 ,      
00507      52 ,      55 ,      56 ,      59 ,      58 ,      63 ,      64 ,      69 ,      
00508      74 ,      75 ,      80 ,      79 ,      84 ,      85 ,      88 ,      89 ,      
00509      90 ,      93 ,      98 ,      97 ,     102 ,     103 ,     106 ,     107 ,     
00510     114 ,     115 ,     120 ,     121 ,     130 ,     127 ,     132 ,     133 ,     
00511     138 ,     139 ,     140 ,     141 ,     142 ,     148 ,     152 ,     153 ,     
00512     158 ,     159 ,     164 ,     165 ,     166 ,     169 ,     174 ,     175 ,     
00513     180 ,     181 ,     184 ,     187 ,     192 ,     193 ,     195 ,     197 ,     
00514     202 ,     205 ,     208 ,     209 ,     209 ,     210 ,     222 ,     223 ,     
00515     226 ,     227 ,     232 ,     231 ,     238};
00516   
00517   double maiMArray[93]={
00518      0.000  ,   1.008 ,   4.003 ,   7.016 ,   9.012 ,  11.009 ,  12.000 ,  14.003 ,  
00519      15.995 ,  18.998 ,  19.992 ,  22.990 ,  23.985 ,  26.982 ,  27.977 ,  30.974 ,  
00520      31.972 ,  34.969 ,  39.962 ,  38.964 ,  39.963 ,  44.956 ,  47.950 ,  50.940 ,  
00521      51.940 ,  54.940 ,  55.935 ,  58.930 ,  57.940 ,  62.930 ,  63.930 ,  68.930 ,  
00522      73.920 ,  74.920 ,  79.920 ,  78.920 ,  83.912 ,  84.910 ,  87.910 ,  88.906 ,  
00523      89.900 ,  92.910 ,  97.905 ,  97.000 , 101.900 , 102.900 , 105.900 , 106.900 , 
00524     113.900 , 114.900 , 119.900 , 120.900 , 129.906 , 126.900 , 131.904 , 132.905 , 
00525     137.905 , 139.000 , 140.000 , 141.000 , 142.000 , 148.000 , 152.000 , 153.000 , 
00526     157.900 , 158.925 , 164.000 , 165.000 , 166.000 , 169.000 , 174.000 , 175.000 , 
00527     180.000 , 181.000 , 184.000 , 187.000 , 192.000 , 193.000 , 195.000 , 197.000 , 
00528     202.000 , 205.000 , 208.000 , 209.000 , 208.982 , 210.000 , 222.000 , 223.000 , 
00529     226.000 , 227.000 , 232.000 , 231.000 , 238.040 };
00530   
00531   double natMArray[93]={
00532       0.000 ,   1.008 ,   4.003 ,   6.941 ,   9.012 ,  10.811 ,  12.011 ,  14.007 ,
00533      15.999 ,  18.998 ,  20.180 ,  22.990 ,  24.305 ,  26.982 ,  28.086 ,  30.974 ,  
00534      32.066 ,  35.453 ,  39.948 ,  39.098 ,  40.080 ,  44.956 ,  47.900 ,  50.942 ,  
00535      51.996 ,  54.938 ,  55.847 ,  58.933 ,  58.690 ,  63.546 ,  65.390 ,  69.720 ,  
00536      72.610 ,  74.922 ,  78.960 ,  79.904 ,  83.800 ,  85.470 ,  87.620 ,  88.905 ,  
00537      91.220 ,  92.906 ,  95.940 ,  97.000 , 101.070 , 102.910 , 106.400 , 107.870 , 
00538     112.400 , 114.820 , 118.710 , 121.750 , 127.600 , 126.900 , 131.300 , 132.910 , 
00539     137.327 , 138.910 , 140.120 , 140.910 , 144.240 , 148.000 , 150.360 , 151.970 , 
00540     157.250 , 158.930 , 162.500 , 164.930 , 167.260 , 168.930 , 173.040 , 174.970 , 
00541     178.490 , 180.950 , 183.850 , 186.200 , 190.200 , 192.200 , 195.080 , 196.970 , 
00542     200.590 , 204.380 , 207.190 , 208.980 , 210.000 , 210.000 , 222.000 , 223.000 , 
00543     226.000 , 227.000 , 232.000 , 231.000 , 238.030 };
00544   
00545   if(Z<1 || Z> 92) {fprintf(stderr,"\nERROR: Data for Atomic number '%d' not available.\n",Z);exit(1);}
00546   
00547   switch(option){
00548     case 'n':  // Natural Mass (i.e., isotopic average) , in amu
00549       *mass=natMArray[Z];
00550       break;
00551     case 'm':  // Most Abundant Isotope mass, in amu
00552       *mass=maiMArray[Z];
00553       break;
00554     default:
00555       {fprintf(stderr,"\nERROR: Z2mass() Option argument can only be 'n' (natural) or 'm' (most abundant) \n");exit(1);}
00556       break;
00557   }
00558   
00559   return(maiAArray[Z]);
00560 }
00561 
00562 
00563 /**Reads a compound of 'nelem' elements from the stream f and fills with this info  the the compound c
00564  * This is a slightly modified version from that of hstoplib.c 
00565  * It fills the normalized atomic and mass concentration.
00566  * Mass of the elements is obtained by calling Z2mass()
00567  *
00568  * The data from the stream must have the following format (repeated nelem times):
00569  * [element] [atomic_concentration]
00570  * ...
00571  * 
00572  * @param f (I) Pointer to a stream from which the compound definition is read.
00573  * @param nelem (I) Number of elements in the compound
00574  * @param c (O) Pointer to structure defining the compound
00575  * @return Maximum Atomic number read 
00576  */
00577 int readCOMPOUND(FILE *f, int nelem, COMPOUND *c)
00578 {
00579   int i,nchar1,nchar2,maxZ;
00580   double sumM;
00581   char temp[30],temp2[30];
00582   
00583   //if(nelem==0)readCOMPOUND2(f, c);  //Modified from the original
00584   if(nelem<1){fprintf(stderr,"\n ERROR: readCOMPOUND must read at least 1 element\n");exit(1);}
00585   else{
00586     c->nelem=nelem;
00587     if(!(c->elem=(ELEMENT*)calloc(nelem,sizeof(ELEMENT)))){fprintf(stderr,"\n Error allocating memory\n");exit(1);}
00588     if(!(c->X=(double*)calloc(nelem,sizeof(double)))){fprintf(stderr,"\n Error allocating memory\n");exit(1);}
00589     if(!(c->xn=(double*)calloc(nelem,sizeof(double)))){fprintf(stderr,"\n Error allocating memory\n");exit(1);}
00590     if(!(c->w=(double*)calloc(nelem,sizeof(double)))){fprintf(stderr,"\n Error allocating memory\n");exit(1);}
00591     for(maxZ=0.,c->sumX=0.,sumM=0.,i=0,nchar1=0,nchar2=0 ; i<nelem ; i++){
00592       fscanf(f,"%2s%lf",(c->elem[i].symbol),&(c->X[i]));
00593       c->elem[i].Z=symbol2Z(c->elem[i].symbol);
00594       c->elem[i].A=Z2mass(c->elem[i].Z, &c->elem[i].IM, 'm');
00595       Z2mass(c->elem[i].Z, &c->elem[i].M, 'n');
00596       
00597       
00598       if(c->elem[i].Z==0){fprintf(stderr,"\n ERROR: Chemical symbol '%s' not valid\n",c->elem[i].symbol);exit(1);}
00599       c->sumX+=c->X[i];
00600       sumM+=c->elem[i].M*c->X[i];
00601       if(c->elem[i].Z>maxZ)maxZ=c->elem[i].Z;
00602       nchar1+=strlen(c->elem[i].symbol);
00603       nchar2+=snprintf(temp,30,"%4lf",c->X[i]);
00604     }
00605     /*Normalize concentrations and calculate the MASS concentration*/
00606     for(i=0;i<nelem;i++){
00607       c->xn[i]=c->X[i]/c->sumX;
00608       c->w[i]=c->X[i]*c->elem[i].M/sumM;
00609     }
00610     /*Build the name of the compound*/
00611     strcpy(temp2,"");
00612     strcpy(temp,"");
00613     if(nchar1+nchar2 < 30 && nelem<4){
00614       for(i=0;i<nelem;i++){
00615         if(c->X[i]!=1.)snprintf(temp,30,"%s%1.lf",c->elem[i].symbol,c->X[i]);
00616         else snprintf(temp,30,"%s",c->elem[i].symbol);
00617         strcat(temp2,temp);
00618       }
00619     }
00620     else if(nchar1<30){
00621       for(i=0;i<nelem;i++){
00622         snprintf(temp,30,"%s",c->elem[i].symbol);
00623         strcat(temp2,temp);
00624       }
00625     }
00626     else{
00627       for(i=0;i<nelem;i++){
00628         snprintf(temp2,25,"%s%s",temp,c->elem[i].symbol);
00629         strcpy(temp,temp2);
00630       }
00631       snprintf(temp2,30,"%s+",temp); 
00632     } 
00633     strcpy(c->name,temp2);
00634   }
00635   return(maxZ);
00636 }
00637 
00638 
00639 
00640 
00641 /**Allocates and initializes the sample definition from a file. 
00642    It also returns Number of foils and Maximum atomic number present in sample.
00643   
00644   The File must have the following format:
00645   -----------------
00646   NUMBER_OF_FOILS [nfoils]
00647   FOIL [thickness_in_ug/cm2] 
00648   [numberofelems]
00649   [symbol] [concentration]
00650   [symbol] [concentration]
00651   ...
00652   FOIL CalEner
00653   [numberofelems]
00654   [symbol] [concentration]
00655   ...
00656   -----------------
00657   
00658   Note:Any number of foils and any number of elements are allowed.
00659 
00660  * 
00661  * @param SampleDefFileNm (I) Name of the file to be read.
00662  * @param MaxZ (O) Largest atomic number present in sample (Dimension of PresentElems).
00663  * @param NFoil (O) Number of target foils
00664  * @param Sample (O) Pointer to Array of files (Dim=NFoil)
00665  * @return Always 0
00666  */
00667 int readsample(char *SampleDefFileNm, int *MaxZ, int *NFoil, foil **Sample)
00668 {
00669   
00670   FILE *SampleDefFile;
00671   char dummy[LONGSTRINGLENGTH];
00672   int i,tempZ,j;
00673   foil *pfoil;
00674   double ug2at,natmass;
00675   SampleDefFile = fopen(SampleDefFileNm, "r");
00676   if (SampleDefFile == NULL)
00677     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",SampleDefFileNm);exit(1);}
00678       
00679   /*Skip until "NUMBER OF FOILS"*/
00680   do {
00681     fscanf(SampleDefFile,"%255s",dummy);   
00682   } while (strcasecmp(dummy, "NUMBER_OF_FOILS"));  
00683   
00684   fscanf(SampleDefFile, "%d", NFoil);
00685   
00686   /*Initialize  Sample*/
00687   //if(*Sample!=NULL)free(*Sample);
00688   *Sample=(foil*)malloc((*NFoil)*sizeof(foil));
00689   if (*Sample==NULL){fprintf(stderr,"\n Error allocating memory (Sample)\n");exit(1);}
00690   
00691   for (*MaxZ=0,i = 0; i < *NFoil ; i++) {
00692     pfoil=&((*Sample)[i]);
00693     do {
00694       fscanf(SampleDefFile,"%255s",dummy);   
00695       } while (strcasecmp(dummy, "FOIL"));  
00696     
00697     fscanf(SampleDefFile, "%lg %10s", &pfoil->thick, dummy);
00698     if(strcasecmp(dummy,"cm2") && strcasecmp(dummy,"mg")){
00699       fprintf(stderr,"\n Error: Bad syntax in sample definition file: '%s' is not a known thickness unit\n",dummy);exit(1);
00700     }
00701     fscanf(SampleDefFile, "%d",  &pfoil->nfoilelm);
00702     tempZ=readCOMPOUND(SampleDefFile, pfoil->nfoilelm, &pfoil->comp);
00703     if(tempZ>*MaxZ) *MaxZ=tempZ;
00704     
00705     if(!strcasecmp(dummy,"mg")){
00706       /*Convert the value in pfoil->thick from mg/cm2 to 1e15at/cm2 */
00707       for(natmass=0, j=0 ; j<pfoil->nfoilelm ; j++) natmass += pfoil->comp.xn[j] * pfoil->comp.elem[j].M;
00708       ug2at=natmass/602.2141; // (Pm [g/mol] *1e6 [ug/g] / (Navo [at/mol])) * 1e15  
00709                               // ==> ug2at is in [ug/1e15at]
00710       pfoil->thick *= (1e3/ug2at);  //Before this, thick was in mg/cm2, hence multiply by 1e3 to get ug/cm2 
00711                                      //and then divide by ug2at to get 1e15at/cm2
00712     }
00713     
00714   }
00715   fclose(SampleDefFile);
00716  
00717   return(0);
00718 }
00719 
00720 /**Creates an array of integer flags indicating whether an element
00721  * is present in the sample (1) or not (0). 
00722  * The dimension of the array is that of the maximum atomic number present in the sample. 
00723  * For example, if the sample contains only C and Si, the array will be:
00724  * PresentElems[6]= PresentElems[14]=1 (and all the other=0)
00725  * 
00726  * @param MaxZ (I) Largest atomic number present in sample (Dimension of PresentElems).
00727  * @param NFoil (I) Number of target foils
00728  * @param MatArray (I) Array of foils defining the current sample
00729  * @param PresentElems (O) Pointer to array of flags indicating presence for each element
00730  * @return Always 0
00731  */
00732 int createPresentElems(int MaxZ, int NFoil, const foil *MatArray, int **PresentElems)
00733 {  
00734   const COMPOUND *pcmp;
00735   int tempZ;
00736   int i,j;
00737   
00738   /*Initialize and fill the PresentElems Array (it is calloc'ed so by default contains 0's*/
00739   *PresentElems=(int*)calloc((MaxZ+1),sizeof(int));
00740   if (*PresentElems==NULL){fprintf(stderr,"\n Error allocating memory (PresentElems)\n");exit(1);}
00741   for(i=0;i<NFoil; i++) {
00742     pcmp=&MatArray[i].comp;
00743     for(j=0 ; j< pcmp->nelem ; j++)  {
00744       tempZ=pcmp->elem[j].Z;
00745       if(tempZ<=MaxZ) (*PresentElems)[tempZ]=1;
00746       else {fprintf(stderr,"\n ERROR: in createPresentElems(): %d > MaxZ (=%d)\n",tempZ,MaxZ);exit(1);}
00747     }
00748   }
00749   return(0);
00750 }
00751 
00752 
00753 /**Reads files containing the Calculation Flags (i.e. which lines should be calculated) or,
00754  *alternativelly reads areas files from a file in the DATTPIXE Areas format. The behaviour
00755  * depends on the DTAreasFlag (see below)
00756  * 
00757  * The Format of the file is as follows:
00758       -----------------
00759       (any header)
00760       DATA 
00761       (datablocks)
00762       -----------------
00763       
00764   if AreasFormat=1, The datablock for each element has the following structure:
00765     
00766     [ChemSymb] 
00767     [Kalpha1,2]  [Kbeta1]   [Kbeta2]  
00768     [Lalpha1,2]  [Lbeta2]   [Ll]  
00769     [Lbeta1]     [Lgamma1]  [Leta] 
00770     [Lbeta3]     [Lbeta4]   [Lgamma3]
00771     [Malpha1,2]  [Mbeta]    [Mgamma]
00772  
00773  Note: the flags are: 0 if not to be calculated, 1 (or >1) if should be calculated
00774  
00775  If AreasFormat=2 the datablock format is:
00776     [ChemSymb] 
00777     [Kalpha1,2]  [err]  [Kbeta1]  [err]  [Kbeta2]  [err]
00778     [Lalpha1,2]  [err]  [Lbeta2]  [err]  [Ll]      [err]  
00779     [Lbeta1]     [err]  [Lgamma1] [err]  [Leta]    [err] 
00780     [Lbeta3]     [err]  [Lbeta4]  [err]  [Lgamma3] [err]
00781     [Malpha1,2]  [err]  [Mbeta]   [err]  [Mgamma]  [err]
00782  *
00783  * Note: The information for elements not present in the sample is just ignored.
00784  *
00785  * @param CalcFlagsFileNm (I) Name of the input file
00786  * @param PresentElems (I) Array of flags indicating presence for each element. See createPresentElems()
00787  * @param MaxZinsample (I) Largest atomic number present in sample (dimension of PresentElems).
00788  * @param AreasFormat (I) Defines the format of the Areas File. 1 for raw areas format, 2 for DATTPIXE Areas Format
00789  * @param CalcFlags (O) Array (dimension is allocated to MaxZinsample+1) of structures containing the flags.
00790  * @return Always 0
00791  */
00792 int readCalcFlags(const char *CalcFlagsFileNm, const int *PresentElems, int MaxZinsample, int AreasFormat,  CPIXERESULTS **CalcFlags){
00793   
00794   int i,j,tempZ,nread=0;
00795   char dummy[LONGSTRINGLENGTH];
00796   double trash;
00797   ChemSymb tempchem;
00798   CPIXERESULTS *pCFlags;
00799   FILE *CalcFlagsFile;
00800   /*Open File*/
00801   CalcFlagsFile = fopen(CalcFlagsFileNm, "r");
00802   if (CalcFlagsFile== NULL)
00803     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",CalcFlagsFileNm);exit(1);}
00804   
00805   /*Initialize CalcFlags */
00806   *CalcFlags=(CPIXERESULTS*)calloc(MaxZinsample+1,sizeof(CPIXERESULTS));
00807   if (*CalcFlags==NULL){fprintf(stderr,"\n Error allocating memory (CalcFlags)\n");exit(1);}
00808   
00809   /*Initialize the atnums of the present elems (to prevent crashes afterwards) */
00810   for(i=0;i<=MaxZinsample;i++)if(PresentElems[i])(*CalcFlags)[i].atnum=i;
00811     
00812   do {
00813     fscanf(CalcFlagsFile,"%255s",dummy);   
00814     if(feof(CalcFlagsFile)) {fprintf(stderr,"\nERROR: 'DATA' not found in '%s'\n",CalcFlagsFileNm);exit(1);}
00815   } while (strcasecmp(dummy, "DATA"));
00816  
00817   /*Read Data blocks*/
00818   for(;!feof(CalcFlagsFile);){
00819     fscanf(CalcFlagsFile,"%255s",dummy);
00820     
00821     if( (!strcmp(dummy,"END_DATA") && AreasFormat==1) || (AreasFormat==2 && !strcmp(dummy,"CALIB" )) ) {
00822       break;
00823     }
00824     /*
00825     else if(!strcmp(dummy,"INCLUDE")){
00826       fscanf(CalcFlagsFileNm,"%3s",tempchem);
00827     }
00828     */
00829     
00830     
00831     //If the reading continues, "dummy" contains either a chem. symbol or a Z value  
00832     if(AreasFormat==1){
00833       strncpy(tempchem,dummy,3);
00834       tempZ = symbol2Z(tempchem);
00835     }
00836     else if (AreasFormat==2){
00837       strncpy(tempchem,"-",3);
00838       tempZ = atoi(dummy);
00839     }
00840     else tempZ=0;
00841     
00842     if(tempZ<=MaxZinsample && PresentElems[tempZ]){
00843       nread++;
00844 
00845       pCFlags=&(*CalcFlags)[tempZ];
00846       pCFlags->atnum=tempZ;
00847       
00848       /*Read K-lines*/
00849       for(i=1;i<=3;i++) {
00850         fscanf(CalcFlagsFile, "%lg", &pCFlags->simareas.K_[i]);
00851         if(AreasFormat==2)fscanf(CalcFlagsFile, "%lg", &pCFlags->err.K_[i]);
00852       }
00853       /*Read L-lines*/
00854       for(i=1;i<=3;i++){
00855         for(j=1;j<=3;j++){
00856           fscanf(CalcFlagsFile, "%lg", &pCFlags->simareas.L_[i][j]);
00857           if(AreasFormat==2)fscanf(CalcFlagsFile, "%lg", &pCFlags->err.L_[i][j]);
00858         }
00859       }
00860       /*read M-lines*/
00861       for(i=1;i<=3;i++) {
00862         fscanf(CalcFlagsFile, "%lg", &pCFlags->simareas.M_[i]);
00863         if(AreasFormat==2)fscanf(CalcFlagsFile, "%lg", &pCFlags->err.M_[i]);
00864       }
00865       #if CPIXEVERBOSITY > 0  
00866       printf("\n CalcFlags[%2d] (%2s) read", pCFlags->atnum,tempchem);
00867       #endif
00868     }
00869     else {
00870       for(i=0;i<15;i++)fscanf(CalcFlagsFile, "%lg",&trash);//just discard the 3+9+3 following numbers
00871       if(AreasFormat==2)for(i=0;i<15;i++)fscanf(CalcFlagsFile, "%lg",&trash); //plus 15 more if err are present
00872       #if CPIXEVERBOSITY > 0  
00873       printf("\n Warning: Element '%s' ignored (not present in sample).",tempchem);
00874       #endif
00875     }
00876   }
00877   fclose(CalcFlagsFile);
00878   //Do some checks on the read data
00879   if(AreasFormat==2 && strcmp(dummy,"CALIB")) 
00880     {fprintf(stderr,"\nERROR: Bad DT format in '%s'\n",CalcFlagsFileNm);exit(1);}
00881   if(AreasFormat==1 && strcmp(dummy,"END_DATA"))
00882     {fprintf(stderr,"\nERROR: 'END_DATA' not found in '%s'\n",CalcFlagsFileNm);exit(1);}
00883   if(nread==0){fprintf(stderr,"\nERROR: '%s' contained no valid data\n",CalcFlagsFileNm);exit(1);}
00884   
00885   return(0);
00886 }
00887 
00888 
00889 /**Reads from an ascii file the calibration yields and also returns CalEner.
00890     @todo Modify to read only the present elems.
00891     
00892     Note: the index of XYldArray starts in 1.
00893     The File must have the following format:
00894       -----------------
00895       (any header)
00896       CALENER [calener]
00897       MAXZ [maxZ]
00898       
00899       DATA 
00900       (datablocks)
00901       -----------------
00902       
00903    The datablock for each element has the following structure:
00904     
00905     [AtNum]     [ChemSymb] 
00906     
00907     [Kalpha1,2]  [Kbeta1]   [Kbeta2]   <----Energies
00908     [Kalpha1,2]  [Kbeta1]   [Kbeta2]   <----Yields 
00909     
00910     [Lalpha1,2]  [Lbeta2]   [Ll]  <---------Energies      
00911     [Lalpha1,2]  [Lbeta2]   [Ll]  <---------Yields      
00912     [Lbeta1]     [Lgamma1]  [Leta] <--------Energies     
00913     [Lbeta1]     [Lgamma1]  [Leta] <--------Yields     
00914     [Lbeta3]     [Lbeta4]   [Lgamma3]  <----Energies
00915     [Lbeta3]     [Lbeta4]   [Lgamma3]  <----Yields
00916     
00917     [Malpha1,2]  [Mbeta]    [Mgamma]  <-----Energies  
00918     [Malpha1,2]  [Mbeta]    [Mgamma]  <-----Yields  
00919 
00920   
00921   -----------------
00922 
00923  * 
00924  * @param XYldFileNm (I) Name of the file to be read.
00925  * @param PresentElems (I) Array of flags indicating presence for each element. See createPresentElems()
00926  * @param CalcFlags (I) array of structures indicating which lines are to be calculated (simareas values>0) and which not (simareas values=-1). See readCalcFlags()
00927  * @param MaxZinsample (I) Largest atomic number present in sample (dimension of PresentElems).
00928  * @param CalEner (O) Energy at which the calibration was performed
00929  * @param XYldArray (O) Pointer to array of structs containing the efficiencies for each element
00930  * @return Always 0
00931  *
00932  * NOTE that the calib yield files from DT are in (cm2/ug)/uC  and should be passed to (cm2/1e15at)/uC
00933  */
00934 int readXYld(const char *XYldFileNm, const int *PresentElems, const CPIXERESULTS *CalcFlags, int MaxZinsample, double *CalEner, XrayYield **XYldArray)
00935 {
00936   FILE *XYldFile;
00937   char dummy[LONGSTRINGLENGTH];
00938   int maxZ;
00939   XrayYield *pXYld;
00940   int i,j,tempZ,result,iel;
00941   ChemSymb tempchem;
00942   double natmass,ug2at, trash;
00943   const CalibYld *pFlag;
00944   int atomicunits=0;
00945   
00946   XYldFile = fopen(XYldFileNm, "r");
00947   if (XYldFile == NULL)
00948     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",XYldFileNm);exit(1);}
00949     
00950   do {
00951     fscanf(XYldFile,"%255s",dummy);   
00952     if(feof(XYldFile)) {fprintf(stderr,"\nERROR: 'CALENER' not found in '%s'\n",XYldFileNm);exit(1);}
00953   } while (strcasecmp(dummy, "CALENER"));
00954   
00955   fscanf(XYldFile, "%lf", CalEner);
00956   
00957   do {
00958     fscanf(XYldFile,"%255s",dummy);   
00959     if(feof(XYldFile)) {fprintf(stderr,"\nERROR: 'MAXZ' not found in '%s'\n",XYldFileNm);exit(1);}
00960   } while (strcasecmp(dummy, "MAXZ"));
00961   
00962   fscanf(XYldFile, "%d", &maxZ);
00963   if(MaxZinsample>maxZ){fprintf(stderr,"\nERROR: Calib. file '%s' maxZ=%d<%d\n",XYldFileNm,maxZ,MaxZinsample);exit(1);}
00964   
00965   /*Initialize XYldArray */
00966   *XYldArray=(XrayYield*)calloc(MaxZinsample+1,sizeof(XrayYield));
00967   if (*XYldArray==NULL){fprintf(stderr,"\n Error allocating memory (XYldArray)\n");exit(1);}
00968   
00969   do {
00970     fscanf(XYldFile,"%255s",dummy);   
00971     if(feof(XYldFile)) {fprintf(stderr,"\nERROR: 'UNITS' not found in '%s'\n",XYldFileNm);exit(1);}
00972   } while (strcasecmp(dummy, "UNITS"));
00973   
00974   fscanf(XYldFile, "%255s",dummy);
00975   if(!strcasecmp(dummy, "atom"))atomicunits=1;
00976   else if(!strcasecmp(dummy, "mass"))atomicunits=0;
00977   else {fprintf(stderr,"\nERROR: unknown UNITS ('%s') in '%s'. Valid values are 'atom' or mass'\n",dummy,XYldFileNm);exit(1);}
00978   
00979   do {
00980     fscanf(XYldFile,"%255s",dummy);
00981     if(feof(XYldFile)) {fprintf(stderr,"\nERROR: 'DATA' not found in '%s'\n",XYldFileNm);exit(1);}
00982   } while (strcasecmp(dummy, "DATA"));
00983   
00984   /*Read Data blocks*/
00985   for(result=0,tempZ=0;!feof(XYldFile) && tempZ!=MaxZinsample;){
00986     fscanf(XYldFile, "%d", &tempZ);
00987     if(tempZ<1 || tempZ>MaxZinsample || (*XYldArray)[tempZ].atnum != 0){
00988       fprintf(stderr,"\nERROR: Bad format in Calib. file '%s' (Z=%d)\n",XYldFileNm,tempZ);
00989       exit(1);
00990     }
00991     fscanf(XYldFile,"%3s",tempchem);
00992     if(tempZ != symbol2Z(tempchem)){
00993       fprintf(stderr,"\nERROR: Bad format in Calib. file '%s' (Z=%d)\n",XYldFileNm,tempZ);
00994       exit(1);
00995     }
00996     if(PresentElems[tempZ]){
00997       result++;
00998       pXYld=&(*XYldArray)[tempZ];
00999       pXYld->atnum=tempZ;
01000       strcpy(pXYld->symb, tempchem);
01001       for(iel=0;CalcFlags[iel].atnum!=tempZ;iel++){} //findout the iel corresponding to tempZ
01002       
01003       pFlag=&CalcFlags[iel].simareas;
01004       
01005       if(!atomicunits){
01006         Z2mass(tempZ, &natmass,'n');
01007         ug2at=natmass/602.2141; // (Pm [g/mol] *1e6 [ug/g] / (Navo [at/mol])) * 1e15  
01008                                 // ==> ug2at is in [ug/1e15at]
01009       }
01010       else ug2at=1; //If Units are already atomic, the conversion shouldn't be done
01011       
01012       /*Read K-lines*/
01013       for(i=1;i<=3;i++) fscanf(XYldFile, "%lg", &pXYld->ener.K_[i]);
01014       for(i=1;i<=3;i++) {
01015         fscanf(XYldFile, "%lg", &pXYld->XYld.K_[i]);
01016         pXYld->XYld.K_[i]*=ug2at;  // ug2at is in [ug/1e15at]
01017         //If the line is not to be used, put it at 0
01018         if(!(int)pFlag->K_[i]){ pXYld->XYld.K_[i]=0. ; pXYld->ener.K_[i]=0.;} 
01019       }
01020       /*Read L-lines*/
01021       for(i=1;i<=3;i++){
01022         for(j=1;j<=3;j++){
01023           fscanf(XYldFile, "%lg", &pXYld->ener.L_[i][j]);
01024         }
01025         for(j=1;j<=3;j++){
01026           fscanf(XYldFile, "%lg", &pXYld->XYld.L_[i][j]);
01027           pXYld->XYld.L_[i][j]*=ug2at;
01028           if(!(int)pFlag->L_[i][j]){ pXYld->XYld.L_[i][j]=0. ; pXYld->ener.L_[i][j]=0.;}
01029         }
01030       }
01031     
01032       /*read M-lines*/
01033       for(i=1;i<=3;i++) fscanf(XYldFile, "%lg", &pXYld->ener.M_[i]);
01034       for(i=1;i<=3;i++) {
01035         fscanf(XYldFile, "%lg", &pXYld->XYld.M_[i]);
01036         pXYld->XYld.M_[i]*=ug2at;
01037         if(!(int)pFlag->M_[i]){ pXYld->XYld.M_[i]=0. ; pXYld->ener.M_[i]=0.;}
01038       }
01039       #if CPIXEVERBOSITY > 0  
01040       printf("\n XyldArray[%2d] (%2s) read", pXYld->atnum,tempchem);
01041       #endif
01042     }
01043     else for(i=0;i<30;i++)fscanf(XYldFile, "%lg",&trash);//just discard the 3*2+9*2+3*2 following numbers
01044   }
01045   fclose(XYldFile);
01046   
01047   return(result);
01048 }
01049 
01050 
01051 /**Reads from an ascii file the Fluorescence and Coster-Kronig coefficients.
01052  Note: the index of FCKCoefArray starts in 1.
01053  @todo Modify to read only the present elems.
01054  
01055  The File must have the following format:
01056  
01057   -----------------
01058   (any header)
01059   
01060   MAXZ [maxZ]
01061   
01062   DATA 
01063   (datablocks)
01064   -----------------
01065   
01066   The datablock for each element has the following structure:
01067   
01068   
01069   [atnum]  [chemsymb]
01070   
01071   (Fluorescence Coeficients)
01072   [K] [LI] [LII] [LIII] [MI]... @todo Substitute the "..." by explicit labels
01073   
01074   [f12] [f13] [f23]
01075   
01076   (Line fractions for:) 
01077   [Kalpha1,2]  [Kbeta1]   [Kbeta2]   
01078   [Lalpha1,2]  [Lbeta2]   [Ll]        
01079   [Lbeta1]     [Lgamma1]  [Leta]      
01080   [Lbeta3]     [Lbeta4]   [Lgamma3]  
01081   [Malpha1,2]  [Mbeta]    [Mgamma]    
01082 
01083 
01084   -----------------
01085  
01086  * 
01087  * @param FCKCoefFileNm (I) Name of the file to be read.
01088  * @param MaxZinsample (I) Largest atomic number present in sample.
01089  * @param FCKCoefArray (O) Pointer to array of structs containing Fluorescence and C-K Coefs
01090  * @return Always 0
01091  */
01092 int readFCK(char *FCKCoefFileNm, int MaxZinsample, FluorCKCoef **FCKCoefArray)
01093 {
01094   FILE *FCKCoefFile;
01095   char dummy[LONGSTRINGLENGTH];
01096   int maxZ;
01097   FluorCKCoef *pFCKCoef;
01098   int i,tempZ;
01099   ChemSymb tempchem;
01100  
01101   maxZ=0;
01102   FCKCoefFile= fopen(FCKCoefFileNm, "r");
01103   if (FCKCoefFile == NULL)
01104     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",FCKCoefFileNm);exit(1);}
01105   
01106   do {
01107   fscanf(FCKCoefFile,"%255s",dummy);
01108   if(feof(FCKCoefFile)) {fprintf(stderr,"\nERROR: 'MAXZ' not found in '%s'\n",FCKCoefFileNm);exit(1);}
01109   } while (strcasecmp(dummy, "MAXZ"));
01110   
01111   fscanf(FCKCoefFile, "%d", &maxZ);
01112   if(MaxZinsample>maxZ){fprintf(stderr,"\nERROR: FCK file '%s' maxZ=%d<%d\n",FCKCoefFileNm,maxZ,MaxZinsample);exit(1);}
01113   
01114   /*Initialize FCKCoefArray*/
01115   *FCKCoefArray=(FluorCKCoef*)calloc(MaxZinsample+1,sizeof(FluorCKCoef));
01116   if (*FCKCoefArray==NULL){fprintf(stderr,"\n Error allocating memory (FCKCoefArray)\n");exit(1);}
01117   
01118   do {
01119   fscanf(FCKCoefFile,"%255s",dummy);   
01120   if(feof(FCKCoefFile)) {fprintf(stderr,"\nERROR: 'DATA' not found in '%s'\n",FCKCoefFileNm);exit(1);}
01121   } while (strcasecmp(dummy, "DATA"));
01122   
01123   /*Read Data blocks*/
01124   for(tempZ=0;!feof(FCKCoefFile) && tempZ!=MaxZinsample;){
01125     fscanf(FCKCoefFile, "%d", &tempZ);
01126     if(tempZ<1 || tempZ>MaxZinsample || (*FCKCoefArray)[tempZ].atnum != 0){
01127       fprintf(stderr,"\nERROR: Bad format in FCKCoef file '%s' (Z=%d)\n",FCKCoefFileNm,tempZ);
01128       exit(1);
01129     }
01130     fscanf(FCKCoefFile,"%3s",tempchem);
01131     if(tempZ != symbol2Z(tempchem)){
01132       fprintf(stderr,"\nERROR: Bad format in FCKCoef file '%s' (Z=%d)\n",FCKCoefFileNm,tempZ);
01133       exit(1);
01134     }
01135     pFCKCoef=&(*FCKCoefArray)[tempZ];
01136     pFCKCoef->atnum=tempZ;
01137     
01138     /*Read Fluorescence coeffs*/
01139     for (i = 1; i <= 9; i++) fscanf(FCKCoefFile, "%lg", &pFCKCoef->w[i]);
01140     
01141     /*Read f12,f13,f23 coeffs (Coster-Kronig)*/
01142     fscanf(FCKCoefFile, "%lg%lg%lg", &pFCKCoef->ck[0], &pFCKCoef->ck[1], &pFCKCoef->ck[2]);
01143     
01144     /*Read Line fractions*/
01145     fscanf(FCKCoefFile, "%lg%lg%lg", &pFCKCoef->k.K_[1], &pFCKCoef->k.K_[2], &pFCKCoef->k.K_[3]);
01146     for (i = 1; i <= 3; i++) fscanf(FCKCoefFile, "%lg%lg%lg", &pFCKCoef->k.L_[i][1], &pFCKCoef->k.L_[i][2], &pFCKCoef->k.L_[i][3]);
01147     fscanf(FCKCoefFile, "%lg%lg%lg", &pFCKCoef->k.M_[1], &pFCKCoef->k.M_[2], &pFCKCoef->k.M_[3]);
01148    
01149 //     printf("\n DEBUG: FCKCoef[%2d] (%2s) read", pFCKCoef->atnum,tempchem);
01150   }
01151   fclose(FCKCoefFile);
01152   return(0);
01153 }
01154 
01155 
01156 
01157 /**Reads from an ascii file the X-ray Absorption coefficients.
01158  The File must have the following format:
01159  Note: the index of TotAbsCoefArray starts in 1.
01160  
01161   -----------------
01162   (any header)
01163   
01164   MAXZ [maxZ]
01165   
01166   DATA 
01167   (datablocks)
01168   -----------------
01169   
01170   The datablock for each element has the following structure:
01171   
01172   [atnum]  [chemsymb]
01173   
01174   (23 coefs each one for a given standard energy (see stdtable in TotAbsor() ) 
01175   [stdcoef[0]]....[stdcoef[22]]
01176   
01177   (9 triplets --1 for K, 3 for L and 5 for M-- describing absorp edges for K, L & M (1+3+5 triplets). First member of triplet is the transition ener, 2nd is abs coef for E below E_edge and 3rd is  abs coef for E above E_edge )
01178   [enr[1]] [coefenr[0][0]] [coefenr[0][1]]
01179   ...
01180   [enr[9]] [coefenr[8][0]] [coefenr[8][1]]
01181   
01182   -----------------
01183     
01184   @todo Note that enr indexing starts in 1 while the stdcoeffs & coefenr start in 0. A conversion from 1-->0 could be done with little work.
01185   
01186   IMPORTANT: The Absorption coeffs are tabulated using cm2/mg as unit but they need to be converted to 
01187              (cm2/1e15at) 
01188  
01189  * 
01190  * @param TotAbsCoefFileNm (I) Name of the file to be read. Coefs are expected in (cm2/mg)
01191  * @param MaxZinsample (I) Largest atomic number present in sample.
01192  * @param PresentElems (I) Array of flags indicating presence for each element. See createPresentElems()
01193  * @param Filter (I) Pointer to filter structure.
01194  * @param TotAbsCoefArray (O) Pointer to array of structs containing the Absorption Coefs (in cm2/1e15at ) (see readAbsCoef() ) 
01195  * @return  Always 0
01196  */
01197 int readAbsCoef(char *TotAbsCoefFileNm, int MaxZinsample, const int *PresentElems, const FILTER *Filter, AbsCoef **TotAbsCoefArray)
01198 {
01199   FILE *TotAbsCoefFile;
01200   char dummy[LONGSTRINGLENGTH];
01201   int maxZ;
01202   AbsCoef *pTotAbsCoef;
01203   int i,tempZ;
01204   ChemSymb tempchem;
01205   double trash, natmass;
01206   double mg2at; //conversion factor from cm2/mg to cm2/(1e15at) , which depends on the mass. 
01207    
01208   TotAbsCoefFile= fopen(TotAbsCoefFileNm, "r");
01209   if (TotAbsCoefFile == NULL)
01210     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",TotAbsCoefFileNm);exit(1);}
01211   
01212   do {
01213   fscanf(TotAbsCoefFile,"%255s",dummy);
01214   if(feof(TotAbsCoefFile)) {fprintf(stderr,"\nERROR: 'MAXZ' not found in '%s'\n",TotAbsCoefFileNm);exit(1);}
01215   } while (strcasecmp(dummy, "MAXZ"));
01216   
01217   fscanf(TotAbsCoefFile, "%d", &maxZ);
01218   if(MaxZinsample>maxZ){fprintf(stderr,"\nERROR: X-Absorption file '%s' maxZ=%d<%d\n",TotAbsCoefFileNm,maxZ,MaxZinsample);exit(1);}
01219   
01220   /*Initialize TotAbsCoefArray*/
01221   *TotAbsCoefArray=(AbsCoef*)calloc(MaxZinsample+1,sizeof(AbsCoef));
01222   if (*TotAbsCoefArray==NULL){fprintf(stderr,"\n Error allocating memory (TotAbsCoefArray)\n");exit(1);}
01223   
01224   do {
01225   fscanf(TotAbsCoefFile,"%255s",dummy);   
01226   if(feof(TotAbsCoefFile)) {fprintf(stderr,"\nERROR: 'DATA' not found in '%s'\n",TotAbsCoefFileNm);exit(1);}
01227   } while (strcasecmp(dummy, "DATA"));
01228   
01229   /*Read Data blocks*/
01230   for(tempZ=0;!feof(TotAbsCoefFile) && tempZ!=MaxZinsample;){
01231     fscanf(TotAbsCoefFile, "%d", &tempZ);
01232     if(tempZ<1 || tempZ>MaxZinsample || (*TotAbsCoefArray)[tempZ].atnum != 0){
01233       fprintf(stderr,"\nERROR: Bad format in X-Absorption file '%s' (Z=%d)\n",TotAbsCoefFileNm,tempZ);
01234       exit(1);
01235     }
01236     fscanf(TotAbsCoefFile,"%3s",tempchem);
01237     if(tempZ != symbol2Z(tempchem)){
01238       fprintf(stderr,"\nERROR: Bad format in X-Absorption file '%s' (Z=%d)\n",TotAbsCoefFileNm,tempZ);
01239       exit(1);
01240     }
01241     if(PresentElems[tempZ] || ( tempZ<=Filter->MaxZ && Filter->FilterElems[tempZ] ) ){
01242       pTotAbsCoef=&(*TotAbsCoefArray)[tempZ];
01243       pTotAbsCoef->atnum=tempZ;
01244       
01245       Z2mass(tempZ, &natmass,'n');
01246       mg2at=natmass/602214.1; // (Pm [g/mol] *1e3 [mg/g] / (Navo [at/mol])) * 1e15  
01247                               // ==> mg2at is in [mg/1e15at]
01248       
01249       for (i = 0; i < 23; i++){
01250         fscanf(TotAbsCoefFile, "%lg", &pTotAbsCoef->coefstd[i]);
01251         /*Transform: from cm2/mg to cm2/(1e15at)*/
01252         pTotAbsCoef->coefstd[i]*=mg2at;
01253       }
01254       for (i = 1; i <= 9; i++){
01255         fscanf(TotAbsCoefFile, "%lg%lg%lg", &pTotAbsCoef->enr[i], &pTotAbsCoef->coefenr[i-1][0],&pTotAbsCoef->coefenr[i-1][1]);
01256         /*Transform: from cm2/mg to cm2/(1e15at)*/
01257          pTotAbsCoef->coefenr[i-1][0]*=mg2at;
01258          pTotAbsCoef->coefenr[i-1][1]*=mg2at;
01259       }
01260       #if CPIXEVERBOSITY > 0
01261       printf("\n TotAbsCoef[%2d] (%2s) read", pTotAbsCoef->atnum,tempchem);
01262       #endif
01263     }
01264     else for (i = 0; i < 50; i++) fscanf(TotAbsCoefFile, "%lg", &trash); //just discard the 23+9*3 following numbers
01265   }
01266   fclose(TotAbsCoefFile);
01267   return(0);
01268 }
01269 
01270 
01271 
01272 /**Generates the stopping force tables 
01273  * Returns an array of pointers referencing to one table for each element present
01274  * in sample)
01275  * 
01276  * IMPORTANT: The tables are generated in the following units: keV/(1e15at/cm2) !!!
01277  *
01278  * @param path (I) String containing the path to look for the data base files.
01279  *              (e.g. for SCOEF.95A and SCOEF95B in the case of ZBL96 stoppings)
01280  *               Note that the path MUST contain the last "directory separator" 
01281  * @param pexp (I) Pointer to structure containing experimental parameters.
01282  * @param MaxZinsample (I) Largest atomic number present in sample.
01283  * @param PresentElems (I) Array of flags indicating presence for each element. See createPresentElems()
01284  * @param step (I) Energy step to be used (in keV) in the case of linear energy scale
01285  *             or the multiplicative factor in the case logarithmic energy scale.
01286  * @param SPTArray (O) Array of Stopping power table structs for each present element. 
01287  *                 IMPORTANT: The tables are generated in the following units: keV/(1e15at/cm2) !!!
01288  * @return Always 0
01289  */
01290 int createSPTs(const char *path, const EXP_PARAM *pexp, int MaxZinsample, const int *PresentElems, double step, SPT **SPTArray)
01291 {
01292   int Z,j;
01293   SPT *pSPT;
01294   double E;
01295   double *nucSP;
01296   char afilename[FILENMLENGTH], bfilename[FILENMLENGTH];  
01297   /**@todo readstopcoef assumes that the files SCOEF.95A and SCOEF.95B are located where the program is called. This must be generalized (In fact, the coefficients could be hardcoded using an include file)*/
01298   snprintf(afilename,FILENMLENGTH,"%sSCOEF.95A",path);
01299   snprintf(bfilename,FILENMLENGTH,"%sSCOEF.95B",path);
01300   readstopcoef(afilename, bfilename);
01301   
01302   /*Initialize SPTables*/
01303   /*Calloc is used, so all the non-explicitely initialized, remain 0/NULL */
01304   *SPTArray=(SPT*)calloc(MaxZinsample+1,sizeof(SPT));
01305   if (*SPTArray==NULL){fprintf(stderr,"\n Error allocating memory (SPTArray)\n");exit(1);}
01306   
01307   for(Z=1; Z<=MaxZinsample ;Z++){
01308     if(PresentElems[Z]){
01309       pSPT=&(*SPTArray)[Z];
01310       
01311       pSPT->Emax=1.1*pexp->BeamEner;
01312       pSPT->Estep=step;  
01313       pSPT->logmode=0;  ///<For the moment, only linear Energy scale is implemented
01314       pSPT->nrows=1+(int)ceil(pSPT->Emax/pSPT->Estep);
01315       
01316       /*Initialize the arrays*/
01317       pSPT->E=(double*)malloc(pSPT->nrows*sizeof(double));
01318       if (pSPT->E==NULL){fprintf(stderr,"\n Error allocating memory (SPTArray[%d].E)\n",Z);exit(1);}
01319       pSPT->S=(double*)malloc(pSPT->nrows*sizeof(double));
01320       if (pSPT->S==NULL){fprintf(stderr,"\n Error allocating memory (SPTArray[%d].S)\n",Z);exit(1);}
01321       pSPT->dSdE=(double*)malloc(pSPT->nrows*sizeof(double));
01322       if (pSPT->dSdE==NULL){fprintf(stderr,"\n Error allocating memory (SPTArray[%d].dSdE)\n",Z);exit(1);}
01323       
01324       nucSP=(double*)malloc(pSPT->nrows*sizeof(double));
01325       if (nucSP==NULL){fprintf(stderr,"\n Error allocating memory (nucSP)\n");exit(1);}
01326       
01327       for(j=0 ,E=0; j< pSPT->nrows ; j++, E+=step)pSPT->E[j]=E;
01328       
01329       stop96d(pexp->ion.Z, Z, pexp->ion.IM,  pSPT->E, pSPT->nrows, pSPT->S);
01330       nuclearstopping_ZBL(pexp->ion.Z, Z, pexp->ion.IM, (double)(-1.), pSPT->E, pSPT->nrows, nucSP);
01331       
01332       for(pSPT->Smax=0., j=0 ; j< pSPT->nrows ; j++){
01333         pSPT->S[j] += nucSP[j];
01334         pSPT->S[j] *=0.001; //Return stopping in keV/(1e15at/cm2)
01335         if(pSPT->Smax < pSPT->S[j]) pSPT->Smax = pSPT->S[j];  //obtain the maximum of S
01336       }
01337       for(j=0 ; j< pSPT->nrows-1 ; j++){
01338       pSPT->dSdE[j]=(pSPT->S[j+1] - pSPT->S[j])/(pSPT->E[j+1] - pSPT->E[j]);
01339       }
01340       pSPT->dSdE[pSPT->nrows-1]=pSPT->dSdE[pSPT->nrows -2];
01341       
01342       free(nucSP);
01343       #if CPIXEVERBOSITY > 0
01344       printf("\n Created SP table for Z=%2d (%d rows)",Z,pSPT->nrows);
01345       #endif
01346     }
01347   }
01348   
01349   return(0);
01350 }
01351 
01352 
01353 /**Returns stopping Using previously calculated tables.
01354  * Performs a linear interpolation and a Bragg adition.
01355  * 
01356  * @param pcmp (I) Pointer to target definition
01357  * @param SPTArray (I) Pointer to precalculated tables of stoppings (see createSPT() )
01358  * @param E (I) Energy of the ion, in keV
01359  * @return Stopping Power, in keV/(1e15at/cm2)  IMPORTANT!!! note that it's keV and ot eV
01360  */
01361 double getSP(const COMPOUND *pcmp, const SPT *SPTArray, double E)
01362 {
01363   int i,j;
01364   double SP;
01365   const SPT *pspt;
01366   
01367   /*For each element in the compound, obtain the stopping power from its table and apply bragg rule*/
01368   for(SP=0, i=0 ; i< pcmp->nelem ; i++){
01369     pspt= &SPTArray[pcmp->elem[i].Z];
01370     j=(int)floor(E / pspt->Estep);  // j is the index in the table (index of nearest lower tabulated energy)
01371     SP+= (pspt->S[j] + pspt->dSdE[j]*(E - pspt->E[j]) )* pcmp->xn[i];    //linear interpolation + Bragg rule
01372   }
01373   return (SP);
01374 }
01375 
01376 
01377 
01378 /**Initializes the lyr array 
01379  * 
01380  * @param pexp (I) Pointer to structure containing experimental parameters.
01381  * @param MatArray (I) Array of foils defining the current sample
01382  * @param XYldArray (I) Array of Xray yield coefs. See readXYld()
01383  * @param TotAbsCoefArray (I) Array containing a tables of Absorption Coefs (see readAbsCoef() )
01384  * @param SPTArray (I) Pointer to precalculated tables of stoppings (see createSPT() )
01385  * @param NFoil (I) Number of target foils
01386  * @param PresentElems (O) Pointer to array of flags indicating presence for each element
01387  * @param NFoilUsed (O) Number of foils finally used in the calcs 
01388  * @param plyrarray (O) Pointer to the layer array.
01389  * @return Always 0
01390  */
01391 int initlyrarray(const EXP_PARAM *pexp, const foil *MatArray, const XrayYield *XYldArray, const AbsCoef *TotAbsCoefArray, const SPT *SPTArray, const int *PresentElems, int NFoil, int *NFoilUsed, LYR **plyrarray)
01392 {
01393   int i;
01394   int Eovermin;
01395   double MajAbsCoef;
01396   LYR *plyr, *plyrold;
01397     
01398   *plyrarray=(LYR*)calloc(NFoil+1,sizeof(LYR));
01399   if (*plyrarray==NULL){fprintf(stderr,"\n Error allocating memory (lyrarray)\n");exit(1);}
01400   
01401   /*The following definitions for layer 0 are done for convenience even when first "real" layer has label 1.*/
01402   plyr=&(*plyrarray)[0];
01403   
01404 //   (*plyrarray)[0].FoilOutEner=pexp->BeamEner; 
01405 //   (*plyrarray)[0].absolutepos=0.;
01406 //   (*plyrarray)[0].ThickIn=0.;
01407   plyr->FoilOutEner=pexp->BeamEner;
01408   plyr->absolutepos=0.;
01409   plyr->ThickIn=0.;
01410 
01411   for(Eovermin=1, i=1; i<=NFoil && Eovermin; i++){
01412 //     printf("\n\nDEBUG:  Layer %d: \n",i);   
01413 //     (*plyrarray)[i].absolutepos=(*plyrarray)[i-1].absolutepos + (*plyrarray)[i-1].ThickIn;
01414 //     (*plyrarray)[i].FoilInEner=(*plyrarray)[i-1].FoilOutEner;
01415 //     initlyr(pexp, &MatArray[i-1], XYldArray, TotAbsCoefArray, &(*plyrarray)[i], &MajAbsCoef);
01416 //     createsublyrs(pexp, &MatArray[i-1], SPTArray, MajAbsCoef, &(*plyrarray)[i] );
01417 //     Eovermin=((*plyrarray)[i].FoilOutEner > pexp->FinalEner);
01418     plyrold=plyr;
01419     plyr=&(*plyrarray)[i];
01420     plyr->absolutepos=plyrold->absolutepos + plyrold->ThickIn;
01421     plyr->FoilInEner=plyrold->FoilOutEner;
01422     plyr->pFoil=&MatArray[i-1];
01423     initlyr(pexp, XYldArray, TotAbsCoefArray, PresentElems, plyr, &MajAbsCoef);
01424     createsublyrs(pexp, &MatArray[i-1], SPTArray, MajAbsCoef, plyr);
01425     Eovermin=(plyr->FoilOutEner > pexp->FinalEner);
01426   }
01427   
01428   /*if the lyr initialization loop was exited without initializing some layers, 
01429     reallocate the lyr structure and change the (used) number of foils.
01430     */
01431   *NFoilUsed=i-1;
01432   if(*NFoilUsed<NFoil){
01433     #if CPIXEVERBOSITY >0
01434     printf("\n\nWarning: Layer %d (and deeper) Have been ignored during calculation\n",*NFoilUsed+1);
01435     #endif
01436   }
01437   
01438   return(0);
01439 }
01440 
01441 
01442 /** Initializes ONE given layer.
01443  *  It allocates space for various arrays and sets initial values for  TrcUse, ResYldArray,...
01444  *  It also calculates the absorption and returns the Maximum absorption coefficient (MACoef).
01445  * 
01446  * Note: it uses the global vars minK, maxK, minM, minL,...
01447  * 
01448  * @param pexp (I) Pointer to structure containing experimental parameters.
01449  * @param XYldArray (I) Array of Xray yield coefs. See readXYld()
01450  * @param TotAbsCoefArray (I) Array containing a tables of Absorption Coefs (see readAbsCoef() )
01451  * @param plyr (I+O) Pointer to current layer struct.
01452  * @param PresentElems (O) Pointer to array of flags indicating presence for each element
01453  * @param MACoef (I+O) Maximum absorption coefficient to be used in calcs (presently only cares about K&Lcoefs) 
01454  * @return Always 0
01455  */
01456 int initlyr(const EXP_PARAM *pexp, const XrayYield *XYldArray, const AbsCoef *TotAbsCoefArray, const int *PresentElems, LYR *plyr, double *MACoef)
01457 {
01458   int i,j,jj,ll,Z;
01459   /*Auxiliary vars (or pointers):*/
01460   CalibYld *AbsFac;  
01461   XrayYield *ResYld;
01462   double geomcorr;
01463   
01464   
01465   plyr->NumOfTrc=plyr->pFoil->nfoilelm;
01466   
01467 //   plyr->ResArray=(XrayYield*)calloc(plyr->NumOfTrc,sizeof(XrayYield));
01468 //   if (plyr->ResArray==NULL){fprintf(stderr,"\n Error allocating memory (plyr->ResArray)\n");exit(1);}
01469   
01470   plyr->ResYldArray=(XrayYield*)calloc(plyr->NumOfTrc,sizeof(XrayYield));
01471   if (plyr->ResYldArray==NULL){fprintf(stderr,"\n Error allocating memory (plyr->ResYldArray)\n");exit(1);}
01472   
01473   plyr->SecResArray=(SecResType*)calloc(plyr->NumOfTrc,sizeof(SecResType));
01474   if (plyr->SecResArray==NULL){fprintf(stderr,"\n Error allocating memory (plyr->SecResArray)\n");exit(1);}
01475   
01476   /**CAUTION: Change with respect to CDT: TrcUse now starts with index 0*/
01477   plyr->TrcUse=(int*)calloc(plyr->NumOfTrc,sizeof(int));
01478   if (plyr->TrcUse==NULL){fprintf(stderr,"\n Error allocating memory (plyr->TrcUse)\n");exit(1);}
01479   
01480   /**CAUTION: Change with respect to CDT: NeedSFC now starts with index 0*/
01481    plyr->NeedSFC=(int*)calloc(plyr->NumOfTrc,sizeof(int));
01482    if (plyr->NeedSFC==NULL){fprintf(stderr,"\n Error allocating memory (plyr->NeedSFC)\n");exit(1);}
01483   ///Note: @todo plyr->NeedSFC is just a convenience pointer to the Sample-general NeedSFC. This should be changed  and not used, but for the moment it works.
01484 //   plyr->NeedSFC=NULL;   
01485 
01486    /**CAUTION: Change with respect to CDT: TrcAtnum now starts with index 0*/
01487   plyr->TrcAtnum=(int*)calloc(plyr->NumOfTrc,sizeof(int));
01488   if (plyr->TrcAtnum==NULL){fprintf(stderr,"\n Error allocating memory (plyr->TrcAtnum)\n");exit(1);}
01489     
01490   
01491   plyr->dimTrans=pexp->simpar.MaxZinsample + 1;  //The dimenssion of the Transmission vector must be enough to hold the element with Z=MaxZinsample
01492   plyr->Trans=(CalibYld*)calloc(plyr->dimTrans,sizeof(CalibYld));
01493   if (plyr->Trans==NULL){fprintf(stderr,"\n Error allocating memory (plyr->Trans)\n");exit(1);}
01494   
01495   /*Calculation of Transmission coefficient in this layer for each element present in the sample*/
01496   geomcorr= 1. / pexp->cosDet; //the thickness will be corrected considering the detector direction
01497   for(Z=1;Z<plyr->dimTrans;Z++){
01498     if(PresentElems[Z]){
01499       Transmission(XYldArray, TotAbsCoefArray, Z, plyr->pFoil, geomcorr, (CalibYld*)NULL, &plyr->Trans[Z]);
01500     }
01501   } 
01502   
01503   
01504   /*Initializations for each element in the layer*/
01505   for (*MACoef=0, i = 0; i < plyr->NumOfTrc; i++){
01506     /*Select which elements should be simulated*/
01507     plyr->TrcUse[i]= (plyr->pFoil->comp.elem[i].Z > minK);
01508     if (plyr->TrcUse[i]) {
01509       /**Note: At this point in the CDT code, CalYld is defined, but it makes no sense since 
01510       it is just a copy of XYldArray[].XYld (which is already there and never changing...
01511       So whenever CalYld[i] is needed, use XYldArray[i].XYld instead*/
01512       /*Initialization for XYldArray*/
01513       plyr->ResYldArray[i]=XYldArray[plyr->pFoil->comp.elem[i].Z];
01514       /*Some (stupid?) initialization for SecResArray*/
01515       plyr->SecResArray[i].Pk.atnum=plyr->pFoil->comp.elem[i].Z;
01516       for(j=0;j<3;j++){plyr->SecResArray[i].Pk.area[j][0]=1; plyr->SecResArray[i].Pk.area[j][1]=1;}
01517       
01518       /*Calculate absorption coefficients*/
01519       ResYld=&(plyr->ResYldArray[i]);
01520       plyr->TrcAtnum[i] = ResYld->atnum;   //<Fills the TrcAtnum Array
01521       AbsFac= &(plyr->SecResArray[i].SR.AbsFact);
01522       
01523       if (ResYld->ener.K_[1] > 0 && ResYld->atnum < maxK) {
01524         for (jj = 1; jj <= 3; jj++) {
01525           AbsFac->K_[jj] = TotAbsor(TotAbsCoefArray, &plyr->pFoil->comp, ResYld->ener.K_[jj]);
01526           if (*MACoef < AbsFac->K_[jj]) *MACoef = AbsFac->K_[jj];
01527         }
01528       }
01529       if (ResYld->ener.M_[1] > 0 && ResYld->atnum > minM) {
01530         for (jj = 1; jj <= 3; jj++) {
01531           AbsFac->M_[jj] = TotAbsor(TotAbsCoefArray, &plyr->pFoil->comp, ResYld->ener.M_[jj]);
01532           ///@todo TODO:Check why was the following line commented out (in the Pascal Code):
01533           /* if *MACoef<AbsC[ii].M[jj] then *MACoef:=AbsC[ii].M[jj] ;  */
01534         }
01535       }
01536       if (ResYld->ener.L_[1][1] > 0 && ResYld->atnum > minL) {
01537         for (jj = 1; jj <= 3; jj++) {
01538           for (ll = 1; ll <= 3; ll++) {
01539             AbsFac->L_[jj][ll] = TotAbsor(TotAbsCoefArray, &plyr->pFoil->comp, ResYld->ener.L_[jj][ll]);
01540             if (*MACoef < AbsFac->L_[jj][ll])  *MACoef = AbsFac->L_[jj][ll];
01541           }
01542         }
01543       }
01544     }
01545   }
01546   return(0);
01547 }
01548 
01549 
01550 int readFilter(const char *FilterDefFileNm, FILTER *Filter)
01551 {
01552   
01553   FILE *FilterDefFile;
01554   char dummy[LONGSTRINGLENGTH];
01555   int i,tempZ,j;
01556   foil *pfoil;
01557   double mg2at,natmass;
01558   
01559   
01560   Filter->geomcorr=1.;  ///<@todo For the moment, the geometric correction is just initialized to 1
01561   
01562   FilterDefFile = fopen(FilterDefFileNm, "r");
01563   if (FilterDefFile == NULL)
01564     {fprintf(stderr,"\nERROR: Could not open file '%s' for read.\n",FilterDefFileNm);exit(1);}
01565       
01566   /*Skip until "NUMBER OF FOILS"*/
01567   do {
01568     fscanf(FilterDefFile,"%255s",dummy);   
01569   } while (strcasecmp(dummy, "NUMBER_OF_FOILS"));  
01570   
01571   fscanf(FilterDefFile, "%d", &Filter->nlyr);
01572   
01573   /*Initialize  Sample*/
01574   //if(*Sample!=NULL)free(*Sample);
01575   Filter->foil=(foil*)malloc((Filter->nlyr)*sizeof(foil));
01576   if (Filter->foil==NULL){fprintf(stderr,"\n Error allocating memory (Filter->foil)\n");exit(1);}
01577   
01578   for (Filter->MaxZ=0, i = 0; i < Filter->nlyr ; i++) {
01579     pfoil=&(Filter->foil[i]);
01580     do {
01581       fscanf(FilterDefFile,"%255s",dummy);   
01582       } while (strcasecmp(dummy, "FOIL"));  
01583     
01584     fscanf(FilterDefFile, "%lg %10s", &pfoil->thick, dummy);
01585     if(strcasecmp(dummy,"cm2") && strcasecmp(dummy,"mg")){
01586       fprintf(stderr,"\n Error: Bad syntax in filter definition file: '%s' is not a known thickness unit\n",dummy);exit(1);
01587     }
01588     fscanf(FilterDefFile, "%d",  &pfoil->nfoilelm);
01589     tempZ=readCOMPOUND(FilterDefFile, pfoil->nfoilelm, &pfoil->comp);
01590     if(Filter->MaxZ < tempZ) Filter->MaxZ = tempZ;
01591     
01592     if(!strcasecmp(dummy,"mg")){
01593       /*Convert the value in pfoil->thick from mg/cm2 to 1e15at/cm2 */
01594       for(natmass=0, j=0 ; j<pfoil->nfoilelm ; j++) natmass += pfoil->comp.xn[j] * pfoil->comp.elem[j].M;
01595       mg2at=natmass/602214.1; // (Pm [g/mol] *1e3 [mg/g] / (Navo [at/mol])) * 1e15  
01596                               // ==> mg2at is in [mg/1e15at]
01597       pfoil->thick /= mg2at;  //Before this, thick was in mg/cm2, hence divide by mg2at to get 1e15at/cm2
01598     }
01599     
01600   }
01601   fclose(FilterDefFile);
01602   
01603   createPresentElems(Filter->MaxZ, Filter->nlyr, Filter->foil, &Filter->FilterElems);
01604   
01605   return(0);
01606 }
01607 
01608 /**@todo Document this function*/
01609 int FilterTrans(const EXP_PARAM *pexp, const XrayYield *XYldArray, const AbsCoef *TotAbsCoefArray, const int *PresentElems, FILTER *Filter)
01610 {
01611   int Z,i;
01612   CalibYld auxTrans, *pTrans, *pauxTrans;
01613   CalibYld unitTrans={ { 0.0, 1.0, 1.0, 1.0 },
01614                        { { 0.0, 0.0, 0.0, 0.0 },
01615                          { 0.0, 1.0, 1.0, 1.0 },
01616                          { 0.0, 1.0, 1.0, 1.0 },
01617                          { 0.0, 1.0, 1.0, 1.0 }},
01618                        { 0.0, 1.0, 1.0, 1.0 }};
01619   
01620   Filter->dimTrans=pexp->simpar.MaxZinsample + 1;  //The dimenssion of the Transmission vector must be enough to hold the element with Z=MaxZinsample
01621   Filter->Trans=(CalibYld*)calloc(Filter->dimTrans,sizeof(CalibYld));
01622   if (Filter->Trans==NULL){fprintf(stderr,"\n Error allocating memory (Filter->Trans)\n");exit(1);}
01623    
01624   for(Z=1;Z<Filter->dimTrans;Z++){
01625     for(Z=1;Z<Filter->dimTrans;Z++)
01626     if(PresentElems[Z]){
01627       pauxTrans=NULL; //Initially, we have nothing to accumulate 
01628       pTrans=&Filter->Trans[Z];
01629       *pTrans=unitTrans;
01630    
01631       for (i=0 ; i < Filter->nlyr ; i++){
01632         Transmission(XYldArray, TotAbsCoefArray, Z, &Filter->foil[i], Filter->geomcorr, pauxTrans, pTrans);
01633         auxTrans= *pTrans;  //backup the last pTrans values (not the pointer but the values!)
01634         pauxTrans=&auxTrans; //pauxTrans is set to the last foil transmission for accumulating
01635       }
01636     }
01637   }
01638   
01639   return(0);
01640 }
01641 
01642 
01643 /** Calculates the Transmission coefficients for a given foil (whith effective thickness calculated
01644  * using a geometric correction).
01645  * 
01646  * @param XYldArray (I) Array of Xray yield coefs. See readXYld()
01647  * @param TotAbsCoefArray (I) Array containing a tables of Absorption Coefs (see readAbsCoef() )
01648  * @param Z (I) Atomic number of the element for whose lines the transmission is calculated
01649  * @param pFoil (I) pointer to the current foil definition 
01650  * @param geomcorr (I) geometric correction to the foil thickness (allows tiltings)
01651  * @param pTransOld (I) If this pointer is not null, pTrans will be multiplied by it line-by-line. 
01652  * @param pTrans (O) Structure where the transmission coefs for each line are returned.
01653  * @return Always 0
01654  */
01655 int Transmission(const XrayYield *XYldArray, const AbsCoef *TotAbsCoefArray, int Z, const foil *pFoil, double geomcorr, const CalibYld *pTransOld, CalibYld *pTrans)
01656 {
01657   int jj,ll;
01658   double thickout;
01659   const CalibYld *pXYldener;  
01660   
01661   thickout=pFoil->thick * geomcorr;  //Effective thickness 
01662   pXYldener=&XYldArray[Z].ener;  //energies of lines for element with at.number Z
01663   
01664   /*Transmission coefs for K lines*/
01665   if (pXYldener->K_[1] > 0 && Z < maxK) {
01666     for (jj = 1; jj <= 3; jj++) {
01667       pTrans->K_[jj] = exp(-thickout * TotAbsor(TotAbsCoefArray, &pFoil->comp, pXYldener->K_[jj]) );
01668       if(pTransOld!=NULL) 
01669         pTrans->K_[jj] *= pTransOld->K_[jj];
01670     }
01671   }
01672   /*Transmission coefs for M lines*/
01673   if (pXYldener->M_[1] > 0 && Z > minM) {
01674     for (jj = 1; jj <= 3; jj++) {
01675       pTrans->M_[jj] = exp(-thickout * TotAbsor(TotAbsCoefArray, &pFoil->comp, pXYldener->M_[jj]) );
01676       if(pTransOld!=NULL) pTrans->M_[jj] *= pTransOld->M_[jj];
01677     }
01678   }
01679   /*Transmission coefs for L lines*/
01680   if (pXYldener->L_[1][1] > 0 && Z > minL) {
01681     for (jj = 1; jj <= 3; jj++) {
01682       for (ll = 1; ll <= 3; ll++) {
01683         pTrans->L_[jj][ll] = exp(-thickout * TotAbsor(TotAbsCoefArray, &pFoil->comp, pXYldener->L_[jj][ll]) );
01684         if(pTransOld!=NULL) pTrans->L_[jj][ll] *= pTransOld->L_[jj][ll];
01685       }
01686     }
01687   }
01688   return(0);
01689 }
01690 
01691 /**Calculates the total absoption (it returns it as a double) for a given X-ray line in a given compound
01692  * 
01693  * @param TotAbsCoefArray (I) Array containing a tables of Absorption Coefs (see readAbsCoef() )
01694  * @param cmp (I) Definition of the absorber material.
01695  * @param Xray (I) Energy of the X-ray, in keV  
01696  * @return Total absorption coefficient
01697  */
01698 double TotAbsor(const AbsCoef *TotAbsCoefArray, const COMPOUND *cmp, double Xray)
01699 {
01700   int i,iener;
01701   double absaux;
01702   int dimstdener;
01703   const AbsCoef *Absco;
01704   double stdener[23] = {      1.00, 1.25, 1.50, 1.75, 2.00, 
01705                         2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 
01706                         5.50, 6.00, 6.50, 7.00, 8.00, 10.0,
01707                         12.5, 15.0, 17.5, 20.0, 25.0, 30.0};
01708   
01709   dimstdener=23-1;                    
01710   /**<@todo This function returns 0 if the Xray energy is not in the range covered by stdener.
01711     Maybe an error (and exit) should be triggered instead. Moreover: Is this
01712     absolutely general? I think this limits the generality of the program since
01713     elements below Na cannot be treated (and this is not desirable from a
01714     generalistic point of view). Therefore, these limits should be coded as
01715     variables just as minK, maxK,...
01716     UPDATE 1: The limits can be expanded, but the X-absorption data table should
01717     be altered accordingly (and dimstdener too).
01718     UPDATE 2: Better to show a warning than to exit in case that the limits are
01719     violated (TODO). 
01720     */
01721   if (Xray < stdener[0] || Xray >= stdener[dimstdener])  return (0.);
01722   
01723   for(iener=1;Xray > stdener[iener];iener++);
01724   
01725   
01726   for (absaux=0, i = 0; i < cmp->nelem; i++) {
01727     Absco=&(TotAbsCoefArray[cmp->elem[i].Z]); 
01728     absaux += cmp->xn[i] * TotAbsor_elemental(iener, Absco, cmp->elem[i].Z, Xray);
01729   }
01730   
01731   return(absaux);
01732 }
01733 
01734 /**Calculates the total absoption coefficient (it returns it as a double) for a given X-ray line in a given element.
01735  *
01736  * @param iener (I) Index of the absorption line to be considered
01737  * @param Absco (I) Pointer to structure of Absorption Coefs for the absorber element
01738  * @param Z (I) Atomic number of the absorber element
01739  * @param Xray (I) Energy of the X-ray, in keV  
01740  * @return Total absorption coefficient
01741  */
01742 double TotAbsor_elemental(int iener, const AbsCoef *Absco, int Z, double Xray)
01743 {
01744   int j,limj;
01745   double absaux = 0.0;
01746   double enermaj, enermin, a, b, majcoef, mincoef;
01747   double stdener[23] = {      1.00, 1.25, 1.50, 1.75, 2.00, 
01748                         2.50, 3.00, 3.50, 4.00, 4.50, 5.00, 
01749                         5.50, 6.00, 6.50, 7.00, 8.00, 10.0,
01750                         12.5, 15.0, 17.5, 20.0, 25.0, 30.0};
01751                         
01752   /**@todo This function returns 0 if the Xray energy is not in the 1-30 range.
01753     Maybe an error (and exit) should be triggered instead. Moreover: Is this
01754     absolutely general? I think this limits the generality of the program since
01755     elements below Na cannot be treated (and this is not desirable from a
01756     generalistic point of view). Therefore, these limits should be coded as
01757     variables just as minK, maxK,...
01758     UPDATE 1: The limits can be expanded, but the X-absorption data table should
01759     be altered accordingly.
01760     UPDATE 2: Better to show a warning than to exit in case that the limits are
01761     violated (TODO). 
01762     */
01763 
01764   enermaj = stdener[iener];
01765   enermin = stdener[iener-1];
01766   majcoef = Absco->coefstd[iener];
01767   mincoef = Absco->coefstd[iener-1];
01768   
01769   if(Z<11) limj=0;     //No absorp edges in the 1-30keV range for elements of Z<11
01770   else{
01771   if(Z<28) limj=1;     //Only K absorp edges in the 1-30keV range for elements of Z<28
01772     else{
01773       if(Z<52) limj=4; //Only K & L absorp edges in the 1-30keV range for elements of Z<52
01774       else limj=9;                  // K, L & M  absorp edges in the 1-30keV range for elements of Z>52
01775     }  
01776   }
01777   /*Check wether the energy is affected by an absorption edge*/
01778   for (j = 1; j <= limj; j++) {
01779     if (Absco->enr[j] > 0 && Absco->enr[j] > enermin && Absco->enr[j] < Xray) {
01780       enermin = Absco->enr[j];
01781       mincoef = Absco->coefenr[j-1][1];
01782     }
01783     if (Absco->enr[j] > 0 && Absco->enr[j] < enermaj && Absco->enr[j] > Xray) {
01784       enermaj = Absco->enr[j];
01785       majcoef = Absco->coefenr[j-1][0];
01786     }
01787   }
01788   /*Logarithmic average*/
01789   a = log(majcoef / mincoef) / log(enermaj / enermin);
01790   b = log(majcoef) - a * log(enermaj);
01791   absaux = exp(a * log(Xray) + b);
01792 
01793   return(absaux);
01794 }
01795 
01796 
01797 
01798 /**Manages the creation of internal sublayers in each layer
01799  * 
01800  * @param pexp (I) Pointer to structure containing experimental parameters.
01801  * @param pMat (I) Pointer to current foil structure.
01802  * @param SPTArray (I) Pointer to precalculated tables of stoppings (see createSPT() )
01803  * @param MajAbsCoef (I) Maximum absorption coef for this layer.
01804  * @param plyr (I+O) Pointer to current layer struct.
01805  * @return Always 0
01806  */
01807 int createsublyrs(const EXP_PARAM *pexp, const foil *pMat, const SPT *SPTArray, double MajAbsCoef, LYR *plyr)
01808 {
01809   ESxType ESx1,ESx2,ESx3;
01810   int i,Fpos;
01811   double Range,range1,range2, Smax;
01812   
01813   //Before starting, find out the maximum stopping force for this layer (Smax)
01814   for(Smax=0., i=0 ; i < pMat->nfoilelm ; i++) Smax += SPTArray[pMat->comp.elem[i].Z].Smax * pMat->comp.xn[i];
01815    
01816  
01817   plyr->ThickIn=pMat->thick/pexp->cosInc;
01818 
01819   Fpos=1;
01820   plyr->ESxArray=(ESxType*)malloc((Fpos)*sizeof(ESxType));
01821   if (plyr->ESxArray==NULL){fprintf(stderr,"\n Error allocating memory (plyr->ESxArray)\n");exit(1);}
01822   
01823   ESx1.ep = plyr->FoilInEner;     //note that FoilInEner has been already initialized in initlyrarray()
01824   ESx1.stpp = getSP(&pMat->comp, SPTArray, ESx1.ep);
01825   ESx1.x = 0.0;
01826   plyr->ESxArray[Fpos-1]=ESx1;
01827   
01828   ///@todo Discuss this initialization with M.R.
01829   ESx2.ep = plyr->FoilInEner * 0.90;  
01830   ESx2.stpp = getSP(&pMat->comp, SPTArray, ESx2.ep);
01831   ESx2.x = 0.0; 
01832   
01833   ESx3.ep=pexp->FinalEner;
01834   ESx3.stpp = getSP(&pMat->comp, SPTArray, ESx3.ep);
01835   ESx3.x = 0.0;
01836 
01837 //   ESx2.ep = plyr->FoilInEner - plyr->ThickIn * Smax; 
01838 //   if(ESx2.ep < pexp->FinalEner)ESx2.ep= pexp->FinalEner;
01839 //   ESx2.stpp = getSP(&pMat->comp, SPTArray, ESx2.ep);
01840 //   ESx2.x = plyr->ThickIn; 
01841 //
01842 //   ESx3.ep=pexp->FinalEner;
01843 //   ESx3.stpp = getSP(&pMat->comp, SPTArray, ESx3.ep);
01844 //   ESx3.x = (plyr->FoilInEner - pexp->FinalEner)/Smax;
01845 
01846   
01847   SSThick(pexp, pMat, SPTArray, MajAbsCoef, plyr->ThickIn, ESx1, &ESx2, &Fpos, &range1, &plyr->ESxArray);
01848 
01849   ESx2=  plyr->ESxArray[Fpos - 1];
01850 
01851   if (ESx2.x == plyr->ThickIn) {
01852     plyr->FoilOutEner = ESx2.ep;
01853     Range = ESx2.x;
01854     plyr->FESxlen= Fpos;
01855   } 
01856   else {
01857     SSThick(pexp, pMat, SPTArray, MajAbsCoef, plyr->ThickIn, ESx2, &ESx3, &Fpos, &range2, &plyr->ESxArray);
01858     ESx3=plyr->ESxArray[Fpos-1];
01859     
01860     plyr->FoilOutEner = ESx3.ep;
01861     Range = range1 + range2;
01862     if (Range < plyr->ThickIn) plyr->ThickIn = Range;
01863     plyr->FESxlen = Fpos;
01864   }
01865   
01866   return(0);
01867 }
01868 
01869 
01870 /**Recursive function which divides a sublayer in two if either energy loss or absorption are too large
01871  * 
01872  * @param pexp (I) Pointer to structure containing experimental parameters.
01873  * @param pMat (I) Pointer to current foil structure.
01874  * @param SPTArray (I) Pointer to precalculated tables of stoppings (see createSPT() )
01875  * @param MajAbsCoef (I) Maximum absorption coef for this layer.
01876  * @param LayerThickness (I) Effective Thickness (in-going path) for the layer containing this sublayer.
01877  * @param ESxin (I) Struct of energy, stopping and depth (ESx) for first half of this sublayer
01878  * @param ESxfin (I+O) Pointer to struct of energy, stopping and depth (ESx) for 2nd half of this sublayer 
01879  * @param pFpos (I+O) Pointer to index of sublayer position into the layer.
01880  * @param thick (O) Pointer to thickness of current sublayer.
01881  * @param ESxA (O) Pointer to Array of sublayers in the current layer.
01882  * @return always 0.
01883  */
01884 int SSThick(const EXP_PARAM *pexp, const foil *pMat, const SPT *SPTArray, double MajAbsCoef, 
01885             double LayerThickness, ESxType ESxin,  ESxType *ESxfin, int *pFpos, double *thick, ESxType **ESxA)
01886 {
01887   double tck1, tck2, auxdecis, auxstpchange,auxaux;
01888   ESxType ESxm1, ESxaux;
01889 
01890   auxaux=exp(-MajAbsCoef * ESxin.x * pexp->cosFac);
01891   if (auxaux > 1e-7){
01892     /*calculate the relative transmission 
01893       Note: auxdecis is the relative contribution to the transmission due to the present layer
01894             compared to the transmission from the present layer to the surface.
01895             The cosFac transforms distances from in-going to out-going paths.
01896     */ 
01897     auxdecis = exp(MajAbsCoef * (ESxin.x - ESxfin->x) * pexp->cosFac) /auxaux;
01898          
01899   }
01900   else auxdecis = 1.0;
01901     
01902   /*Calculate the relative change in stopping forces (with an ad-hoc weight based on the relative energy)
01903   */ 
01904   auxstpchange= (ESxin.ep / pexp->BeamEner)* fabs(ESxin.stpp - ESxfin->stpp) / ((ESxin.stpp + ESxfin->stpp)/2.);
01905 
01906   /* Exit condition (no more recursive calls)*/
01907   /**@todo: check if the thressholds of these conditions are reasonable or should be more conservative.
01908    */
01909    if ( auxstpchange < 0.005  && auxdecis > 0.997 ){    
01910 //    if ( auxstpchange < 0.05   ){    //DEBUG!!!!!!!
01911     ESxaux.ep = (ESxin.ep + ESxfin->ep) / 2.; //mean energy
01912     ESxaux.stpp = getSP(&pMat->comp, SPTArray, ESxaux.ep);//stopping at mean energy 
01913     *thick = (ESxin.ep - ESxfin->ep) / ((ESxin.stpp + 4. *ESxaux.stpp  + ESxfin->stpp) / 6.); //
01914     ESxfin->x = ESxin.x + *thick;
01915     
01916     if (ESxfin->x > LayerThickness) {        
01917       *thick = LayerThickness - ESxin.x;
01918       ESxfin->x = LayerThickness;
01919       ESxfin->ep = ESxin.ep - 0.5*(ESxin.stpp + ESxfin->stpp) * (*thick) ;
01920       ESxaux.ep = (ESxin.ep + ESxfin->ep) / 2.;
01921       ESxaux.stpp = getSP(&pMat->comp, SPTArray, ESxaux.ep);
01922     }
01923 
01924     ESxaux.x = ESxin.x + *thick / 2.;
01925     
01926     //Reallocating ESxA
01927     *ESxA=(ESxType*)realloc(*ESxA,((*pFpos)+2)*sizeof(ESxType));
01928     if (*ESxA==NULL){fprintf(stderr,"\n Error allocating memory (ESxA)\n");exit(1);}
01929        
01930     (*ESxA)[*pFpos]=ESxaux;
01931     (*pFpos)++;
01932     
01933     (*ESxA)[*pFpos]= *ESxfin; 
01934     (*pFpos)++;
01935 
01936     
01937     /**@todo The reallocation of ESxArray could be done inteligently in increments larger than 2, thus sacrificing some memory to speed up the process. Some extra variable would also be needed to remember the actual dimension of the matrix and comparing it with pFpos.*/
01938 //      printf("\nDEBUG :  x[%d]=%.3le (E=%.2lf)\tx[%d]=%.3le (E=%.2lf) ",*pFpos-2,ESxaux.x,ESxaux.ep,*pFpos-1, ESxfin->x,ESxfin->ep);
01939 //     printf("\nDEBUG : %d) xin=%.3le (E=%.2lf)\txfin=%.3le (E=%.2lf) ",*pFpos,ESxin.x,ESxin.ep,ESxfin->x,ESxfin->ep); 
01940   }
01941   else{ //split in two and call SSThick() for each part
01942 //      if(auxdecis<0.97) printf("\nDEBUG :  R[%d]=A (%.4le)  x=%.4le",*pFpos,auxdecis,ESxfin->x);
01943 //      else printf("\nDEBUG :  R[%d]=S",*pFpos);
01944     
01945     ESxm1.ep = (ESxin.ep + ESxfin->ep) / 2;
01946     ESxm1.stpp = getSP(&pMat->comp, SPTArray, ESxm1.ep);
01947     ESxm1.x = ESxin.x + (ESxin.ep - ESxm1.ep) / ESxin.stpp;
01948     //if (ESxm1.x > LayerThickness)ESxm1.x = LayerThickness; //note: this value of ESxm1.x is only used for the calc of auxdecis, but does not affect to the stopping and E calcs, so we don't need to update ESxm1.ep and ESxm1.stpp
01949     
01950     SSThick(pexp, pMat, SPTArray, MajAbsCoef, LayerThickness, ESxin, &ESxm1, pFpos, &tck1, ESxA);
01951     
01952     if (ESxm1.x < LayerThickness) {
01953       SSThick(pexp, pMat, SPTArray, MajAbsCoef, LayerThickness, ESxm1, ESxfin, pFpos, &tck2, ESxA);
01954       *thick = tck1 + tck2;
01955     }
01956     else *thick = tck1;
01957   }  
01958   return(0);
01959 }
01960 
01961 
01962 
01963 /**Performs Calculation of Transmission and Yields and then calculates the Penetration Integral.
01964  Uses Simpson integration method.
01965 
01966 TotAbsCoefArray
01967 XYldSums (O)is a matrix which contains, for each element, the total sum of XRayYlds for the whole sample.
01968 
01969 
01970 @todo document this function
01971 
01972 NOTE: This function uses the global vars maxK, minM & minL
01973 */
01974 int integrate_Simpson(const EXP_PARAM *pexp, const AbsCoef *TotAbsCoefArray,
01975                        const FluorCKCoef *FCKCoefArray, const XrayYield *XYldArray,
01976                        int NFoilUsed, const FILTER *Filter, LYR *plyrarray, CalibYld *XYldSums){
01977   int ilyr, itrans, ii, jj, ll,mm;
01978   LYR *plyr;
01979   CalibYld *AbsFac;   
01980   CalibYld *pSSYld, *pSSTrs;  
01981   const AbsCoef *AbsC;
01982   const FluorCKCoef *pFCKTrc;
01983   XrayYield *pResYld;
01984   const CalibYld *pXYld;
01985   SecResType *pSecRes;
01986   CalibYld *pXYldSum;
01987   double tckout,tempE,tempM,attfraction;
01988   int tempZ, FirstReg;
01989   const SIM_PARAM *psim;
01990   CalibYld tempTr0;   
01991   psim=&pexp->simpar;
01992   
01993   for(ilyr=1; ilyr<=NFoilUsed; ilyr++){
01994     plyr=&plyrarray[ilyr]; 
01995   
01996     /*Initialize (with 0 values) the SSTrsArray. (Simpson Transmission)*/
01997     plyr->SSTrsArray=(CalibYld*)calloc((plyr->NumOfTrc * plyr->FESxlen),sizeof(CalibYld));
01998     if (plyr->SSTrsArray==NULL){fprintf(stderr,"\n Error allocating memory (lyr[layer].SSTrsArray)\n");exit(1);}
01999     /*Initialize (with 0 values) the SSYldArray. (Simpson Yield) */
02000     plyr->SSYldArray=(CalibYld*)calloc((plyr->NumOfTrc * plyr->FESxlen),sizeof(CalibYld));
02001     if (plyr->SSYldArray==NULL){fprintf(stderr,"\n Error allocating memory (lyr[layer].SSYldArray)\n");exit(1);}
02002     
02003           
02004     /*Calculate the transmission array (all sublayers x all elements) FOR THE GIVEN LAYER ONLY*/
02005   
02006     for (jj = 0; jj < plyr->NumOfTrc ; jj++) {
02007       if (plyr->TrcUse[jj]) {
02008         
02009         AbsFac= &(plyr->SecResArray[jj].SR.AbsFact);
02010         tempZ=plyr->TrcAtnum[jj];
02011         
02012         for (ii = 0; ii < plyr->FESxlen; ii++) { 
02013           tckout=plyr->ESxArray[ii].x * pexp->cosFac;  //effective thicknes to the surface of this layer from the sublayer ii  
02014           pSSTrs=&(plyr->SSTrsArray[ii + plyr->FESxlen * jj]);  //points to the "transmission matrix element"
02015           
02016           if (tempZ < maxK) {
02017             for (ll = 1; ll <= 3; ll++) {
02018               if (AbsFac->K_[ll] > 0)
02019                 pSSTrs->K_[ll] = exp(-AbsFac->K_[ll] * tckout);
02020             }
02021           }
02022           if (tempZ > minM) {
02023             for (ll = 1; ll <= 3; ll++) {
02024               if (AbsFac->M_[ll] > 0)
02025                 pSSTrs->M_[ll] = exp(-AbsFac->M_[ll] * tckout);
02026             }
02027           }
02028           if (tempZ > minL) {
02029             for (ll = 1; ll <= 3; ll++) {
02030               for (mm = 1; mm <= 3; mm++) {
02031                 if (AbsFac->L_[ll][mm] > 0)
02032                   pSSTrs->L_[ll][mm] = exp(-AbsFac->L_[ll][mm] * tckout);
02033               }
02034             }
02035           }
02036         }
02037       }
02038     }
02039     
02040     /*Perform "Simpson" Calculation of yield. 
02041     (Originally this was done in a separated function called SimpSSYld()*/
02042     for (jj = 0; jj < plyr->NumOfTrc; jj++) {
02043       if (plyr->TrcUse[jj]) {
02044         
02045         tempZ=plyr->TrcAtnum[jj];
02046         Z2mass(tempZ, &tempM, 'n');
02047         pFCKTrc=&FCKCoefArray[tempZ];
02048         AbsC=&TotAbsCoefArray[tempZ];
02049         
02050         for (ii = 0; ii < plyr->FESxlen; ii++) {
02051           tempE=plyr->ESxArray[ii].ep;
02052           pSSYld=&( plyr->SSYldArray[ (ii + plyr->FESxlen * jj) ] );
02053           
02054           Xprod(AbsC, pFCKTrc, pexp->ion.Z, tempZ, tempM, tempE, pSSYld);
02055           
02056         }
02057       }
02058     }     
02059   
02060   }
02061   
02062   /*clears any previously used Sum*/
02063   
02064   /*Calculates the Penetration Integral*/
02065   for(ilyr=1; ilyr<=NFoilUsed; ilyr++){
02066     plyr=&plyrarray[ilyr]; 
02067     
02068     for (ii = 0; ii < plyr->NumOfTrc ; ii++) {
02069     
02070       if (plyr->TrcUse[ii]) {
02071         tempZ=plyr->TrcAtnum[ii];
02072         Z2mass(tempZ, &tempM, 'n');
02073         pFCKTrc=&FCKCoefArray[tempZ];
02074         AbsC=&TotAbsCoefArray[tempZ];
02075         pResYld=&plyr->ResYldArray[ii];
02076         pSecRes=&plyr->SecResArray[ii];
02077         AbsFac= &(plyr->SecResArray[ii].SR.AbsFact);
02078         pXYld=&XYldArray[tempZ].XYld;
02079         pXYldSum=&XYldSums[tempZ];
02080         attfraction=plyr->pFoil->comp.xn[ii];
02081 
02082 //         printf("\n DEBUG: Calculating Penetration Integral for : %s in layer %d\n",pResYld->symb,ilyr) ;
02083 
02084         //pSSTrs and pSSYld are reused to hold now one-dimensional arrays of CalibYld structures containing the Transmission and yield values for the ii element in all sublayers. More precisely, they point to subsections (rows) of the 2-dim arrays SSTrsArray and SSYldArray that contain the mentioned info.
02085         FirstReg = (ii) * plyr->FESxlen;  
02086         pSSTrs=&plyr->SSTrsArray[FirstReg]; 
02087         pSSYld=&plyr->SSYldArray[FirstReg];
02088         
02089         // keep in mind that YFirstReg and TFirstReg (now combined in just FirstReg) have been shifted down by one to accomodate to the redefiniton of the SSTrsArray and Yield matrices (which start in 0 for both indexes) 
02090                 
02091         //correction due to transmission in layers over the one we are considering
02092         tempTr0=plyr->SSTrsArray[FirstReg];  //the relevant lines become initialized at value=1
02093         //For K lines...
02094         if (tempZ < maxK) {
02095           for (ll = 1; ll <= 3; ll++) {
02096             tempTr0.K_[ll] *= Filter->Trans[tempZ].K_[ll]; //Apply transmission of filter
02097             for(itrans=ilyr-1 ; itrans>0 ; itrans--){ //apply transmission of every layer on top of current one
02098               tempTr0.K_[ll] *= plyrarray[itrans].Trans[tempZ].K_[ll];
02099             }
02100           }
02101         }
02102         //Same for M lines...
02103         if (tempZ > minM) {
02104           for (ll = 1; ll <= 3; ll++) {
02105             tempTr0.M_[ll] *= Filter->Trans[tempZ].M_[ll]; 
02106             for(itrans=ilyr-1 ; itrans>0 ; itrans--){
02107               tempTr0.M_[ll] *= plyrarray[itrans].Trans[tempZ].M_[ll];
02108             }
02109           }
02110         }
02111         //Same for L lines...
02112         if (tempZ > minL) {
02113           for (ll = 1; ll <= 3; ll++) {
02114             for (mm = 1; mm <= 3; mm++) {
02115               tempTr0.L_[ll][mm] *= Filter->Trans[tempZ].L_[ll][mm]; 
02116               for(itrans=ilyr-1 ; itrans>0 ; itrans--){
02117                 tempTr0.L_[ll][mm] *= plyrarray[itrans].Trans[tempZ].L_[ll][mm];
02118               }
02119             }
02120           }
02121         }  
02122           
02123         PenInteg(tempZ, AbsFac, plyr->ESxArray, pSSYld,
02124                 pSSTrs, &tempTr0, plyr->FESxlen, 
02125                 plyr->NeedSFC[ii], psim->AllowXEqCalc, plyr->absolutepos, pexp->cosInc,
02126                 &pResYld->XYld, &pSecRes->SR.SFCr, &pSecRes->SR.Xeq);
02127           
02128         deNormalize(pexp, AbsC ,pFCKTrc, tempZ, tempM, attfraction, pXYld, pResYld, pXYldSum);
02129         
02130       }
02131     }
02132   }
02133 
02134   
02135   return(0);
02136 }
02137 
02138 /**Calculates X-Ray production efficiency for a given beam and target, in cm2/(1e15at).
02139  * 
02140  * @param AbsC (I) pointer to Absorption coef structure for Z2
02141  * @param pFCK (I) pointer to Fluorescence and Coster-Kronig coefficients for Z2
02142  * @param Z1 (I) atomic number of the ion (note: currently only Z1=1 is supported)
02143  * @param Z2 (I) atomic number of the target
02144  * @param M2 (I) mass of the target atom
02145  * @param ener (I) energy of the incident ion, in keV
02146  * @param XYld (O) Pointer to return the X-ray production efficiency, in cm2/(1e15at)
02147  * @return Always 0
02148  *
02149  *@todo This function only works for proton beams!!
02150  */
02151 int Xprod(const AbsCoef *AbsC, const FluorCKCoef *pFCK, atomicnumber Z1, atomicnumber Z2, double M2 , double ener, CalibYld *XYld)
02152 {
02153   int i, j;
02154   SecXL XLaux;
02155   double auxsec;
02156   CalibYld CYldNul = { { 0.0, 0.0, 0.0, 0.0 },
02157                        { { 0.0, 0.0, 0.0, 0.0 },
02158                          { 0.0, 0.0, 0.0, 0.0 },
02159                          { 0.0, 0.0, 0.0, 0.0 },
02160                          { 0.0, 0.0, 0.0, 0.0 }},
02161                        { 0.0, 0.0, 0.0, 0.0 }};
02162   double barn_to_cm21e15;
02163   
02164   barn_to_cm21e15=1e-9;  // 1 barn/at = 1e-24 cm2/at= 1e-9 cm2/(1e15at)
02165 
02166   
02167   if(Z1!=1){fprintf(stderr,"\n Error: Xprod() currently supports only H ions\n");exit(1);}
02168     
02169   *XYld = CYldNul;
02170   switch (Z2) {
02171 
02172   case 10: ///@todo Check hardcoded Z limits 
02173   case 11:
02174   case 12:
02175   case 13:
02176   case 14:
02177     auxsec = PaulX(ener, Z2);  // barn
02178     XYld->K_[1] = auxsec * pFCK->k.K_[1] * barn_to_cm21e15;  // cm2/1e15at
02179     break;
02180 
02181   case 54:
02182   case 55:
02183   case 56:
02184   case 57:
02185   case 58:
02186   case 59:
02187     ReisX(AbsC,pFCK, ener, Z2, M2, XLaux);
02188     for (i = 1; i <= 3; i++) {
02189       for (j = 1; j <= 3; j++)
02190         XYld->L_[i][j] = XLaux[4 - i] * pFCK->k.L_[i][j] * barn_to_cm21e15;  // cm2/1e15at
02191     }
02192     break;
02193 
02194   default:
02195     if (Z2 >= 15 && Z2 <minL) { ///@todo Check hardcoded Z limits 
02196       auxsec = PaulX(ener, Z2);
02197       XYld->K_[1] = auxsec * pFCK->k.K_[1] * barn_to_cm21e15;  // cm2/1e15at
02198       XYld->K_[2] = auxsec * pFCK->k.K_[2] * barn_to_cm21e15;  // cm2/1e15at
02199     } 
02200     else if (Z2 >= minL && Z2 < maxK) {
02201       auxsec = PaulX(ener, Z2);
02202       ReisX(AbsC,pFCK, ener, Z2, M2, XLaux);
02203       for (i = 1; i <= 3; i++) {
02204         XYld->K_[i] = auxsec * pFCK->k.K_[i] * barn_to_cm21e15;  // cm2/1e15at
02205         for (j = 1; j <= 3; j++)
02206           XYld->L_[i][j] = XLaux[4 - i] * pFCK->k.L_[i][j] * barn_to_cm21e15;  // cm2/1e15at
02207       }
02208     }
02209     else if (Z2 >= minM && Z2 <= 99) {///@todo Check hardcoded Z limits 
02210       ReisX(AbsC,pFCK, ener, Z2, M2, XLaux);
02211       for (i = 1; i <= 3; i++) {
02212         for (j = 1; j <= 3; j++)
02213           XYld->L_[i][j] = XLaux[4 - i] * pFCK->k.L_[i][j] * barn_to_cm21e15;  // cm2/1e15at
02214       }
02215     }
02216     break;
02217   }
02218   return(0);
02219 }
02220 
02221 /**
02222  * 
02223  * @param ener 
02224  * @param z Atomic number of Target
02225  * @return X-ray cross-section, in barn
02226  *
02227  *@todo Document this function (description, units for ener & return and references)
02228  *
02229  *@todo This function only works for proton beams!!
02230  */
02231 double PaulX(double ener, atomicnumber z)
02232 {
02233   static double sc1 = -2.1717, sc2 = 10.8883, sc3 = 9.45875, sc4 = 0.975316,
02234     sc5 = 0.0165458, sc6 = 1.00859, sc7 = 0.0474606;
02235 
02236   static double ylim[4] = { 0., -0.86, -0.582, -0.037  };  //note, index 0 not used
02237 
02238   static double C[8][7] = {//note, indexes 0 not used
02239     { 0.,  0.       ,  0.        , 0.         ,  0.        ,  0.        ,  0.         },
02240     { 0.,  4.97159  , -0.0334597 ,  4.56721e-3, -4.17618e-6, -0.0152467 ,  9.11304e-4 },
02241     { 0.,  -3.89274 , -0.883283  , -0.0177272 ,  1.03168e-4,  0.824937  ,  0.0110194  },
02242     { 0.,  597612.0 ,  597919.0  ,  25220.1   , -37.2554   , -362099.0  , -13942.3    },
02243     { 0.,  0.107444 , -4.47727e-3,  1.30581e-4, -1.9793e-6 ,  1.00964e-8,  0.0        },
02244     { 0.,  0.113657 , -8.4197e-3 ,  2.40606e-4, -2.95528e-6,  1.26726e-8,  0.0        },
02245     { 0.,  0.0105593,  7.4928e-4 , -1.30255e-5,  9.19824e-8,  0.0       ,  0.0        },
02246     { 0., -0.0306492,  1.00377e-3, -1.68953e-5,  8.74937e-8,  0.0       ,  0.0        }};
02247 
02248   long i;
02249   double sc = 0.0;
02250   double MeV,f, pauly, paule, xx, auxpp1, auxpp2, auxpp3;
02251   double auxl[7];
02252   double b[8];
02253 
02254   
02255   MeV = ener*0.001;   // converting keV-->MeV
02256   paule = log10(MeV / (z * z));
02257   xx = paule / 1.15 + 2.22;
02258   pauly = PaulX_y(MeV, z);
02259   if (pauly < ylim[1])   // This correction is not in the PAul's paper
02260     sc = 0.0;
02261   if (pauly >= ylim[1] && pauly <= ylim[2])
02262     sc = sc1 - sc2 * pauly - sc3 * pauly * pauly;
02263   if (pauly > ylim[2] && pauly <= ylim[3])
02264     sc = sc4 - sc5 * cos(13.6 * (pauly + 0.393));
02265   if (pauly > ylim[3])
02266     sc = sc6 + sc7 * cos(6.23 * (pauly - 0.33));
02267   for (i = 1; i <= 7; i++) {
02268     b[i] = C[i][1] + C[i][2] * z + C[i][3] * z * z + C[i][4] * z * z * z;
02269     switch (i) {
02270 
02271     case 1:
02272     case 2:
02273     case 3:
02274       b[i] /= 1 + C[i][5] * z + C[i][6] * z * z;
02275       break;
02276 
02277     case 4:
02278     case 5:
02279       b[i] += C[i][5] * z * z * z * z;
02280       break;
02281     }
02282   }
02283   for (i = 3; i <= 6; i++)
02284     auxl[i] = PaulX_lp(xx, i);
02285   auxpp1 = paule - b[3];
02286   auxpp1 *= auxpp1;
02287   auxpp2 = b[4] * PaulX_lp(xx, 3);
02288   auxpp3 = b[5] * PaulX_lp(xx, 4) + b[6] * PaulX_lp(xx, 5) + b[7] * PaulX_lp(xx, 6);
02289   f = b[1] + b[2] * auxpp1 + auxpp2 + auxpp3;
02290   return (sc * exp(f * log(10.0) - 2.2 * log(z)));
02291 }
02292 
02293 
02294 
02295 /**
02296  * 
02297  * @param MeV Energy of the ion, in MeV
02298  * @param z Atomic number of Target
02299  * @return 
02300  *
02301  *@todo Document this function (description, units for ener & return and references)
02302  *
02303  *@todo This function only works for proton beams!!
02304  */
02305 double PaulX_y(double MeV, atomicnumber z)
02306 {
02307   static double teta1 = 0.313076, teta2 = 0.149231, teta3 = 5.54982e-5,
02308     teta4 = 3.7093e-6, teta5 = 0.166608;
02309   double auxz = z;
02310   double eta, theta, TEMP;
02311 
02312   TEMP = auxz - 0.3;
02313   eta = 40.0283 * MeV / (TEMP * TEMP);
02314   theta = teta1 + teta2 * auxz - teta3 * auxz * auxz + teta4 * auxz * auxz * auxz;
02315   theta /= 1 + teta5 * auxz;
02316   return (log10(2 * sqrt(eta) / theta));
02317 }
02318 
02319 /**
02320  * 
02321  * @param x 
02322  * @param p
02323  * @return 
02324  *
02325  *@todo Document this function (description, units for ener & return and references)
02326  */
02327 double PaulX_lp(double x, long p)
02328 {
02329   double prr = 0.0;
02330   double TEMP, TEMP1;
02331 
02332   switch (p) {
02333 
02334   case 3:
02335     prr = 0.5 * (5 * x * x * x - 3 * x);
02336     break;
02337 
02338   case 4:
02339     TEMP = x * x;
02340     prr = 0.125 * (35 * (TEMP * TEMP) - 30 * x * x + 3);
02341     break;
02342 
02343   case 5:
02344     TEMP = x * x;
02345     prr = 0.125 * (63 * x * (TEMP * TEMP) - 70 * x * x * x + 15 * x);
02346     break;
02347 
02348   case 6:
02349     TEMP = x * x;
02350     TEMP1 = x * x;
02351     prr = 0.0625 * (231 * x * x * (TEMP * TEMP) - 315 * (TEMP1 * TEMP1) +
02352         105 * x * x - 5);
02353     break;
02354   }
02355   return (prr);
02356 }
02357 
02358 
02359 /**Returns X-ray fluorescence cross-sections for L lines. See paper ??? @todo(cite M.Reis paper named ???)
02360  * 
02361  * @param AbsC (I) Pointer to Absorption coef structure for element with Z2
02362  * @param pFCK (I) Pointer to structure containing the Fluorescence and Coster-Kronig coefs
02363  * @param ener (I) Proton energy, in keV
02364  * @param z (I) Atomic number of Target
02365  * @param M2 (I) Atomic mass of Target (in amu)
02366  * @param sigmaXL (O) X-ray cross sections, in barn
02367  * @return Always 0
02368  *
02369  *@todo This function is only for proton beams!! 
02370  */
02371 int ReisX(const AbsCoef *AbsC, const FluorCKCoef *pFCK, double ener, atomicnumber z, double M2, double *sigmaXL)
02372 {  
02373 
02374   SecXL ion, ionuni;
02375   int i;
02376   double xi[4];
02377   int seted = 0;
02378   double TEMP;
02379   double enr;
02380   FwTipo tipo;
02381   
02382   int Ncam, Zpr, nium;
02383   double MeV, Hr, cau, a02, Z2b, z2, z4, miu, EnrSm1, Mpr, MprMeV, MprUAt, a2s, v1,Iabs, q0sb,
02384          theta, ksi, zeta, ys, ys2, d, mRs, ksir, xcb, zcbs, cbe, etam, ratnorm;
02385   
02386   MeV = ener * 1e-3;   //converting from keV to MeV
02387   Zpr = 1;   //Only protons!
02388   Mpr = 1.007;   //Only protons!
02389   Ncam = 2;   //L atomic layer
02390   
02391   Hr = 27.2116;            ///@todo What is Hr ???
02392   cau = 137.03604;         ///@todo What is cau ???
02393   a02 = 2.800283608e-21;   ///@todo What is a02 ???
02394   
02395   tipo = L;
02396   Z2b = (double)(z) - 4.15;
02397   z2 = Z2b * Z2b;
02398   z4 = z2 * z2;
02399   
02400   MprMeV = Mpr * MEVAMU;   //MEVAMU is defined at the beginning of the file
02401   MprUAt = Mpr / UATMASS ; //UATMASS is defined at the beginning of the file
02402   EnrSm1 = MeV / MprMeV;
02403   miu = Mpr / (1 + Mpr / M2) / UATMASS;   /** U.Atomicas de massa  **/
02404   a2s = (double)(Ncam * Ncam) / Z2b;
02405   TEMP = 1 + EnrSm1;
02406   TEMP = 1 / (TEMP * TEMP);
02407   v1 = cau * sqrt(1 - TEMP);   /** U.Atomicas  **/
02408   d = (double)Zpr * z / (miu * (v1 * v1));
02409   for (i = 1; i <= 3; i++) {
02410     enr=AbsC->enr[i+1];
02411     if (enr > 0) {
02412       seted = 1;
02413       Iabs = enr * 1e3;   // in eV 
02414       q0sb = Iabs / (Hr * v1);
02415       theta = (double)(Ncam * Ncam * 2) * Iabs / (z2 * Hr);
02416       ksi = 2 * v1 / (theta * (Z2b / (double)Ncam));
02417       TEMP = ReisX_gs(tipo, i, ksi);
02418       TEMP -= ReisX_hs(tipo, i, ksi, theta);
02419       zeta = 1. + (double)(Zpr * 2) * TEMP / (Z2b * theta);
02420     /** parametro de correccao de polarizacao-ligacao **/
02421       TEMP=z2/(cau*cau*ksi/zeta);
02422       if (i == 1)  ys = TEMP * 0.40  / (double)Ncam ;
02423       else  ys =  TEMP * 0.15 ;
02424       ys2 = ys * ys;
02425       mRs = sqrt(1. + 1.1 * ys2) + ys;
02426       ksir = sqrt(mRs) * ksi;
02427       xi[i] = 1. / ksir;
02428       /** correccao de defleccao Coulombiana  **/
02429       xcb = 2. * M_PI * d * q0sb * zeta;
02430       zcbs = sqrt(1. - 4. * zeta / (theta * miu * ksi * ksi * mRs));
02431       switch (i) {
02432         case 1:
02433           nium = 9;
02434           break;
02435         case 2:
02436         case 3:
02437           nium = 11;
02438           break;
02439         case 4:
02440         case 5:
02441           nium = 13;
02442           break;
02443       }
02444       TEMP = xcb / (zcbs * (1 + zcbs));
02445       cbe = (double)nium * ReisX_En(TEMP, nium + 1);
02446       TEMP = theta * ksir / ((double)(Ncam * 2));
02447       etam = TEMP * TEMP;
02448       TEMP = (double)Zpr / Z2b;
02449       ratnorm = 8. * M_PI * (a02 / (etam * theta)) * (TEMP * TEMP) * cbe / BARNTOM2;
02450       ionuni[i] = ReisX_polisec(i, ksir, theta);
02451       ion[i] = ionuni[i] * ratnorm;
02452     }
02453   }
02454   sigmaXL[1] = ReisX_g(1, z, xi[1]) * pFCK->w[2] * ion[1];
02455   sigmaXL[2] = ReisX_g(2, z, xi[2]) * pFCK->w[3] * (pFCK->ck[0] * ion[1] + ion[2]);
02456   sigmaXL[3] = ReisX_g(3, z, xi[3]) * pFCK->w[4] * 
02457                ((pFCK->ck[1] + pFCK->ck[0] * pFCK->ck[2]) * ion[1] + pFCK->ck[2] * ion[2] + ion[3]);
02458   
02459   return(0);
02460 }
02461 
02462 /**Auxiliar function to ReisX()
02463  * 
02464  * @param T 
02465  * @param SS 
02466  * @param ksis 
02467  * @return 
02468  * 
02469  *@todo check that the units of the hardcoded constants are appropriate 
02470  *
02471  *
02472  *@todo document this function
02473  */
02474 double ReisX_gs(FwTipo T, int SS, double ksis)
02475 {
02476   /** ref. Brandt and Lapicki,Phys.Rev.,A20(1979)465 **/
02477   static double gK[9] = {
02478     1.0, 1.0, 9.0, 31.0, 98.0, 12.0, 25.0, 4.2, 0.515
02479   };
02480 
02481   static double gL1[9] = {
02482     1.0, 1.0, 9.0, 31.0, 49.0, 162.0, 63.0, 18.0, 1.97
02483   };
02484 
02485   static double gL23[10] = {
02486     1.0, 1.0, 10.0, 45.0, 102.0, 331.0, 6.7, 58.0, 7.8, 0.888
02487   };
02488 
02489   double ksis2, ksis3, ksis4, ksis5, ksis6, ksis7, ksis8;
02490   double gsaux = 0.0;
02491   double gsaux2;
02492 
02493   ksis2 = ksis * ksis;
02494   ksis3 = ksis * ksis2;
02495   ksis4 = ksis2 * ksis2;
02496   ksis5 = ksis2 * ksis3;
02497   ksis6 = ksis3 * ksis3;
02498   ksis7 = ksis3 * ksis4;
02499   ksis8 = ksis4 * ksis4;
02500   switch (T) {
02501 
02502   case K:
02503     gsaux = gK[1] + gK[2] * ksis + gK[3] * ksis2 + gK[4] * ksis3;
02504     gsaux += gK[5] * ksis4 + gK[6] * ksis5 + gK[7] * ksis6 + gK[8] * ksis7;
02505     gsaux2 = 1 + ksis;
02506     gsaux2 *= gsaux2 * gsaux2;
02507     gsaux2 *= gsaux2 * gsaux2;
02508     gsaux /= gsaux2;
02509     break;
02510 
02511   case L:
02512     if (SS == 1) {
02513       gsaux = gL1[1] + gL1[2] * ksis + gL1[3] * ksis2 + gL1[4] * ksis3;
02514       gsaux += gL1[5] * ksis4 + gL1[6] * ksis5 + gL1[7] * ksis6 + gL1[8] * ksis7;
02515       gsaux2 = 1 + ksis;
02516       gsaux2 *= gsaux2 * gsaux2;
02517       gsaux2 *= gsaux2 * gsaux2;
02518       gsaux /= gsaux2;
02519     } else {
02520       gsaux = gL23[1] + gL23[2] * ksis + gL23[3] * ksis2 + gL23[4] * ksis3;
02521       gsaux += gL23[5] * ksis4 + gL23[6] * ksis5 + gL23[7] * ksis6 +
02522          gL23[8] * ksis7;
02523       gsaux += gL23[9] * ksis8;
02524       gsaux2 = 1 + ksis;
02525       gsaux2 *= gsaux2 * gsaux2;
02526       gsaux2 *= gsaux2 * gsaux2;
02527       gsaux2 *= 1 + ksis;
02528       gsaux /= gsaux2;
02529     }
02530     break;
02531   default:break;
02532   }
02533   return (gsaux);
02534 } 
02535 
02536 
02537 /** Auxiliar function to ReisX()
02538  * 
02539  * @param T 
02540  * @param SS 
02541  * @param ksih 
02542  * @param thet 
02543  * @return 
02544  * 
02545  *@todo check that the units of the hardcoded constants are appropriate 
02546  *
02547  *
02548  *@todo document this function
02549  */
02550 double ReisX_hs(FwTipo T, int SS, double ksih, double thet)
02551 {
02552   static double IhsC[6] = { 0.031, 0.031, 0.210, 0.005, -0.069, 0.324  };
02553   double x, x12, ksih3;
02554   double Ihs = 0.0, cs = 0.0;
02555   int n2hs = 0;
02556 
02557   switch (T) {
02558 
02559   case K:
02560     n2hs = 1;
02561     cs = 3.0 / 2.;
02562     break;
02563 
02564   case L:
02565     n2hs = 2;
02566     if (SS == 1) cs = 3.0 / 2.;
02567     else  cs = 5.0 / 4.;
02568     break;
02569     
02570   default:break;  
02571   }
02572   ksih3 = ksih * ksih * ksih;
02573   x = cs * n2hs / ksih;
02574   x12 = sqrt(x);
02575   if (x > 0 && x <= 0.035)
02576     Ihs = 3 * M_PI / 4 * log(1 / (x * x) - 1);
02577   if (x > 0.035 && x <= 3.1) {
02578     Ihs = IhsC[1] + IhsC[2] * x12 + IhsC[3] * x + IhsC[4] * x * x12 + IhsC[5] * x * x;
02579     Ihs = exp(-2 * x) / Ihs;
02580   }
02581   if (x > 3.1 && x < 11)
02582     Ihs = 2 * exp(-2 * x) / exp(1.6 * log(x));
02583     
02584   return(n2hs * 2 * Ihs / (thet * ksih3));
02585 } 
02586 
02587 
02588 /**Auxiliar function to ReisX()
02589  * 
02590  * @param z 
02591  * @param niu 
02592  * @return 
02593  * 
02594  *@todo check that the units of the hardcoded constants are appropriate 
02595  *
02596  *
02597  *@todo document this function
02598  */
02599 double ReisX_En(double z, int niu)
02600 {
02601   /** aproximation for niu>> **/
02602   /** vide Abramowitz & Stegun , Dover 1Ed. 1965 **/
02603   double Eaux, z2, z3, niu2, aux, aux2, aux4, aux6;
02604 
02605   z2 = z * z;
02606   z3 = z2 * z; 
02607   niu2 = niu * niu;
02608   aux = z + niu;
02609   aux2 = aux * aux;
02610   aux4 = aux2 * aux2;
02611   aux6 = aux4 * aux2;
02612   Eaux = niu * (6 * z2 - 8 * niu * z + niu2) / aux6;
02613   Eaux++;
02614   Eaux = exp(-z) * Eaux / aux;
02615   return(Eaux);
02616 }
02617 
02618 /**Auxiliar function to ReisX()
02619  * 
02620  * @param ssind 
02621  * @param kz 
02622  * @param tz 
02623  * @return 
02624  * 
02625  * 
02626  *@todo check that the units of the hardcoded constants are appropriate 
02627  *
02628  *
02629  *@todo document this function
02630  */
02631 double ReisX_polisec(int ssind, double kz, double tz)
02632 {
02633   double Result = 0.0;
02634 
02635   static double fc1[8] = {
02636      737.658767, -5422.24598, 17070.7835, -29572.7846, 
02637      30490.2736, -18719.3387, 6343.25887, -916.108807
02638   };
02639 
02640   static double fc2[8] = {
02641     -1513.63296, 5152.69169, -7347.41315, 5748.20489,
02642     -2665.54100, 733.610039, -111.064039, 7.14045527
02643   };
02644 
02645   static double fc3[8] = {
02646      13.1119073, -41.7263393, 97.1163461, -100.159645, 
02647      60.9662790, -21.6315896, 4.12048128, -0.325361134
02648   };
02649 
02650   static double fc4[8] = {
02651      18.9172599, -59.1559460, 126.801210, -127.067875, 
02652      74.6217068, -25.5046721, 4.68627281, -0.357639954
02653   };
02654 
02655   double p1;
02656   double x = 0.0;
02657   double coef[8];
02658   int i;
02659   
02660   switch (ssind) {
02661 
02662   case 1:
02663     x = 1 / sqrt(kz * exp(0.3 * log(tz)));
02664     if (x < 1.35)
02665       memcpy(coef, fc1, sizeof(double) * 8);
02666     else
02667       memcpy(coef, fc2, sizeof(double) * 8);
02668     break;
02669 
02670   case 2:
02671     x = 1 / sqrt(kz * exp(0.2 * log(tz)));
02672     memcpy(coef, fc3, sizeof(double) * 8);
02673     break;
02674 
02675   case 3:
02676     x = 1 / sqrt(kz * exp(0.32 * log(tz)));
02677     memcpy(coef, fc4, sizeof(double) * 8);
02678     break;
02679   }
02680   
02681   for (p1 = coef[7], i = 6; i >=0; i--)  p1 = x * p1 + coef[i]; //polynomial calculation
02682   
02683   switch (ssind) {
02684 
02685   case 1:
02686     Result = exp(-p1) / exp(3.8 * log(tz));
02687     break;
02688 
02689   case 2:
02690     Result = exp(-p1) / exp(2.5 * log(tz));
02691     break;
02692 
02693   case 3:
02694     Result = exp(-p1) / exp(6.5 * log(tz));
02695     break;
02696   }
02697   return(Result);
02698 }
02699 
02700 /**Auxiliar function to ReisX()
02701  * 
02702  * @param ss 
02703  * @param Zg 
02704  * @param xi 
02705  * @return 
02706  * 
02707  *@todo check that the units of the hardcoded constants are appropriate 
02708  *
02709  *
02710  *@todo document this function
02711  */
02712 double ReisX_g(int ss, atomicnumber Zg, double xi)
02713 {
02714   static double g3pol[2][8] = {
02715     { 4.980374404, -18.84795179, 37.53135546, -39.83029409, 23.94060788,
02716       -8.048533664, 1.397129084, -0.09706728869 },
02717     { -1.859600742, 12.30009972, -21.67920610, 20.38505540, -11.17032345,
02718       3.604521250, -0.6347055945, 0.04676377726 }
02719   };
02720 
02721   static double g12pol[2][8] = {
02722     { 0.7800031227, 0.5779760376, 0.01209015664, 1.382072250, -2.555731314,
02723       1.534786106, -0.3844825563, 0.03457310793 },
02724     { -4.910259919, 27.43184219, -50.44519949, 48.46725025, -26.40954176,
02725       8.230146858, -1.365807669, 0.09332547710 }
02726   };
02727 
02728   int i;
02729   int polsel = 0;
02730   double gaux = 0.0;
02731 
02732   if (xi < 0.6 || xi > 2.6)
02733     return(1.0);
02734   else {
02735     if (ss == 3) {
02736       if (Zg < 47)  return(1.0);
02737       
02738       if (Zg < 64) polsel = 0;
02739       else polsel = 1;        
02740       
02741       for (gaux = g3pol[polsel][7],i = 6; i >= 0; i--)  gaux = gaux * xi + g3pol[polsel][i];
02742       return(gaux);
02743     }
02744     if (ss == 1) {
02745       if (Zg > 61 && Zg < 72)  polsel = 0;
02746       else return(1.0);
02747     }
02748     if (ss == 2) {
02749       if (Zg > 54 && Zg < 75)   polsel = 1;
02750       else return(1.0);
02751     }
02752     
02753     for (gaux = g12pol[polsel][7], i = 6; i >= 0; i--)  gaux = gaux * xi + g12pol[polsel][i];
02754     return(gaux);
02755   }
02756 }
02757 
02758 
02759 /** Calculates a normalized "Penetration Integral" for a given X-ray emission line of a given element. 
02760 See "Reis et al. NIM B 109/110 (1996) 134-138"
02761 See section 1.4 of "Correccoes de Fluorescencia Secundaria em PIXE" Master Thesis by M.A. Reis
02762 
02763 It calculates the integral of eq. (4) of the cited paper except that it does not include the normalization constant "sigmaX_ij(Ep)"
02764 
02765   * 
02766   * @param atnumb (I) Atomic number of the target element
02767   * @param AbsFac (I) Absorption coefficients structure for the target element
02768   * @param ESA  (I) Pointer to Array of sublayers in the current layer.
02769   * @param YldA (I) Array of X-ray production cross section for the target element in each sublayer
02770   * @param TrsA (I) Array of Transmission coefs for the target element in each sublayer
02771   * @param pTrs0 (I) Array of Transmission factors due tolayers over the one we are considering.
02772   * @param FExlen (I) Number of sublayers in this layer
02773   * @param NeedSFC (I) Flag indicating whether secondary fluorescence should be calculated (1) or not (0)
02774   * @param AllowXEqCalc (I) Flag indicating whether "equivalent thickness" should be calculated (1) or not (0)
02775   * @param x0 (I) absolute in-going path length, in 1e15at/cm2, from sample surface (Only relevant if AllowXEqCalc=1)
02776   * @param CosInc Cosine of the incident angle (Only relevant if AllowXEqCalc=1)
02777   * @param XYld (O) Penetration integral results.
02778   * @param XSFCr (O) Correction factor applied due to secondary fluorescence  (Only relevant if NeedSFC=1)
02779   * @param XYldxmed (O) Equivalent thickness results (Only relevant if AllowXEqCalc=1)
02780 
02781 */
02782 void PenInteg(atomicnumber atnumb, const CalibYld *AbsFac, const ESxType *ESA,
02783         const CalibYld *YldA, const CalibYld *TrsA, const CalibYld *pTrs0, 
02784         int FExlen, int NeedSFC, int AllowXEqCalc,
02785         double x0, double CosInc,
02786         CalibYld *XYld, CalibYld *XSFCr, CalibYld *XYldxmed)
02787 {
02788   int i, j, l, limit;
02789   double auxfa, auxfb, auxfi, diffl;
02790   CalibYld auxxmed, auxy2;
02791   const CalibYld *pTrs1, *pYld1, *pSFC1, *pTrs2, *pYld2, *pSFC2, *pTrs3, *pYld3, *pSFC3;
02792   
02793   const ESxType *pEF1, *pEF2, *pEF3;
02794   
02795 /*  static const CalibYld CYldNul = { { 0.0, 0.0, 0.0, 0.0 },
02796                             { { 0.0, 0.0, 0.0, 0.0 },
02797                               { 0.0, 0.0, 0.0, 0.0 },
02798                               { 0.0, 0.0, 0.0, 0.0 },
02799                               { 0.0, 0.0, 0.0, 0.0 }},
02800                             { 0.0, 0.0, 0.0, 0.0 }};*/
02801         
02802   /*These variables need to be 0-initialized because they will be used for sumation*/
02803 
02804   *XYld=CYldNul;
02805   
02806   if(AllowXEqCalc) auxxmed = CYldNul;
02807   
02808   
02809   if (NeedSFC) {
02810     fprintf(stderr,"\n Error: Secondary Fluorescence not implemented yet\n"); exit(1);
02811     /*Note: when implementing Secondary fluorescence correction, 
02812     SFC1, SFC2 and SFC3 should be read here*/
02813     auxy2 = CYldNul;
02814     }
02815   else {
02816     pSFC1=&CYldNul;
02817     pSFC2=&CYldNul;
02818     pSFC3=&CYldNul;
02819   }
02820   
02821   pEF1=&ESA[0];
02822   pTrs1=&TrsA[0];
02823   pYld1=&YldA[0];
02824   
02825   /*Note: The following loop starts in 1 and ends 1 before the max to make possible
02826     the definition of Trs1, Trs2,Trs3 and so on. Also note that its step is 2*/
02827   limit=FExlen-1;
02828   for(i=1 ; i<limit ; i+=2){    
02829     
02830     pEF2=&ESA[i];
02831     pTrs2=&TrsA[i];
02832     pYld2=&YldA[i];
02833 
02834     pEF3=&ESA[i+1];
02835     pTrs3=&TrsA[i +1];
02836     pYld3=&YldA[i +1];
02837     
02838     if (atnumb < maxK) {
02839       for (j = 1; j <= 3; j++) {
02840         if (AbsFac->K_[j] > 0. && pTrs2->K_[j] > 1e-5) {
02841           
02842           auxfa = (pTrs1->K_[j] * pYld1->K_[j] + pSFC1->K_[j]) / pEF1->stpp;
02843           auxfi = (pTrs2->K_[j] * pYld2->K_[j] + pSFC2->K_[j]) / pEF2->stpp;
02844           auxfb = (pTrs3->K_[j] * pYld3->K_[j] + pSFC3->K_[j]) / pEF3->stpp;
02845           XYld->K_[j] -= pTrs0->K_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02846           #if CPIXEVERBOSITY > 1
02847           if(j==1) printf("\n Z=%d   XYld=%le  (XYld/Dx=%le)   x1=%le    ",
02848                           atnumb, pTrs0->K_[j] * 
02849                           Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb),
02850                           Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb)/(pEF1->x - pEF3->x),
02851                           pEF1->x);
02852           #endif
02853           ///@todo IMPORTANT: check here the use of cosInc in relation with the definition of x0
02854           if (AllowXEqCalc) {
02855             auxfa = (pTrs1->K_[j] * pYld1->K_[j] + pSFC1->K_[j]) * (pEF1->x + x0) * CosInc / pEF1->stpp;
02856             auxfi = (pTrs2->K_[j] * pYld2->K_[j] + pSFC2->K_[j]) * (pEF2->x + x0) * CosInc / pEF2->stpp;
02857             auxfb = (pTrs3->K_[j] * pYld3->K_[j] + pSFC3->K_[j]) * (pEF3->x + x0) * CosInc / pEF3->stpp;
02858             auxxmed.K_[j] -= pTrs0->K_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02859           }
02860           if (NeedSFC){
02861             auxfa = pSFC1->K_[j] / pEF1->stpp;
02862             auxfi = pSFC2->K_[j] / pEF2->stpp;
02863             auxfb = pSFC3->K_[j] / pEF3->stpp;
02864             auxy2.K_[j] -= pTrs0->K_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02865           }
02866         }
02867       }
02868     }
02869     if (atnumb > minM) {
02870       for (j = 1; j <= 3; j++) {
02871         if (AbsFac->M_[j] > 0. && pTrs2->M_[j] > 1e-5) {
02872           auxfa = (pTrs1->M_[j] * pYld1->M_[j] + pSFC1->M_[j]) / pEF1->stpp;
02873           auxfi = (pTrs2->M_[j] * pYld2->M_[j] + pSFC2->M_[j]) / pEF2->stpp;
02874           auxfb = (pTrs3->M_[j] * pYld3->M_[j] + pSFC3->M_[j]) / pEF3->stpp;
02875           XYld->M_[j] -= pTrs0->M_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02876           if (AllowXEqCalc) {
02877             auxfa = (pTrs1->M_[j] * pYld1->M_[j] + pSFC1->M_[j]) * (pEF1->x + x0) * CosInc / pEF1->stpp;
02878             auxfi = (pTrs2->M_[j] * pYld2->M_[j] + pSFC2->M_[j]) * (pEF2->x + x0) * CosInc / pEF2->stpp;
02879             auxfb = (pTrs3->M_[j] * pYld3->M_[j] + pSFC3->M_[j]) * (pEF3->x + x0) * CosInc / pEF3->stpp;
02880             auxxmed.M_[j] -= pTrs0->M_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02881           }
02882           if (NeedSFC){
02883             auxfa = pSFC1->M_[j] / pEF1->stpp;
02884             auxfb = pSFC2->M_[j] / pEF2->stpp;
02885             auxy2.M_[j] -= pTrs0->M_[j] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02886           }
02887         }
02888       }
02889     }
02890     if (atnumb > minL) {
02891       for (j = 1; j <= 3; j++) {
02892         for (l = 1; l <= 3; l++) {
02893           if (AbsFac->L_[j][l] > 0. && pTrs2->L_[j][l] > 1e-5) {
02894             auxfa = (pTrs1->L_[j][l] * pYld1->L_[j][l] + pSFC1->L_[j][l]) / pEF1->stpp;
02895             auxfi = (pTrs2->L_[j][l] * pYld2->L_[j][l] + pSFC2->L_[j][l]) / pEF2->stpp;
02896             auxfb = (pTrs3->L_[j][l] * pYld3->L_[j][l] + pSFC3->L_[j][l]) / pEF3->stpp;
02897             XYld->L_[j][l] -= pTrs0->L_[j][l] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02898             if (AllowXEqCalc) {
02899               auxfa = (pTrs1->L_[j][l] * pYld1->L_[j][l] + pSFC1->L_[j][l]) * (pEF1->x + x0) * CosInc / pEF1->stpp;
02900               auxfi = (pTrs2->L_[j][l] * pYld2->L_[j][l] + pSFC2->L_[j][l]) * (pEF2->x + x0) * CosInc / pEF2->stpp;
02901               auxfb = (pTrs3->L_[j][l] * pYld3->L_[j][l] + pSFC3->L_[j][l]) * (pEF3->x + x0) * CosInc / pEF3->stpp;
02902               auxxmed.L_[j][l] -= pTrs0->L_[j][l] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02903             }
02904             if (NeedSFC){
02905               auxfa = pSFC1->L_[j][l] / pEF1->stpp;
02906               auxfi = pSFC2->L_[j][l] / pEF2->stpp;
02907               auxfb = pSFC3->L_[j][l] / pEF3->stpp;
02908               diffl = 0.0;
02909               auxy2.L_[j][l] -= pTrs0->L_[j][l] * Simps(pEF1->ep, pEF3->ep, auxfa, auxfi, auxfb);
02910             }
02911           }
02912         }
02913       }
02914     }
02915     pYld1 = pYld3;
02916     pTrs1 = pTrs3;
02917     pEF1 = pEF3;
02918     pSFC1 = pSFC3;
02919   }
02920   
02921   if (NeedSFC) {
02922     for (i = 1; i <= 3; i++) {
02923       if (XYld->K_[i] > 0.)  XSFCr->K_[i] = auxy2.K_[i] / XYld->K_[i];
02924       if (XYld->M_[i] > 0.)  XSFCr->M_[i] = auxy2.M_[i] / XYld->M_[i];
02925       for (j = 1; j <= 3; j++) {
02926         if (XYld->L_[i][j] > 0.)  XSFCr->L_[i][j] = auxy2.L_[i][j] / XYld->L_[i][j];
02927       }
02928     }
02929   } 
02930   else  *XSFCr = CYldNul;
02931   
02932   if (AllowXEqCalc) {
02933     for (i = 1; i <= 3; i++) {
02934       if (XYld->K_[i] > 0.)  XYldxmed->K_[i] = auxxmed.K_[i] / XYld->K_[i];
02935       if (XYld->M_[i] > 0.)  XYldxmed->M_[i] = auxxmed.M_[i] / XYld->M_[i];
02936       for (j = 1; j <= 3; j++) {
02937         if (XYld->L_[i][j] > 0.)  XYldxmed->L_[i][j] = auxxmed.L_[i][j] / XYld->L_[i][j];
02938       }
02939     }
02940   }
02941   
02942   
02943 }
02944 
02945 
02946 /** Returns area of trapezoid, useful for Simpson Integration.
02947  *
02948  * See "Corrected Trapezoidal Rule" in 
02949  *    Conte & de Boor "Elementar Numerical Analysis" 3rd Ed. McGraw-Hill,1980,,p309
02950  *    ExpCTR:=(b-a)/2*(fa+fb)  
02951  *
02952  * @param a First point of the trapezoid base
02953  * @param b Second point of the Trapezoid base
02954  * @param fa 
02955  * @param fi 
02956  * @param fb 
02957  * @return 
02958  *
02959  *@todo IMPORTANT: Why the 6 and the 4??????? Has something to do with exponential function integration? If not, it should be rather: return(  (b-a)/4 * (fa+2*fi+fb)  ) 
02960  UPDATE: This has to do with the line in SSthick where "thick" is calculated.
02961  *
02962  *@todo document this function
02963  */
02964 double Simps(double a, double b, double fa, double fi, double fb)
02965 {
02966   
02967   return ((b - a) / 6. * (fa + 4. * fi + fb));
02968 }
02969 
02970 
02971 
02972 /*
02973 useFilter is a flag
02974 Filter is the filter struct
02975 */
02976 /**Calculates the yield values using the penetration integral results, i.e. Applies all the factors such as solid angle, atomic fraction, charge,... etc
02977 
02978 See eq. (1) of "Reis et al. NIM B 109/110 (1996) 134-138"
02979 
02980 @todo This function does not support M-lines
02981 @todo Note: This function is only valid for 10  Z2 in range [10,99]
02982  * 
02983  * @param pexp (I) Pointer to structure containing experimental parameters.
02984  * @param AbsC (I) Pointer to Absorption coef structure for element with Z2
02985  * @param pFCK (I) pointer to Fluorescence and Coster-Kronig coefficients for Z2
02986  * @param Z2 (I) atomic number of the target element
02987  * @param M2 (I) mass of the target element
02988  * @param attfraction (I) atomic fraction of the target element in the current layer
02989  * @param pXYld (I) Penetration integral values.
02990  * @param ResY (I+O) The calculated yields (in counts) for each layer will be returned in ResY->XYld
02991  * @param XYldSum (O) The total yield (sum for all layers processed up to this moment of ResY->XYld) is acumulated in XYldSum. 
02992  
02993  Note: deNormalize() returns both the partial and the total spectra through ResY->XYld and XYldSum, respectively.
02994  */
02995 void deNormalize(const EXP_PARAM *pexp, const AbsCoef *AbsC, const FluorCKCoef *pFCK, atomicnumber Z2, double M2, double attfraction, const CalibYld *pXYld, XrayYield *ResY, CalibYld *XYldSum)
02996 {
02997   double aux1;
02998   long jj, ll;
02999   CalibYld TransFact, Xaux;
03000   const SIM_PARAM *psim;
03001   
03002   psim=&pexp->simpar;
03003   
03004   /*Set the Transfererence factor of the filter (=1 in case no filter)*/
03005   if (psim->useFilter){
03006     ///@todo do this part when the filters are supported
03007     fprintf(stderr,"\n Error: Filters not implemented yet\n"); exit(1);
03008 //     for (jj = 1; jj <= 3; jj++) {
03009 //       if (ResY->ener.K_[jj] > 0) TransFact.K_[jj] = FiltTrs(psim->Filter, ResY->ener.K_[jj]);
03010 //       if (ResY->ener.M_[jj] > 0) TransFact.M_[jj] = FiltTrs(psim->Filter, ResY->ener.M_[jj]);
03011 //     }
03012 //     for (jj = 1; jj <= 3; jj++) {
03013 //       for (ll = 1; ll <= 3; ll++) {
03014 //         if (ResY->ener.L_[jj][ll] > 0) TransFact.L_[jj][ll] = FiltTrs(psim->Filter, ResY->ener.L_[jj][ll]);
03015 //       }
03016 //     }
03017   }
03018   else{
03019     for (jj = 1; jj <= 3; jj++) {
03020       TransFact.K_[jj] = 1.0;
03021       TransFact.M_[jj] = 1.0;
03022     }
03023     for (jj = 1; jj <= 3; jj++) {
03024       for (ll = 1; ll <= 3; ll++) TransFact.L_[jj][ll] = 1.0;
03025     }
03026   }
03027     
03028   Xprod(AbsC, pFCK, pexp->ion.Z, Z2, M2, psim->CalEner, &Xaux);
03029   
03030   switch (ResY->atnum) {
03031 
03032   case 10:///@todo Check hardcoded Z limits 
03033   case 11:
03034   case 12:
03035   case 13:
03036   case 14:
03037     if (Xaux.K_[1] > 0) {
03038       aux1 = ResY->XYld.K_[1] / Xaux.K_[1];
03039       ResY->XYld.K_[1] = pXYld->K_[1] * aux1 * psim->ColCharge * pexp->DetColFac * 
03040                          TransFact.K_[1] * psim->DTCC * attfraction;
03041       XYldSum->K_[1] +=ResY->XYld.K_[1];
03042     }
03043     break;
03044 
03045   case 54:
03046   case 55:
03047   case 56:
03048   case 57:
03049   case 58:
03050   case 59:
03051     for (jj = 1; jj <= 3; jj++) {
03052       for (ll = 1; ll <= 3; ll++) {
03053         if (Xaux.L_[jj][ll] > 0){
03054           ResY->XYld.L_[jj][ll] = pXYld->L_[jj][ll] * (ResY->XYld.L_[jj][ll] / Xaux.L_[jj][ll]) *
03055                                   psim->ColCharge * pexp->DetColFac * TransFact.L_[jj][ll] *
03056                                   psim->DTCC * attfraction;
03057           XYldSum->L_[jj][ll] += ResY->XYld.L_[jj][ll];
03058         }
03059       }
03060     }
03061     break;
03062 
03063   default:
03064     if (ResY->atnum >= 15 && ResY->atnum <minL) {///@todo Check hardcoded Z limits 
03065       for (jj = 1; jj <= 2; jj++) {
03066         if (Xaux.K_[jj] > 0) {
03067           aux1 = ResY->XYld.K_[jj] / Xaux.K_[jj];
03068           ResY->XYld.K_[jj] = pXYld->K_[jj] * aux1 * psim->ColCharge *
03069                               pexp->DetColFac * TransFact.K_[jj] * psim->DTCC * attfraction;
03070           XYldSum->K_[jj] +=ResY->XYld.K_[jj];
03071         }
03072       }
03073     } 
03074     else if (ResY->atnum >= minL && ResY->atnum < maxK) {
03075       for (jj = 1; jj <= 3; jj++) {
03076         if (Xaux.K_[jj] > 0) {
03077           aux1 = ResY->XYld.K_[jj] / Xaux.K_[jj];
03078           ResY->XYld.K_[jj] = pXYld->K_[jj] * aux1 * psim->ColCharge * 
03079                               pexp->DetColFac * TransFact.K_[jj] * psim->DTCC * attfraction;
03080           XYldSum->K_[jj] +=ResY->XYld.K_[jj];
03081         }
03082       }
03083       for (jj = 1; jj <= 3; jj++) {
03084         for (ll = 1; ll <= 3; ll++) {
03085           if (Xaux.L_[jj][ll] > 0){
03086             ResY->XYld.L_[jj][ll] = pXYld->L_[jj][ll] * (ResY->XYld.L_[jj][ll] / Xaux.L_[jj][ll]) *
03087                                     psim->ColCharge * pexp->DetColFac * TransFact.L_[jj][ll] * 
03088                                     psim->DTCC * attfraction;
03089             XYldSum->L_[jj][ll] +=ResY->XYld.L_[jj][ll];
03090           }
03091         }
03092       }
03093     } 
03094     else if (ResY->atnum >= minM && ResY->atnum <= 99) {///@todo Check hardcoded Z limits 
03095       for (jj = 1; jj <= 3; jj++) {
03096         for (ll = 1; ll <= 3; ll++) {
03097           if (Xaux.L_[jj][ll] > 0){
03098             ResY->XYld.L_[jj][ll] = pXYld->L_[jj][ll] * (ResY->XYld.L_[jj][ll] / Xaux.L_[jj][ll]) *
03099                                     psim->ColCharge * pexp->DetColFac * TransFact.L_[jj][ll] * 
03100                                      psim->DTCC * attfraction;
03101             XYldSum->L_[jj][ll] +=ResY->XYld.L_[jj][ll];
03102           }
03103         }
03104       }
03105       /**@todo Support also M lines here*/
03106     }
03107     break;
03108   }
03109 }
03110 
03111 
03112 
03113 
03114 
03115 
03116 
03117 
03118 /** Frees all memory allocated for the filter structure.
03119  * 
03120  * @param Filter (I+O) Pointer to filter structure.
03121  */
03122 void freeFilter(FILTER *Filter)
03123 {
03124   int i;
03125   foil *pFoil;
03126   
03127   for(i=0 ; i < Filter->nlyr ; i++){
03128     pFoil=&Filter->foil[i];
03129     safefree((void*)(&pFoil->comp.elem));
03130     safefree((void*)(&pFoil->comp.X));
03131     safefree((void*)(&pFoil->comp.xn));
03132     safefree((void*)(&pFoil->comp.w));
03133     
03134   }
03135   safefree((void*)(&Filter->FilterElems));
03136   safefree((void*)(&Filter->foil));
03137   safefree((void*)(&Filter->Trans));
03138     
03139 }
03140 
03141 /**Frees the space  allocated for arrays that are to be reused in subsequent iterations
03142  * 
03143  * @param NFoils (I)  Number of target foils
03144  * @param plyrarray (I+O)  Pointer to array of layers. Dim=NFoils+1
03145  * @param MatArray (I+O)  Pointer to array of foils. Dim=NFoils
03146  * @param XYldSums (I+O)  Pointer to the Output Array of summed X-Ray Yields
03147  */
03148 void freeReusable(int NFoils, LYR **plyrarray, foil **MatArray, CalibYld **XYldSums)
03149 {
03150   int i;
03151   LYR *plyr;
03152   foil *pMat;
03153   
03154   /*Clean the layer array and the Sample Array as well as all its members which have been allocated*/
03155   for(i=1;i<=NFoils;i++){
03156     plyr=&(*plyrarray)[i];
03157     safefree((void*)(&plyr->TrcAtnum));
03158     safefree((void*)(&plyr->Trans));
03159 //     safefree((void*)(&plyr->AreasArray));
03160     safefree((void*)(&plyr->ResYldArray));
03161     safefree((void*)(&plyr->SecResArray));
03162     safefree((void*)(&plyr->TrcUse));
03163     safefree((void*)(&plyr->NeedSFC));
03164     safefree((void*)(&plyr->ESxArray));
03165     safefree((void*)(&plyr->SSTrsArray));
03166     safefree((void*)(&plyr->SSYldArray));
03167 
03168     
03169     pMat=&(*MatArray)[i-1];
03170     safefree((void*)(&pMat->comp.elem));
03171     safefree((void*)(&pMat->comp.X));
03172     safefree((void*)(&pMat->comp.xn));
03173     safefree((void*)(&pMat->comp.w));
03174     
03175   }
03176    safefree((void*)plyrarray);
03177 
03178    safefree((void*)MatArray);
03179    
03180    safefree((void*)XYldSums);
03181 }
03182 
03183 
03184 /**Frees memory only if *ptr is not NULL
03185  * 
03186  * @param ptr (I+O) Pointer to array to be freed
03187  */
03188 void safefree(void **ptr){
03189   if(*ptr!=NULL){
03190     //printf("\nDEBUG: freing %x ...",*ptr);fflush(stdout);
03191     free(*ptr);
03192     //printf(" done (%x)",*ptr);fflush(stdout);
03193     *ptr=NULL;
03194   }
03195 }
03196 
03197 
03198 /**Prints a CalibYld structure on a given stream
03199  * 
03200  * @param f (I+O) Stream to which the structure is printed 
03201  * @param pCYld (I) Structure to print
03202  */
03203 void fprintCALIBYLD(FILE *f,const CalibYld *pCYld)
03204 { 
03205   int j,l;
03206   for (j = 1; j <= 3; j++) fprintf(f,"\t%le",pCYld->K_[j]);
03207   for (j = 1; j <= 3; j++) { 
03208     fprintf(f,"\n");
03209     for (l = 1; l <= 3; l++)fprintf(f,"\t%le",pCYld->L_[j][l]);
03210   }
03211   fprintf(f,"\n");
03212   for (j = 1; j <= 3; j++) fprintf(f,"\t%le",pCYld->M_[j]);
03213   
03214   fprintf(f,"\n");
03215 }
03216 
03217 /**Reads a CalibYld structure from a given stream. The expected format is that as printed by fprintCALIBYLD
03218  * 
03219  * @param f (I) Stream from which the structure is read 
03220  * @param pCYld (O) Structure to store the read values
03221  */
03222 void fscanCALIBYLD(FILE *f, CalibYld *pCYld)
03223 { 
03224   int j,l;
03225   for (j = 1; j <= 3; j++) fscanf(f,"%lf",&pCYld->K_[j]);
03226   for (j = 1; j <= 3; j++) { 
03227     for (l = 1; l <= 3; l++)fscanf(f,"%lf",&pCYld->L_[j][l]);
03228   }
03229   for (j = 1; j <= 3; j++) fscanf(f,"%lf",&pCYld->M_[j]);
03230   
03231 }
03232 

Generated on Fri Jul 15 20:43:49 2005 for LibCPIXE API by  doxygen 1.3.9.1