00001 
00002 
00003 #include <ctype.h>
00004 #include "cddefines.h"
00005 #include "elementnames.h"
00006 #include "physconst.h"
00007 #include "dense.h"
00008 #include "called.h"
00009 #include "version.h"
00010 #include "grainvar.h"
00011 #include "rfield.h"
00012 #include "atmdat.h"
00013 #include "grains.h"
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 static const long MAGIC_RFI = 1030103L;
00038 static const long MAGIC_SZD = 2010403L;
00039 static const long MAGIC_OPC = 3030307L;
00040 static const long MAGIC_MIX = 4030103L;
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 static const double SMALLEST_GRAIN = 0.0001*(1.-10.*DBL_EPSILON);
00051 static const double LARGEST_GRAIN = 10.*(1.+10.*DBL_EPSILON);
00052 
00053 
00054 static const int NSD = 7;
00055 
00056 
00057 
00058 static const int ipSize  = 0; 
00059 static const int ipBLo   = 0; 
00060 static const int ipBHi   = 1; 
00061 static const int ipExp   = 2; 
00062 static const int ipBeta  = 3; 
00063 static const int ipSLo   = 4; 
00064 static const int ipSHi   = 5; 
00065 static const int ipAlpha = 6; 
00066 static const int ipGCen  = 2; 
00067 static const int ipGSig  = 3; 
00068 
00069 
00070 typedef enum {
00071         RFI_TABLE, OPC_TABLE, OPC_GREY, OPC_PAH1
00072 } rfi_type;
00073 
00074 
00075 typedef enum {
00076         FARAFONOV00, STOGNIENKO95, BRUGGEMAN35
00077 } emt_type;
00078 
00079 
00080 typedef enum {
00081         SD_ILLEGAL, SD_SINGLE_SIZE, SD_POWERLAW, SD_EXP_CUTOFF1, SD_EXP_CUTOFF2,
00082         SD_EXP_CUTOFF3, SD_LOG_NORMAL, SD_LIN_NORMAL, SD_TABLE
00083 } sd_type;
00084 
00085 typedef struct {
00086         double a[NSD];    
00087         double lim[2];    
00088         double clim[2];   
00089         double *xx;       
00090         double *aa;       
00091         double *rr;       
00092         double *ww;       
00093         double unity;     
00094         double unity_bin; 
00095         double cSize;     
00096         double radius;    
00097         double area;      
00098         double vol;       
00099         double *ln_a;     
00100         double *ln_a4dNda;
00101         sd_type sdCase;   
00102         long int magic;   
00103         long int cPart;   
00104         long int nPart;   
00105         long int nmul;    
00106         long int nn;      
00107         long int npts;    
00108         bool lgLogScale;  
00109 } sd_data;
00110 
00111 
00112 static const int NAX = 3;
00113 static const int NDAT = 4;
00114 
00115 typedef struct {
00116         double *wavlen[NAX];    
00117         complex<double> *n[NAX];
00118         double *nr1[NAX];       
00119         double *opcAnu;         
00120         double *opcData[NDAT];  
00121         double wt[NAX];         
00122         double abun;            
00123         double depl;            
00124         double elmAbun[LIMELM]; 
00125         double mol_weight;      
00126         double atom_weight;     
00127         double rho;             
00128         double norm;            
00129         double work;            
00130         double bandgap;         
00131         double therm_eff;       
00132         double subl_temp;       
00133         long int magic;         
00134         long int cAxis;         
00135         long int nAxes;         
00136         long int ndata[NAX];    
00137         long int nOpcCols;      
00138         long int nOpcData;      
00139         mat_type matType;       
00140         rfi_type rfiType;       
00141 } grain_data;
00142 
00143 
00144 
00145 
00146 
00147 static const int WORDLEN = 5;
00148 
00149 
00150 static const int LABELSUB1 = 3;
00151 static const int LABELSUB2 = 5;
00152 static const int LABELSIZE = LABELSUB1 + LABELSUB2 + 4;
00153 
00154 
00155 static const long MIX_TABLE_SIZE = 2000L;
00156 
00157 STATIC void mie_auxiliary(sd_data*,const char*);
00158 STATIC void mie_integrate(sd_data*,double,double,double*,bool);
00159 STATIC void mie_cs_size_distr(double,sd_data*,grain_data*,
00160                               void(*)(double,sd_data*,grain_data*,double*,
00161                                       double*,double*,int*),
00162                               double*,double*,double*,int*);
00163 STATIC void mie_cs(double,sd_data*,grain_data*,double*,double*,
00164                    double*,int*);
00165 STATIC void pah1_fun(double,sd_data*,grain_data*,double*,double*,
00166                      double*,int*);
00167 STATIC void tbl_fun(double,sd_data*,grain_data*,double*,double*,
00168                     double*,int*);
00169 STATIC double size_distr(double,sd_data*);
00170 STATIC double search_limit(double,double,double,sd_data);
00171 STATIC void mie_calc_ial(grain_data*,long,double[],const char*,bool*);
00172 STATIC void mie_repair(const char*,long,int,int,realnum[],double[],int[],
00173                        bool,bool*);
00174 STATIC double mie_find_slope(const realnum[],const double[],const int[],
00175                              long,long,int,bool,bool*);
00176 STATIC void mie_read_rfi(const char*,grain_data*);
00177 STATIC void mie_read_mix(const char*,grain_data*);
00178 STATIC void init_eps(double,long,grain_data[],complex<double>[]);
00179 STATIC complex<double> cnewton(
00180         void(*)(complex<double>,double[],complex<double>[],long,complex<double>*,double*,double*),
00181         double[],complex<double>[],long,complex<double>,double);
00182 STATIC void Stognienko(complex<double>,double[],complex<double>[],long,complex<double>*,double*,double*);
00183 STATIC void Bruggeman(complex<double>,double[],complex<double>[],long,complex<double>*,double*,double*);
00184 STATIC void mie_read_szd(const char*,sd_data*);
00185 STATIC void mie_read_long(const char*,const char[],long int*,bool,long int);
00186 STATIC void mie_read_realnum(const char*,const char[],realnum*,bool,long int);
00187 STATIC void mie_read_double(const char*,const char[],double*,bool,long int);
00188 STATIC void mie_read_form(const char*,double[],double*,double*);
00189 STATIC void mie_write_form(const double[],char[]);
00190 STATIC void mie_read_word(const char[],char[],long,int);
00191 STATIC void mie_next_data(const char*,FILE*,char*,long int*);
00192 STATIC void mie_next_line(const char*,FILE*,char*,long int*);
00193 
00194 
00195 
00196 
00197 STATIC void sinpar(double,double,double,double*,double*,double*,
00198                    double*,double*,long*);
00199 STATIC void anomal(double,double*,double*,double*,double*,double,double);
00200 STATIC void bigk(complex<double>,complex<double>*);
00201 STATIC void ritodf(double,double,double*,double*);
00202 STATIC void dftori(double*,double*,double,double);
00203 
00204 
00205 
00206 
00207 
00208 void mie_write_opc( const char *rfi_file,
00209                     const char *szd_file,
00210                    long int nbin)
00211 {
00212         int Error = 0,
00213                 
00214           *ErrorIndex;
00215         bool lgErr,
00216           lgErrorOccurred,
00217           lgWarning;
00218         long int i,
00219           j,
00220           nelem,
00221           p;
00222         double **acs_abs,
00223           **acs_sct,
00224           **a1g,
00225           *inv_att_len,
00226           cosb,
00227           cs_abs,
00228           cs_sct,
00229           volfrac,
00230           volnorm,
00231           wavlen;
00232         char chGrainLabel[LABELSIZE+1],
00233           ext[3],
00234           chFile[FILENAME_PATH_LENGTH_2],
00235           chFile2[FILENAME_PATH_LENGTH_2],
00236           hlp1[LABELSUB1+2],
00237           hlp2[LABELSUB2+2],
00238           *str,
00239           chString[FILENAME_PATH_LENGTH_2];
00240         sd_data sd;
00241         grain_data gd,
00242           gd2;
00243         time_t timer;
00244         FILE *fdes;
00245 
00246 
00247         
00248         const long NPTS_TABLE = 100L;
00249 
00250         DEBUG_ENTRY( "mie_write_opc()" );
00251 
00252         
00253         ErrorIndex = (int*)MALLOC(sizeof(int)*(unsigned)rfield.nupper);
00254 
00255         gd.nAxes = 0;
00256         for( j=0; j < NAX; j++ ) 
00257         {
00258                 gd.wavlen[j] = NULL;
00259                 gd.n[j] = NULL;
00260                 gd.nr1[j] = NULL;
00261         }
00262         gd.nOpcCols = 0;
00263         gd.opcAnu = NULL;
00264         for( j=0; j < NDAT; j++ )
00265         {
00266                 gd.opcData[j] = NULL;
00267         }
00268         gd2.nAxes = 0;
00269         for( j=0; j < NAX; j++ ) 
00270         {
00271                 gd2.wavlen[j] = NULL;
00272                 gd2.n[j] = NULL;
00273                 gd2.nr1[j] = NULL;
00274         }
00275         gd2.nOpcCols = 0;
00276         gd2.opcAnu = NULL;
00277         for( j=0; j < NDAT; j++ )
00278         {
00279                 gd2.opcData[j] = NULL;
00280         }
00281         sd.ln_a = NULL;
00282         sd.ln_a4dNda = NULL;
00283 
00284         mie_read_szd( szd_file , &sd );
00285 
00286         sd.nPart = ( sd.sdCase == SD_SINGLE_SIZE ) ? 1 : nbin;
00287         if( sd.nPart <= 0 || sd.nPart >= 100 ) 
00288         {
00289                 fprintf( ioQQQ, " Illegal number of size distribution bins: %ld\n",sd.nPart );
00290                 fprintf( ioQQQ, " The number should be between 1 and 99.\n" );
00291                 cdEXIT(EXIT_FAILURE);
00292         }
00293         sd.lgLogScale = true;
00294 
00295         string rfi_string ( rfi_file );
00296         if( rfi_string.find( ".rfi" ) != string::npos )
00297         {
00298                 mie_read_rfi( rfi_file , &gd );
00299         }
00300         else if( rfi_string.find( ".mix" ) != string::npos )
00301         {
00302                 mie_read_mix( rfi_file , &gd );
00303         }
00304         else
00305         {
00306                 fprintf( ioQQQ, " Refractive index file name %s has wrong extention\n", rfi_file );
00307                 fprintf( ioQQQ, " It should have extention .rfi or .mix.\n" );
00308                 cdEXIT(EXIT_FAILURE);
00309         }
00310 
00311         if( gd.rfiType == OPC_TABLE && sd.nPart > 1 )
00312         {
00313                 fprintf( ioQQQ, " Illegal number of size distribution bins: %ld\n",sd.nPart );
00314                 fprintf( ioQQQ, " The number should always be 1 for OPC_TABLE files.\n" );
00315                 cdEXIT(EXIT_FAILURE);
00316         }
00317         if( gd.rho <= 0. )
00318         {
00319                 fprintf( ioQQQ, " Illegal value for the specific density: %.4e\n",gd.rho );
00320                 cdEXIT(EXIT_FAILURE);
00321         }
00322         if( gd.mol_weight <= 0. )
00323         {
00324                 fprintf( ioQQQ, " Illegal value for the molecular weight: %.4e\n",gd.mol_weight );
00325                 cdEXIT(EXIT_FAILURE);
00326         }
00327 
00328         lgWarning = false;
00329 
00330         
00331         strcpy(chFile,rfi_file);
00332         str = strstr(chFile,".");
00333 
00334         if( str != NULL )
00335                 *str = '\0';
00336 
00337         strcpy(chFile2,szd_file);
00338         str = strstr(chFile2,".");
00339 
00340         if( str != NULL )
00341                 *str = '\0';
00342 
00343         if( sd.sdCase != SD_SINGLE_SIZE ) 
00344         {
00345                 sprintf(ext,"%02ld",nbin);
00346                 strcat(strcat(strcat(strcat(strcat(chFile,"_"),chFile2),"_"),ext),".opc");
00347         }
00348         else 
00349         {
00350                 strcat(strcat(strcat(chFile,"_"),chFile2),".opc");
00351         }
00352 
00353         fprintf( ioQQQ, "\n Starting mie_write_opc, output will be written to %s\n\n",chFile );
00354 
00355         mie_auxiliary(&sd,"init");
00356 
00357         
00358         gd.norm = sd.vol*gd.rho/(ATOMIC_MASS_UNIT*gd.mol_weight*gd.abun*gd.depl);
00359         volnorm = sd.vol;
00360         volfrac = 1.;
00361 
00362         acs_abs = (double **)MALLOC(sizeof(double *)*(unsigned)sd.nPart);
00363         acs_sct = (double **)MALLOC(sizeof(double *)*(unsigned)sd.nPart);
00364         a1g = (double **)MALLOC(sizeof(double *)*(unsigned)sd.nPart);
00365         inv_att_len = (double *)MALLOC(sizeof(double)*(unsigned)rfield.nupper);
00366 
00367         for( p=0; p < sd.nPart; p++ ) 
00368         {
00369                 acs_abs[p] = (double *)MALLOC(sizeof(double)*(unsigned)rfield.nupper);
00370                 acs_sct[p] = (double *)MALLOC(sizeof(double)*(unsigned)rfield.nupper);
00371                 a1g[p] = (double *)MALLOC(sizeof(double)*(unsigned)rfield.nupper);
00372         }
00373 
00374         fdes = open_data( chFile, "w", AS_LOCAL_ONLY );
00375         lgErr = false;
00376 
00377         (void)time(&timer);
00378         lgErr = lgErr || ( fprintf(fdes,"# this file was created by Cloudy %s (%s) on %s",
00379                                    t_version::Inst().chVersion,t_version::Inst().chDate,ctime(&timer)) < 0 );
00380         lgErr = lgErr || ( fprintf(fdes,"# ===========================================\n#\n") < 0 );
00381         lgErr = lgErr || ( fprintf(fdes,"%12ld # magic number opacity file\n",MAGIC_OPC) < 0 );
00382         lgErr = lgErr || ( fprintf(fdes,"%12ld # magic number rfi/mix file\n",gd.magic) < 0 );
00383         lgErr = lgErr || ( fprintf(fdes,"%12ld # magic number szd file\n",sd.magic) < 0 );
00384 
00385         
00386 
00387         strncpy(hlp1,chFile,(size_t)(LABELSUB1+1));
00388         hlp1[LABELSUB1+1] = '\0';
00389         str = strstr(hlp1,"-");
00390 
00391         if( str != NULL )
00392                 *str = '\0';
00393 
00394         strncpy(hlp2,chFile2,(size_t)(LABELSUB2+1));
00395         hlp2[LABELSUB2+1] = '\0';
00396         str = strstr(hlp2,"-");
00397 
00398         if( str != NULL )
00399                 *str = '\0';
00400 
00401         strcpy(chGrainLabel," ");
00402         if( sd.nPart > 1 ) 
00403         {
00404                 hlp1[LABELSUB1] = '\0';
00405                 hlp2[LABELSUB2] = '\0';
00406                 strcat(strcat(strcat(strcat(chGrainLabel,hlp1),"-"),hlp2),"xx");
00407                 lgErr = lgErr || ( fprintf(fdes,"%-12.12s # grain type label, xx will be replaced by bin no.\n",
00408                                            chGrainLabel) < 0 );
00409         }
00410         else 
00411         {
00412                 strcat(strcat(strcat(chGrainLabel,hlp1),"-"),hlp2);
00413                 lgErr = lgErr || ( fprintf(fdes,"%-12.12s # grain type label\n", chGrainLabel) < 0 );
00414         }
00415 
00416         lgErr = lgErr || ( fprintf(fdes,"%.6e # specific weight (g/cm^3)\n",gd.rho) < 0 );
00417         lgErr = lgErr || ( fprintf(fdes,"%.6e # molecular weight of grain molecule (amu)\n",gd.mol_weight) < 0 );
00418         lgErr = lgErr || ( fprintf(fdes,"%.6e # average molecular weight per atom (amu)\n", gd.atom_weight) < 0 );
00419         lgErr = lgErr || ( fprintf(fdes,"%.6e # abundance of grain molecule at max depletion\n",gd.abun) < 0 );
00420         lgErr = lgErr || ( fprintf(fdes,"%.6e # depletion efficiency\n",gd.depl) < 0 );
00421         lgErr = lgErr || ( fprintf(fdes,"%.6e # average grain radius <a^3>/<a^2>, full size distr (cm)\n",
00422                            3.*sd.vol/sd.area) < 0 );
00423         lgErr = lgErr || ( fprintf(fdes,"%.6e # average grain surface area <4pi*a^2>, full size distr (cm^2)\n",
00424                            sd.area) < 0 );
00425         lgErr = lgErr || ( fprintf(fdes,"%.6e # average grain volume <4/3pi*a^3>, full size distr (cm^3)\n",
00426                            sd.vol) < 0 );
00427         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain radius Int(a) per H, full size distr (cm/H)\n",
00428                            sd.radius/gd.norm) < 0 );
00429         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain area Int(4pi*a^2) per H, full size distr (cm^2/H)\n",
00430                            sd.area/gd.norm) < 0 );
00431         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain vol Int(4/3pi*a^3) per H, full size distr (cm^3/H)\n",
00432                            sd.vol/gd.norm) < 0 );
00433         lgErr = lgErr || ( fprintf(fdes,"%.6e # work function (Ryd)\n",gd.work) < 0 );
00434         lgErr = lgErr || ( fprintf(fdes,"%.6e # gap between valence and conduction band (Ryd)\n",gd.bandgap) < 0 );
00435         lgErr = lgErr || ( fprintf(fdes,"%.6e # efficiency of thermionic emission\n",gd.therm_eff) < 0 );
00436         lgErr = lgErr || ( fprintf(fdes,"%.6e # sublimation temperature (K)\n",gd.subl_temp) < 0 );
00437         lgErr = lgErr || ( fprintf(fdes,"%12d # material type, 1=carbonaceous, 2=silicate\n",gd.matType) < 0 );
00438         lgErr = lgErr || ( fprintf(fdes,"#\n# abundances of constituent elements rel. to hydrogen\n#\n") < 0 );
00439 
00440         for( nelem=0; nelem < LIMELM; nelem++ ) 
00441         {
00442                 lgErr = lgErr || ( fprintf(fdes,"%.6e # %s\n",gd.elmAbun[nelem],
00443                                            elementnames.chElementSym[nelem]) < 0 );
00444         }
00445 
00446         if( sd.sdCase != SD_SINGLE_SIZE )
00447         {
00448                 lgErr = lgErr || ( fprintf(fdes,"#\n# entire size distribution, amin=%.5f amax=%.5f micron\n",
00449                                            sd.lim[ipBLo],sd.lim[ipBHi]) < 0 );
00450                 lgErr = lgErr || ( fprintf(fdes,"#\n%.6e # ratio a_max/a_min in each size bin\n",
00451                                            pow(sd.lim[ipBHi]/sd.lim[ipBLo],1./(double)sd.nPart) ) < 0 );
00452                 lgErr = lgErr || ( fprintf(fdes,"#\n# size distribution function\n#\n") < 0 );
00453                 lgErr = lgErr || ( fprintf(fdes,"%12ld # number of table entries\n#\n",NPTS_TABLE+1) < 0 );
00454                 lgErr = lgErr || ( fprintf(fdes,"# ============================\n") < 0 );
00455                 lgErr = lgErr || ( fprintf(fdes,"# size (micr) a^4*dN/da (cm^3/H)\n#\n") < 0 );
00456                 for( i=0; i <= NPTS_TABLE; i++ )
00457                 {
00458                         double radius, a4dNda;
00459                         radius = sd.lim[ipBLo]*exp((double)i/(double)NPTS_TABLE*log(sd.lim[ipBHi]/sd.lim[ipBLo]));
00460                         radius = MAX2(MIN2(radius,sd.lim[ipBHi]),sd.lim[ipBLo]);
00461                         a4dNda = POW4(radius)*size_distr(radius,&sd)/gd.norm*1.e-12/sd.unity;
00462                         lgErr = lgErr || ( fprintf(fdes,"%.6e %.6e\n",radius,a4dNda) < 0 );
00463                 }
00464         }
00465         else
00466         {
00467                 lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00468                 lgErr = lgErr || ( fprintf(fdes,"%.6e # a_max/a_min = 1 for single sized grain\n", 1. ) < 0 );
00469                 lgErr = lgErr || ( fprintf(fdes,"%12ld # no size distribution table\n",0L) < 0 );
00470         }
00471 
00472         lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00473         lgErr = lgErr || ( fprintf(fdes,"%12ld # rfield.nupper\n",rfield.nupper) < 0 );
00474         lgErr = lgErr || ( fprintf(fdes,"%12ld # number of size distr. bins\n#\n",sd.nPart) < 0 );
00475 
00476         for( p=0; p < sd.nPart; p++ ) 
00477         {
00478                 sd.cPart = p;
00479 
00480                 mie_auxiliary(&sd,"step");
00481 
00482                 if( sd.nPart > 1 ) 
00483                 {
00484                         
00485 
00486 
00487 
00488 
00489                         double frac = sd.unity_bin/sd.unity;
00490                         volfrac = sd.vol*frac/volnorm;
00491                         fprintf( ioQQQ, " Starting size bin %ld, amin=%.5f amax=%.5f micron\n",
00492                                  p+1,sd.clim[ipBLo],sd.clim[ipBHi] );
00493                         lgErr = lgErr || ( fprintf(fdes,"# size bin %ld, amin=%.5f amax=%.5f micron\n",
00494                                                    p+1,sd.clim[ipBLo],sd.clim[ipBHi]) < 0 );
00495                         lgErr = lgErr || ( fprintf(fdes,"%.6e # average grain ",3.*sd.vol/sd.area) < 0 );
00496                         lgErr = lgErr || ( fprintf(fdes,"radius <a^3>/<a^2>, this bin (cm)\n") < 0 );
00497                         lgErr = lgErr || ( fprintf(fdes,"%.6e # average ",sd.area) < 0 );
00498                         lgErr = lgErr || ( fprintf(fdes,"grain area <4pi*a^2>, this bin (cm^2)\n") < 0 );
00499                         lgErr = lgErr || ( fprintf(fdes,"%.6e # average ",sd.vol) < 0 );
00500                         lgErr = lgErr || ( fprintf(fdes,"grain volume <4/3pi*a^3>, this bin (cm^3)\n") < 0 );
00501                         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain ",sd.radius*frac/gd.norm) < 0 );
00502                         lgErr = lgErr || ( fprintf(fdes,"radius Int(a) per H, this bin (cm/H)\n") < 0 );
00503                         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain area ",sd.area*frac/gd.norm) < 0 );
00504                         lgErr = lgErr || ( fprintf(fdes,"Int(4pi*a^2) per H, this bin (cm^2/H)\n") < 0 );
00505                         lgErr = lgErr || ( fprintf(fdes,"%.6e # total grain volume ",sd.vol*frac/gd.norm) < 0 );
00506                         lgErr = lgErr || ( fprintf(fdes,"Int(4/3pi*a^3) per H, this bin (cm^3/H)\n#\n") < 0 );
00507                 }
00508 
00509                 lgErrorOccurred = false;
00510 
00511                 
00512                 for( i=0; i < rfield.nupper; i++ ) 
00513                 {
00514                         wavlen = WAVNRYD/rfield.anu[i]*1.e4;
00515 
00516                         switch( gd.rfiType )
00517                         {
00518                         case RFI_TABLE:
00519                                 ErrorIndex[i] = 0;
00520                                 acs_abs[p][i] = 0.;
00521                                 acs_sct[p][i] = 0.;
00522                                 a1g[p][i] = 0.;
00523 
00524                                 for( gd.cAxis=0; gd.cAxis < gd.nAxes; gd.cAxis++ ) 
00525                                 {
00526                                         mie_cs_size_distr(wavlen,&sd,&gd,mie_cs,&cs_abs,&cs_sct,&cosb,&Error);
00527                                         ErrorIndex[i] = MAX2(ErrorIndex[i],Error);
00528                                         acs_abs[p][i] += cs_abs*gd.wt[gd.cAxis];
00529                                         acs_sct[p][i] += cs_sct*gd.wt[gd.cAxis];
00530                                         a1g[p][i] += cs_sct*(1.-cosb)*gd.wt[gd.cAxis];
00531                                 }
00532 
00533                                 if( ErrorIndex[i] > 0 ) 
00534                                 {
00535                                         ErrorIndex[i] = MIN2(ErrorIndex[i],2);
00536                                         lgErrorOccurred = true;
00537                                 }
00538 
00539                                 switch( ErrorIndex[i] ) 
00540                                 {
00541                                 
00542                                 case 2:
00543                                         acs_abs[p][i] = 0.;
00544                                         acs_sct[p][i] = 0.;
00545                                         
00546                                         
00547                                 case 1:
00548                                         a1g[p][i] = 0.;
00549                                         break;
00550                                 
00551                                 case 0:
00552                                         a1g[p][i] /= acs_sct[p][i];
00553                                         break;
00554                                 default:
00555                                         fprintf( ioQQQ, " Insane value for ErrorIndex: %d\n", ErrorIndex[i] );
00556                                         ShowMe();
00557                                         cdEXIT(EXIT_FAILURE);
00558                                 }
00559 
00560                                 
00561                                 if( ErrorIndex[i] < 2 )
00562                                         ASSERT( acs_abs[p][i] > 0. && acs_sct[p][i] > 0. );
00563                                 if( ErrorIndex[i] < 1 )
00564                                         ASSERT( a1g[p][i] > 0. );
00565                                 break;
00566                         case OPC_TABLE:
00567                                 
00568                                 gd.cAxis = 0;
00569                                 mie_cs_size_distr(wavlen,&sd,&gd,tbl_fun,&cs_abs,&cs_sct,&cosb,&Error);
00570                                 ErrorIndex[i] = MIN2(Error,2);
00571                                 lgErrorOccurred = lgErrorOccurred || ( Error > 0 );
00572                                 acs_abs[p][i] = cs_abs*gd.norm;
00573                                 acs_sct[p][i] = cs_sct*gd.norm;
00574                                 a1g[p][i] = 1.-cosb;
00575                                 break;
00576                         case OPC_GREY:
00577                                 ErrorIndex[i] = 0;
00578                                 acs_abs[p][i] = 1.3121e-23*volfrac*gd.norm;
00579                                 acs_sct[p][i] = 2.6242e-23*volfrac*gd.norm;
00580                                 a1g[p][i] = 1.;
00581                                 break;
00582                         case OPC_PAH1:
00583                                 
00584                                 gd.cAxis = 0;
00585                                 mie_cs_size_distr(wavlen,&sd,&gd,pah1_fun,&cs_abs,&cs_sct,&cosb,&Error);
00586                                 ErrorIndex[i] = MIN2(Error,2);
00587                                 lgErrorOccurred = lgErrorOccurred || ( Error > 0 );
00588                                 acs_abs[p][i] = cs_abs;
00589                                 acs_sct[p][i] = cs_sct;
00590                                 a1g[p][i] = 1.-cosb;
00591                                 break;
00592                         default:
00593                                 fprintf( ioQQQ, " Insanity in mie_write_opc\n" );
00594                                 ShowMe();
00595                                 cdEXIT(EXIT_FAILURE);
00596                         }
00597                 }
00598 
00599                 
00600                 if( lgErrorOccurred ) 
00601                 {
00602                         strcpy(chString,"absorption cs");
00603                         mie_repair(chString,rfield.nupper,2,0,rfield.anu,acs_abs[p],ErrorIndex,false,&lgWarning);
00604                         strcpy(chString,"scattering cs");
00605                         mie_repair(chString,rfield.nupper,2,1,rfield.anu,acs_sct[p],ErrorIndex,false,&lgWarning);
00606                         strcpy(chString,"asymmetry parameter");
00607                         mie_repair(chString,rfield.nupper,1,1,rfield.anu,a1g[p],ErrorIndex,true,&lgWarning);
00608                 }
00609 
00610                 for( i=0; i < rfield.nupper; i++ ) 
00611                 {
00612                         acs_abs[p][i] /= gd.norm;
00613                         
00614 
00615                         acs_sct[p][i] /= gd.norm;
00616                 }
00617 #if 0
00618                 {
00619                         FILE* ftmp;
00620                         char name[20] = "asymxx";
00621                         sprintf(&name[4],"%2.2li",p+1);
00622                         ftmp = fopen(name,"w");
00623                         for( i=0; i < rfield.nupper; i++ ) 
00624                         {
00625                                 fprintf( ftmp, "%.6e %.6e\n", rfield.anu[i],a1g[p][i]);
00626                         }
00627                         fclose(ftmp);
00628                 }
00629 #endif
00630 
00631                 mie_auxiliary(&sd,"cleanup");
00632         }
00633 
00634         lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00635         lgErr = lgErr || ( fprintf(fdes,"# ===========================================\n") < 0 );
00636         lgErr = lgErr || ( fprintf(fdes,"# anu (Ryd) abs_cs_01 (cm^2/H) abs_cs_02.....\n#\n") < 0 );
00637 
00638         for( i=0; i < rfield.nupper; i++ ) 
00639         {
00640                 lgErr = lgErr || ( fprintf(fdes,"%.6e ",rfield.anu[i]) < 0 );
00641                 for( p=0; p < sd.nPart; p++ ) 
00642                 {
00643                         lgErr = lgErr || ( fprintf(fdes,"%.6e ",acs_abs[p][i]) < 0 );
00644                 }
00645                 lgErr = lgErr || ( fprintf(fdes,"\n") < 0 );
00646         }
00647 
00648         lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00649         lgErr = lgErr || ( fprintf(fdes,"# ===========================================\n") < 0 );
00650         lgErr = lgErr || ( fprintf(fdes,"# anu (Ryd) sct_cs_01 (cm^2/H) sct_cs_02.....\n#\n") < 0 );
00651 
00652         for( i=0; i < rfield.nupper; i++ ) 
00653         {
00654                 lgErr = lgErr || ( fprintf(fdes,"%.6e ",rfield.anu[i]) < 0 );
00655                 for( p=0; p < sd.nPart; p++ ) 
00656                 {
00657                         lgErr = lgErr || ( fprintf(fdes,"%.6e ",acs_sct[p][i]) < 0 );
00658                 }
00659                 lgErr = lgErr || ( fprintf(fdes,"\n") < 0 );
00660         }
00661 
00662         lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00663         lgErr = lgErr || ( fprintf(fdes,"# ===========================================\n") < 0 );
00664         lgErr = lgErr || ( fprintf(fdes,"# anu (Ryd) (1-g)_bin_01 (1-g)_bin_02.....\n#\n") < 0 );
00665 
00666         for( i=0; i < rfield.nupper; i++ ) 
00667         {
00668                 lgErr = lgErr || ( fprintf(fdes,"%.6e ",rfield.anu[i]) < 0 );
00669                 for( p=0; p < sd.nPart; p++ ) 
00670                 {
00671                         lgErr = lgErr || ( fprintf(fdes,"%.6e ",a1g[p][i]) < 0 );
00672                 }
00673                 lgErr = lgErr || ( fprintf(fdes,"\n") < 0 );
00674         }
00675 
00676         fprintf( ioQQQ, " Starting calculation of inverse attenuation length\n" );
00677         strcpy(chString,"inverse attenuation length");
00678         if( gd.rfiType != RFI_TABLE ) 
00679         {
00680                 
00681                 ial_type icase = gv.which_ial[gd.matType];
00682                 switch( icase )
00683                 {
00684                 case IAL_CAR:
00685                         mie_read_rfi("graphite.rfi",&gd2);
00686                         mie_calc_ial(&gd2,rfield.nupper,inv_att_len,chString,&lgWarning);
00687                         break;
00688                 case IAL_SIL:
00689                         mie_read_rfi("silicate.rfi",&gd2);
00690                         mie_calc_ial(&gd2,rfield.nupper,inv_att_len,chString,&lgWarning);
00691                         break;
00692                 default:
00693                         fprintf( ioQQQ, " mie_write_opc detected unknown ial type: %d\n" , icase );
00694                         cdEXIT(EXIT_FAILURE);
00695                 }
00696         }
00697         else 
00698         {
00699                 mie_calc_ial(&gd,rfield.nupper,inv_att_len,chString,&lgWarning);
00700         }
00701 
00702         lgErr = lgErr || ( fprintf(fdes,"#\n") < 0 );
00703         lgErr = lgErr || ( fprintf(fdes,"# ===========================================\n") < 0 );
00704         lgErr = lgErr || ( fprintf(fdes,"# anu (Ryd) inverse attenuation length (cm^-1)\n#\n") < 0 );
00705 
00706         for( i=0; i < rfield.nupper; i++ ) 
00707         {
00708                 lgErr = lgErr || ( fprintf(fdes,"%.6e %.6e\n",rfield.anu[i],inv_att_len[i]) < 0 );
00709         }
00710 
00711         fclose(fdes);
00712 
00713         if( lgErr ) 
00714         {
00715                 fprintf( ioQQQ, "\n Error writing file: %s\n", chFile );
00716                 if( remove(chFile) == 0 )
00717                 {
00718                         fprintf( ioQQQ, " The file has been removed\n" );
00719                         cdEXIT(EXIT_FAILURE);
00720                 }
00721         }
00722         else 
00723         {
00724                 fprintf( ioQQQ, "\n Opacity file %s written succesfully\n\n", chFile );
00725                 if( lgWarning )
00726                 {
00727                         fprintf( ioQQQ, "\n !!! Warnings were detected !!!\n\n" );
00728                 }
00729         }
00730 
00731         for( p=0; p < sd.nPart; p++ ) 
00732         {
00733                 free(a1g[p]);
00734                 free(acs_sct[p]);
00735                 free(acs_abs[p]);
00736         }
00737 
00738         free(inv_att_len);
00739         free(a1g);
00740         free(acs_sct);
00741         free(acs_abs);
00742 
00743         
00744         if( sd.ln_a != NULL )
00745                 free(sd.ln_a);
00746         if( sd.ln_a4dNda != NULL )
00747                 free(sd.ln_a4dNda);
00748 
00749         
00750         for( j=0; j < gd2.nOpcCols; j++ ) 
00751         {
00752                 if( gd2.opcData[j] != NULL )
00753                         free(gd2.opcData[j]);
00754         }
00755         if( gd2.opcAnu != NULL )
00756                 free(gd2.opcAnu);
00757         for( j=0; j < gd2.nAxes; j++ ) 
00758         {
00759                 if( gd2.nr1[j] != NULL )
00760                         free(gd2.nr1[j]);
00761                 if( gd2.n[j] != NULL )
00762                         free(gd2.n[j]);
00763                 if( gd2.wavlen[j] != NULL )
00764                         free(gd2.wavlen[j]);
00765         }
00766 
00767         for( j=0; j < gd.nOpcCols; j++ ) 
00768         {
00769                 if( gd.opcData[j] != NULL )
00770                         free(gd.opcData[j]);
00771         }
00772         if( gd.opcAnu != NULL )
00773                 free(gd.opcAnu);
00774         for( j=0; j < gd.nAxes; j++ ) 
00775         {
00776                 if( gd.nr1[j] != NULL )
00777                         free(gd.nr1[j]);
00778                 if( gd.n[j] != NULL )
00779                         free(gd.n[j]);
00780                 if( gd.wavlen[j] != NULL )
00781                         free(gd.wavlen[j]);
00782         }
00783 
00784         free( ErrorIndex );
00785         return;
00786 }
00787 
00788 
00789 STATIC void mie_auxiliary( sd_data *sd,
00790                            const char *auxCase)
00791 {
00792         double amin,
00793           amax,
00794           delta,
00795           oldvol,
00796           step;
00797 
00798         
00799         const double TOLER = 1.e-3;
00800 
00801         DEBUG_ENTRY( "mie_auxiliary()" );
00802         if( strcmp(auxCase,"init") == 0 )
00803         {
00804                 sd->xx = NULL;
00805                 sd->aa = NULL;
00806                 sd->rr = NULL;
00807                 sd->ww = NULL;
00808 
00809                 
00810 
00811 
00812                 sd->nmul = 1;
00813 
00814                 
00815                 switch( sd->sdCase ) 
00816                 {
00817                 case SD_SINGLE_SIZE:
00818                         sd->radius = sd->a[ipSize]*1.e-4;
00819                         sd->area = 4.*PI*POW2(sd->a[ipSize])*1.e-8;
00820                         sd->vol = 4./3.*PI*POW3(sd->a[ipSize])*1.e-12;
00821                         break;
00822                 case SD_POWERLAW:
00823                 case SD_EXP_CUTOFF1:
00824                 case SD_EXP_CUTOFF2:
00825                 case SD_EXP_CUTOFF3:
00826                 case SD_LOG_NORMAL:
00827                 case SD_LIN_NORMAL:
00828                 case SD_TABLE:
00829                         
00830 
00831                         amin = sd->lgLogScale ? log(sd->lim[ipBLo]) : sd->lim[ipBLo];
00832                         amax = sd->lgLogScale ? log(sd->lim[ipBHi]) : sd->lim[ipBHi];
00833 
00834                         sd->clim[ipBLo] = sd->lim[ipBLo];
00835                         sd->clim[ipBHi] = sd->lim[ipBHi];
00836 
00837                         
00838                         oldvol= 0.;
00839                         do 
00840                         {
00841                                 sd->nmul *= 2;
00842                                 mie_integrate(sd,amin,amax,&sd->unity,true);
00843                                 delta = fabs(sd->vol-oldvol)/sd->vol;
00844                                 oldvol = sd->vol;
00845                         } while( sd->nmul <= 1024 && delta > TOLER );
00846 
00847                         if( delta > TOLER )
00848                         {
00849                                 fprintf( ioQQQ, " could not converge integration of size distribution\n" );
00850                                 cdEXIT(EXIT_FAILURE);
00851                         }
00852 
00853                         
00854 
00855                         sd->nmul /= 2;
00856                         mie_integrate(sd,amin,amax,&sd->unity,true);
00857                         break;
00858                 case SD_ILLEGAL:
00859                 default:
00860                         fprintf( ioQQQ, " insane case for grain size distribution: %d\n" , sd->sdCase );
00861                         ShowMe();
00862                         cdEXIT(EXIT_FAILURE);
00863                 }
00864         }
00865         else if( strcmp(auxCase,"step") == 0 ) 
00866         {
00867                 
00868                 switch( sd->sdCase ) 
00869                 {
00870                 case SD_SINGLE_SIZE:
00871                         break;
00872                 case SD_POWERLAW:
00873                 case SD_EXP_CUTOFF1:
00874                 case SD_EXP_CUTOFF2:
00875                 case SD_EXP_CUTOFF3:
00876                 case SD_LOG_NORMAL:
00877                 case SD_LIN_NORMAL:
00878                 case SD_TABLE:
00879                         amin = sd->lgLogScale ? log(sd->lim[ipBLo]) : sd->lim[ipBLo];
00880                         amax = sd->lgLogScale ? log(sd->lim[ipBHi]) : sd->lim[ipBHi];
00881                         step = (amax - amin)/(double)sd->nPart;
00882                         amin = amin + (double)sd->cPart*step;
00883                         amax = MIN2(amax,amin + step);
00884 
00885                         sd->clim[ipBLo] = sd->lgLogScale ? exp(amin) : amin;
00886                         sd->clim[ipBHi] = sd->lgLogScale ? exp(amax) : amax;
00887 
00888                         mie_integrate(sd,amin,amax,&sd->unity_bin,false);
00889 
00890                         break;
00891                 case SD_ILLEGAL:        
00892                 default:
00893                         fprintf( ioQQQ, " insane case for grain size distribution: %d\n" , sd->sdCase );
00894                         ShowMe();
00895                         cdEXIT(EXIT_FAILURE);
00896                 }
00897         }
00898         else if( strcmp(auxCase,"cleanup") == 0 ) 
00899         {
00900                 if( sd->xx != NULL )
00901                         free(sd->xx);
00902                 sd->xx = NULL;
00903                 if( sd->aa != NULL )
00904                         free(sd->aa);
00905                 sd->aa = NULL;
00906                 if( sd->rr != NULL )
00907                         free(sd->rr);
00908                 sd->rr = NULL;
00909                 if( sd->ww != NULL )
00910                         free(sd->ww);
00911                 sd->ww = NULL;
00912         }
00913         else 
00914         {
00915                 fprintf( ioQQQ, " mie_auxiliary called with insane argument: %s\n", auxCase );
00916                 ShowMe();
00917                 cdEXIT(EXIT_FAILURE);
00918         }
00919         return;
00920 }
00921 
00922 STATIC void mie_integrate( sd_data *sd,
00923                           double amin,
00924                           double amax,
00925                            double *normalization,
00926                           bool lgFreeMem)
00927 {
00928         long int j;
00929         double unity;
00930 
00931         DEBUG_ENTRY( "mie_integrate()" );
00932 
00933         
00934 
00935         sd->nn = sd->nmul*((long)(2.*log(sd->clim[ipBHi]/sd->clim[ipBLo])) + 1);
00936         sd->nn = MIN2(MAX2(sd->nn,2*sd->nmul),4096);
00937         sd->xx = (double *)MALLOC(sizeof(double)*(unsigned)sd->nn);
00938         sd->aa = (double *)MALLOC(sizeof(double)*(unsigned)sd->nn);
00939         sd->rr = (double *)MALLOC(sizeof(double)*(unsigned)sd->nn);
00940         sd->ww = (double *)MALLOC(sizeof(double)*(unsigned)sd->nn);
00941         gauss_legendre(sd->nn,sd->xx,sd->aa);
00942         gauss_init(sd->nn,amin,amax,sd->xx,sd->aa,sd->rr,sd->ww);
00943 
00944         
00945         unity = 0.;
00946         sd->radius = 0.;
00947         sd->area = 0.;
00948         sd->vol = 0.;
00949 
00950         for( j=0; j < sd->nn; j++ ) 
00951         {
00952                 double weight;
00953 
00954                 
00955                 if( sd->lgLogScale ) 
00956                 {
00957                         sd->rr[j] = exp(sd->rr[j]);
00958                         sd->ww[j] *= sd->rr[j];
00959                 }
00960                 weight = sd->ww[j]*size_distr(sd->rr[j],sd);
00961                 unity += weight;
00962                 sd->radius += weight*sd->rr[j];
00963                 sd->area += weight*POW2(sd->rr[j]);
00964                 sd->vol += weight*POW3(sd->rr[j]);
00965         }
00966         *normalization = unity;
00967         sd->radius *= 1.e-4/unity;
00968         sd->area *= 4.*PI*1.e-8/unity;
00969         sd->vol *= 4./3.*PI*1.e-12/unity;
00970 
00971         if( lgFreeMem )
00972         {
00973                 if( sd->xx != NULL )
00974                         free(sd->xx);
00975                 sd->xx = NULL;
00976                 if( sd->aa != NULL )
00977                         free(sd->aa);
00978                 sd->aa = NULL;
00979                 if( sd->rr != NULL )
00980                         free(sd->rr);
00981                 sd->rr = NULL;
00982                 if( sd->ww != NULL )
00983                         free(sd->ww);
00984                 sd->ww = NULL;
00985         }
00986         return;
00987 }
00988 
00989 
00990 void mie_read_opc(const char *chFile,
00991                   GrainPar gp)
00992 {
00993         int res,
00994           lgDefaultQHeat;
00995         long int dl,
00996           help,
00997           i,
00998           nelem,
00999           j,
01000           magic,
01001           nbin,
01002           nd,
01003           nd2,
01004           nup;
01005         realnum RefAbund[LIMELM],
01006           VolTotal;
01007         double anu;
01008         double RadiusRatio;
01009         char chLine[FILENAME_PATH_LENGTH_2],
01010           *str;
01011         FILE *io2;
01012 
01013         
01014 
01015         const double RATIO_MAX = pow(100.,1./3.);
01016 
01017         DEBUG_ENTRY( "mie_read_opc()" );
01018 
01019         io2 = open_data( chFile, "r", AS_DATA_LOCAL );
01020 
01021         
01022         strcpy( chLine, "                                        " );
01023         if( strlen(chFile) <= 40 )
01024         {
01025                 strncpy( &chLine[0], chFile, strlen(chFile) );
01026         }
01027         else
01028         {
01029                 strncpy( &chLine[0], chFile, 37 );
01030                 strncpy( &chLine[37], "...", 3 );
01031         }
01032         if( called.lgTalk )
01033                 fprintf( ioQQQ, "                       * >>>> mie_read_opc reading file -- %40s <<<< *\n", chLine );
01034 
01035         
01036         for( i=0; i < gv.ReadPtr; ++i )
01037         {
01038                 if( strcmp(chFile,gv.ReadRecord[i]) == 0 )
01039                 {
01040                         fprintf( ioQQQ, " File %s has already been read before, was this intended ?\n", chFile );
01041                         break;
01042                 }
01043         }
01044         
01045         if( gv.ReadPtr < MAX_READ_RECORDS )
01046         {
01047                 strcpy(gv.ReadRecord[gv.ReadPtr],chFile);
01048                 ++gv.ReadPtr;
01049         }
01050 
01051         
01052         nd = NewGrainBin();
01053 
01054         dl = 0; 
01055 
01056         
01057         mie_next_data(chFile,io2,chLine,&dl);
01058         mie_read_long(chFile,chLine,&magic,true,dl);
01059         if( magic != MAGIC_OPC ) 
01060         {
01061                 fprintf( ioQQQ, " Opacity file %s has obsolete magic number\n",chFile );
01062                 fprintf( ioQQQ, " I found magic number %ld, but expected %ld on line #%ld\n",
01063                          magic,MAGIC_OPC,dl );
01064                 fprintf( ioQQQ, " Please recompile this file\n" );
01065                 cdEXIT(EXIT_FAILURE);
01066         }
01067 
01068         
01069         mie_next_data(chFile,io2,chLine,&dl);
01070         mie_read_long(chFile,chLine,&magic,true,dl);
01071 
01072         mie_next_data(chFile,io2,chLine,&dl);
01073         mie_read_long(chFile,chLine,&magic,true,dl);
01074 
01075         
01076 
01077 
01078 
01079 
01080         gv.bin[nd]->dstfactor = (realnum)gp.dep;
01081 
01082         
01083         mie_next_data(chFile,io2,chLine,&dl);
01084         strncpy(gv.bin[nd]->chDstLab,chLine,(size_t)LABELSIZE);
01085         gv.bin[nd]->chDstLab[LABELSIZE] = '\0';
01086 
01087         
01088         mie_next_data(chFile,io2,chLine,&dl);
01089         mie_read_realnum(chFile,chLine,&gv.bin[nd]->dustp[0],true,dl);
01090         
01091         gv.bin[nd]->eec = pow((double)gv.bin[nd]->dustp[0],-0.85);
01092 
01093         
01094         mie_next_data(chFile,io2,chLine,&dl);
01095         mie_read_realnum(chFile,chLine,&gv.bin[nd]->dustp[1],true,dl);
01096 
01097         
01098         mie_next_data(chFile,io2,chLine,&dl);
01099         mie_read_realnum(chFile,chLine,&gv.bin[nd]->atomWeight,true,dl);
01100 
01101         
01102         mie_next_data(chFile,io2,chLine,&dl);
01103         mie_read_realnum(chFile,chLine,&gv.bin[nd]->dustp[2],true,dl);
01104 
01105         
01106         mie_next_data(chFile,io2,chLine,&dl);
01107         mie_read_realnum(chFile,chLine,&gv.bin[nd]->dustp[3],true,dl);
01108 
01109         
01110         mie_next_data(chFile,io2,chLine,&dl);
01111         mie_read_realnum(chFile,chLine,&gv.bin[nd]->AvRadius,true,dl);
01112         gv.bin[nd]->eyc = 1./gv.bin[nd]->AvRadius + 1.e7;
01113 
01114         
01115         mie_next_data(chFile,io2,chLine,&dl);
01116         mie_read_realnum(chFile,chLine,&gv.bin[nd]->AvArea,true,dl);
01117 
01118         
01119         mie_next_data(chFile,io2,chLine,&dl);
01120         mie_read_realnum(chFile,chLine,&gv.bin[nd]->AvVol,true,dl);
01121 
01122         
01123         mie_next_data(chFile,io2,chLine,&dl);
01124         mie_read_realnum(chFile,chLine,&gv.bin[nd]->IntRadius,true,dl);
01125 
01126         
01127         mie_next_data(chFile,io2,chLine,&dl);
01128         mie_read_realnum(chFile,chLine,&gv.bin[nd]->IntArea,true,dl);
01129 
01130         
01131         mie_next_data(chFile,io2,chLine,&dl);
01132         mie_read_realnum(chFile,chLine,&gv.bin[nd]->IntVol,true,dl);
01133 
01134         
01135         mie_next_data(chFile,io2,chLine,&dl);
01136         mie_read_realnum(chFile,chLine,&gv.bin[nd]->DustWorkFcn,true,dl);
01137 
01138         
01139         mie_next_data(chFile,io2,chLine,&dl);
01140         mie_read_realnum(chFile,chLine,&gv.bin[nd]->BandGap,false,dl);
01141 
01142         
01143         mie_next_data(chFile,io2,chLine,&dl);
01144         mie_read_realnum(chFile,chLine,&gv.bin[nd]->ThermEff,true,dl);
01145 
01146         
01147         mie_next_data(chFile,io2,chLine,&dl);
01148         mie_read_realnum(chFile,chLine,&gv.bin[nd]->Tsublimat,true,dl);
01149 
01150         
01151         mie_next_data(chFile,io2,chLine,&dl);
01152         mie_read_long(chFile,chLine,&help,true,dl);
01153         gv.bin[nd]->matType = (mat_type)help;
01154 
01155         for( nelem=0; nelem < LIMELM; nelem++ ) 
01156         {
01157                 mie_next_data(chFile,io2,chLine,&dl);
01158                 mie_read_realnum(chFile,chLine,&RefAbund[nelem],false,dl);
01159 
01160                 
01161                 gv.bin[nd]->AccomCoef[nelem] = 2.*gv.bin[nd]->atomWeight*dense.AtomicWeight[nelem]/
01162                         POW2(gv.bin[nd]->atomWeight+dense.AtomicWeight[nelem]);
01163         }
01164 
01165         
01166         mie_next_data(chFile,io2,chLine,&dl);
01167         mie_read_double(chFile,chLine,&RadiusRatio,true,dl);
01168 
01169         gv.bin[nd]->lgDustFunc = gp.lgAbunVsDepth;
01170         
01171         lgDefaultQHeat = ( RadiusRatio < RATIO_MAX && !gp.lgGreyGrain );
01172         gv.bin[nd]->lgQHeat = ( gp.lgForbidQHeating ) ? false : ( gp.lgRequestQHeating || lgDefaultQHeat );
01173         gv.bin[nd]->cnv_H_pGR = gv.bin[nd]->AvVol/gv.bin[nd]->IntVol;
01174         gv.bin[nd]->cnv_GR_pH = 1./gv.bin[nd]->cnv_H_pGR;
01175 
01176         
01177         gv.bin[nd]->Capacity = PI4*ELECTRIC_CONST*gv.bin[nd]->IntRadius/100.*gv.bin[nd]->cnv_H_pGR;
01178 
01179         
01180         mie_next_data(chFile,io2,chLine,&dl);
01181         mie_read_long(chFile,chLine,&nup,false,dl);
01182         for( i=0; i < nup; i++ )
01183                 mie_next_data(chFile,io2,chLine,&dl);
01184 
01185         
01186         mie_next_data(chFile,io2,chLine,&dl);
01187         mie_read_long(chFile,chLine,&nup,true,dl);
01188 
01189         gv.bin[nd]->NFPCheck = nup;
01190 
01191         
01192         mie_next_data(chFile,io2,chLine,&dl);
01193         mie_read_long(chFile,chLine,&nbin,true,dl);
01194 
01195         if( nbin == 1 )
01196         {
01197                 
01198                 ASSERT( gv.bin[nd]->dstab1 == NULL ); 
01199                 gv.bin[nd]->dstab1 = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01200                 ASSERT( gv.bin[nd]->pure_sc1 == NULL ); 
01201                 gv.bin[nd]->pure_sc1 = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01202                 ASSERT( gv.bin[nd]->asym == NULL ); 
01203                 gv.bin[nd]->asym = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01204                 ASSERT( gv.bin[nd]->inv_att_len == NULL ); 
01205                 gv.bin[nd]->inv_att_len = (realnum*)MALLOC(sizeof(realnum)*(unsigned)nup);
01206 
01207                 gv.bin[nd]->dustp[4] = 1.;
01208                 for( nelem=0; nelem < LIMELM; nelem++ )
01209                 {
01210                         gv.bin[nd]->elmAbund[nelem] = RefAbund[nelem];
01211                 }
01212         }
01213         else if( nbin > 1 )
01214         {
01215                 
01216                 VolTotal = gv.bin[nd]->IntVol;
01217 
01218                 for( i=0; i < nbin; i++ ) 
01219                 {
01220                         
01221                         nd2 = ( i == 0 ) ? nd : NewGrainBin();
01222 
01223                         
01224                         ASSERT( gv.bin[nd2]->dstab1 == NULL ); 
01225                         gv.bin[nd2]->dstab1 = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01226                         ASSERT( gv.bin[nd2]->pure_sc1 == NULL ); 
01227                         gv.bin[nd2]->pure_sc1 = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01228                         ASSERT( gv.bin[nd2]->asym == NULL ); 
01229                         gv.bin[nd2]->asym = (double*)MALLOC(sizeof(double)*(unsigned)nup);
01230                         ASSERT( gv.bin[nd2]->inv_att_len == NULL ); 
01231                         gv.bin[nd2]->inv_att_len = (realnum*)MALLOC(sizeof(realnum)*(unsigned)nup);
01232 
01233                         
01234                         mie_next_data(chFile,io2,chLine,&dl);
01235                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->AvRadius,true,dl);
01236 
01237                         
01238                         mie_next_data(chFile,io2,chLine,&dl);
01239                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->AvArea,true,dl);
01240 
01241                         
01242                         mie_next_data(chFile,io2,chLine,&dl);
01243                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->AvVol,true,dl);
01244 
01245                         
01246                         mie_next_data(chFile,io2,chLine,&dl);
01247                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->IntRadius,true,dl);
01248 
01249                         
01250                         mie_next_data(chFile,io2,chLine,&dl);
01251                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->IntArea,true,dl);
01252 
01253                         
01254                         mie_next_data(chFile,io2,chLine,&dl);
01255                         mie_read_realnum(chFile,chLine,&gv.bin[nd2]->IntVol,true,dl);
01256 
01257                         gv.bin[nd2]->cnv_H_pGR = gv.bin[nd2]->AvVol/gv.bin[nd2]->IntVol;
01258                         gv.bin[nd2]->cnv_GR_pH = 1./gv.bin[nd2]->cnv_H_pGR;
01259 
01260 
01261 
01262                         
01263                         gv.bin[nd2]->Capacity =
01264                                 PI4*ELECTRIC_CONST*gv.bin[nd2]->IntRadius/100.*gv.bin[nd2]->cnv_H_pGR;
01265 
01266                         
01267 
01268 
01269                         gv.bin[nd2]->dustp[4] = gv.bin[nd2]->IntVol/VolTotal;
01270                         for( nelem=0; nelem < LIMELM; nelem++ )
01271                         {
01272                                 gv.bin[nd2]->elmAbund[nelem] = RefAbund[nelem]*gv.bin[nd2]->dustp[4];
01273                         }
01274 
01275                         if( i > 0 ) 
01276                         {
01277                                 gv.bin[nd2]->dstfactor = gv.bin[nd]->dstfactor;
01278                                 strcpy(gv.bin[nd2]->chDstLab,gv.bin[nd]->chDstLab);
01279                                 gv.bin[nd2]->atomWeight = gv.bin[nd]->atomWeight;
01280                                 for( j=0; j < 4; j++ ) 
01281                                 {
01282                                         gv.bin[nd2]->dustp[j] = gv.bin[nd]->dustp[j];
01283                                 }
01284                                 gv.bin[nd2]->eec = gv.bin[nd]->eec;
01285                                 gv.bin[nd2]->eyc = gv.bin[nd]->eyc;
01286                                 gv.bin[nd2]->DustWorkFcn = gv.bin[nd]->DustWorkFcn;
01287                                 gv.bin[nd2]->BandGap = gv.bin[nd]->BandGap;
01288                                 gv.bin[nd2]->ThermEff = gv.bin[nd]->ThermEff;
01289                                 gv.bin[nd2]->Tsublimat = gv.bin[nd]->Tsublimat;
01290                                 gv.bin[nd2]->matType = gv.bin[nd]->matType;
01291                                 gv.bin[nd2]->lgDustFunc = gv.bin[nd]->lgDustFunc;
01292                                 gv.bin[nd2]->lgQHeat = gv.bin[nd]->lgQHeat;
01293                                 gv.bin[nd2]->NFPCheck = gv.bin[nd]->NFPCheck;
01294                                 for( nelem=0; nelem < LIMELM; nelem++ )
01295                                 {
01296                                         gv.bin[nd2]->AccomCoef[nelem] = gv.bin[nd]->AccomCoef[nelem];
01297                                 }
01298                         }
01299                 }
01300                 for( i=0; i < nbin; i++ ) 
01301                 {
01302                         nd2 = nd + i;
01303                         
01304                         str = strstr(gv.bin[nd2]->chDstLab,"xx");
01305                         if( str != NULL )
01306                                 sprintf(str,"%02ld",i+1);
01307                 }
01308         }
01309 
01310         
01311         for( i=0; i < 5; i++ )
01312                 mie_next_line(chFile,io2,chLine,&dl);
01313 
01314         
01315         for( i=0; i < nup; i++ ) 
01316         {
01317                 
01318                 if( (res = fscanf(io2,"%le",&anu)) != 1 ) 
01319                 {
01320                         fprintf( ioQQQ, " Read failed on %s\n",chFile );
01321                         if( res == EOF )
01322                                 fprintf( ioQQQ, " EOF reached prematurely\n" );
01323                         cdEXIT(EXIT_FAILURE);
01324                 }
01325                 for( j=0; j < nbin; j++ ) 
01326                 {
01327                         nd2 = nd + j;
01328                         if( (res = fscanf(io2,"%le",&gv.bin[nd2]->dstab1[i])) != 1 ) 
01329                         {
01330                                 fprintf( ioQQQ, " Read failed on %s\n",chFile );
01331                                 if( res == EOF )
01332                                         fprintf( ioQQQ, " EOF reached prematurely\n" );
01333                                 cdEXIT(EXIT_FAILURE);
01334                         }
01335                         ASSERT( gv.bin[nd2]->dstab1[i] > 0. );
01336                 }
01337         }
01338 
01339         
01340         for( i=0; i < 5; i++ )
01341                 mie_next_line(chFile,io2,chLine,&dl);
01342 
01343         
01344         for( i=0; i < nup; i++ ) 
01345         {
01346                 if( (res = fscanf(io2,"%le",&anu)) != 1 ) 
01347                 {
01348                         fprintf( ioQQQ, " Read failed on %s\n",chFile );
01349                         if( res == EOF )
01350                                 fprintf( ioQQQ, " EOF reached prematurely\n" );
01351                         cdEXIT(EXIT_FAILURE);
01352                 }
01353                 for( j=0; j < nbin; j++ ) 
01354                 {
01355                         nd2 = nd + j;
01356                         if( (res = fscanf(io2,"%le",&gv.bin[nd2]->pure_sc1[i])) != 1 ) 
01357                         {
01358                                 fprintf( ioQQQ, " Read failed on %s\n",chFile );
01359                                 if( res == EOF )
01360                                         fprintf( ioQQQ, " EOF reached prematurely\n" );
01361                                 cdEXIT(EXIT_FAILURE);
01362                         }
01363                         ASSERT( gv.bin[nd2]->pure_sc1[i] > 0. );
01364                 }
01365         }
01366 
01367 
01368 
01369         
01370         for( i=0; i < 5; i++ )
01371                 mie_next_line(chFile,io2,chLine,&dl);
01372 
01373         
01374         for( i=0; i < nup; i++ ) 
01375         {
01376                 if( (res = fscanf(io2,"%le",&anu)) != 1 ) 
01377                 {
01378                         fprintf( ioQQQ, " Read failed on %s\n",chFile );
01379                         if( res == EOF )
01380                                 fprintf( ioQQQ, " EOF reached prematurely\n" );
01381                         cdEXIT(EXIT_FAILURE);
01382                 }
01383                 for( j=0; j < nbin; j++ ) 
01384                 {
01385                         nd2 = nd + j;
01386                         if( (res = fscanf(io2,"%le",&gv.bin[nd2]->asym[i])) != 1 ) 
01387                         {
01388                                 fprintf( ioQQQ, " Read failed on %s\n",chFile );
01389                                 if( res == EOF )
01390                                         fprintf( ioQQQ, " EOF reached prematurely\n" );
01391                                 cdEXIT(EXIT_FAILURE);
01392                         }
01393                         ASSERT( gv.bin[nd2]->asym[i] > 0. );
01394                 }
01395         }
01396 
01397         
01398         for( i=0; i < 5; i++ )
01399                 mie_next_line(chFile,io2,chLine,&dl);
01400 
01401         
01402         for( i=0; i < nup; i++ ) 
01403         {
01404                 double help;
01405                 if( (res = fscanf(io2,"%le %le",&anu,&help)) != 2 ) 
01406                 {
01407                         fprintf( ioQQQ, " Read failed on %s\n",chFile );
01408                         if( res == EOF )
01409                                 fprintf( ioQQQ, " EOF reached prematurely\n" );
01410                         cdEXIT(EXIT_FAILURE);
01411                 }
01412                 gv.bin[nd]->inv_att_len[i] = (realnum)help;
01413                 ASSERT( gv.bin[nd]->inv_att_len[i] > 0. );
01414                 
01415                 gv.bin[nd]->EnergyCheck = (realnum)anu;
01416 
01417                 for( j=1; j < nbin; j++ ) 
01418                 {
01419                         nd2 = nd + j;
01420                         gv.bin[nd2]->inv_att_len[i] = gv.bin[nd]->inv_att_len[i];
01421                         gv.bin[nd2]->EnergyCheck = gv.bin[nd]->EnergyCheck;
01422                 }
01423         }
01424 
01425         fclose(io2);
01426         return;
01427 }
01428 
01429 
01430 
01431 
01432 STATIC void mie_cs_size_distr(double wavlen, 
01433                                sd_data *sd,
01434                                grain_data *gd,
01435                               void(*cs_fun)(double,sd_data*,grain_data*,
01436                                             double*,double*,
01437                                             double*,int*),
01438                                double *cs_abs, 
01439                                double *cs_sct, 
01440                                double *cosb,
01441                                int *error)
01442 {
01443         bool lgADLused;
01444         long int i;
01445         double absval,
01446           g,
01447           sctval,
01448           weight;
01449 
01450         DEBUG_ENTRY( "mie_cs_size_distr()" );
01451 
01452         
01453         ASSERT( wavlen > 0. );
01454         ASSERT( gd->cAxis >= 0 && gd->cAxis < gd->nAxes && gd->cAxis < NAX );
01455 
01456         switch( sd->sdCase ) 
01457         {
01458         case SD_SINGLE_SIZE:
01459                 
01460                 ASSERT( sd->a[ipSize] > 0. );
01461                 sd->cSize = sd->a[ipSize];
01462                 (*cs_fun)(wavlen,sd,gd,cs_abs,cs_sct,cosb,error);
01463                 break;
01464         case SD_POWERLAW:
01465                 
01466         case SD_EXP_CUTOFF1:
01467         case SD_EXP_CUTOFF2:
01468         case SD_EXP_CUTOFF3:
01469                 
01470         case SD_LOG_NORMAL:
01471                 
01472         case SD_LIN_NORMAL:
01473                 
01474         case SD_TABLE:
01475                 
01476                 ASSERT( sd->lim[ipBLo] > 0. && sd->lim[ipBHi] > 0. && sd->lim[ipBHi] > sd->lim[ipBLo] );
01477                 lgADLused = false;
01478                 *cs_abs = 0.;
01479                 *cs_sct = 0.;
01480                 *cosb = 0.;
01481                 for( i=0; i < sd->nn; i++ ) 
01482                 {
01483                         sd->cSize = sd->rr[i];
01484                         (*cs_fun)(wavlen,sd,gd,&absval,&sctval,&g,error);
01485                         if( *error >= 2 ) 
01486                         {
01487                                 
01488                                 *cs_abs = -1.;
01489                                 *cs_sct = -1.;
01490                                 *cosb = -2.;
01491                                 return;
01492                         }
01493                         else if( *error == 1 ) 
01494                         {
01495                                 
01496                                 lgADLused = true;
01497                         }
01498                         weight = sd->ww[i]*size_distr(sd->rr[i],sd);
01499                         *cs_abs += weight*absval;
01500                         *cs_sct += weight*sctval;
01501                         *cosb += weight*sctval*g;
01502                 }
01503                 if( lgADLused ) 
01504                 {
01505                         *error = 1;
01506                         *cosb = -2.;
01507                 }
01508                 else 
01509                 {
01510                         *error = 0;
01511                         *cosb /= *cs_sct;
01512                 }
01513                 *cs_abs /= sd->unity;
01514                 *cs_sct /= sd->unity;
01515                 break;
01516         case SD_ILLEGAL:
01517         default:
01518                 fprintf( ioQQQ, " insane case for grain size distribution: %d\n" , sd->sdCase );
01519                 ShowMe();
01520                 cdEXIT(EXIT_FAILURE);
01521         }
01522         
01523         if( *error < 2 )
01524                 ASSERT( *cs_abs > 0. && *cs_sct > 0. );
01525         if( *error < 1 )
01526                 ASSERT( fabs(*cosb) <= 1.+10.*DBL_EPSILON );
01527         return;
01528 }
01529 
01530 
01531 
01532 
01533 STATIC void mie_cs(double wavlen,  
01534                     sd_data *sd,
01535                     grain_data *gd,
01536                     double *cs_abs, 
01537                     double *cs_sct, 
01538                     double *cosb,
01539                     int *error)
01540 {
01541         bool lgOutOfBounds;
01542         long int iflag,
01543           ind;
01544         double area,
01545           aqabs,
01546           aqext,
01547           aqphas,
01548           beta,
01549           ctbrqs = -DBL_MAX,
01550           delta,
01551           frac,
01552           nim,
01553           nre,
01554           nr1,
01555           qback,
01556           qext = -DBL_MAX,
01557           qphase,
01558           qscatt = -DBL_MAX,
01559           x,
01560           xistar;
01561 
01562         DEBUG_ENTRY( "mie_cs()" );
01563 
01564         
01565         ASSERT( wavlen > 0. );
01566         ASSERT( sd->cSize > 0. );
01567         ASSERT( gd->wavlen[gd->cAxis] != NULL && gd->ndata[gd->cAxis] > 1 );
01568 
01569         
01570         
01571 
01572         find_arr(wavlen,gd->wavlen[gd->cAxis],gd->ndata[gd->cAxis],&ind,&lgOutOfBounds);
01573 
01574         if( lgOutOfBounds ) 
01575         {
01576                 *error = 3;
01577                 *cs_abs = -1.;
01578                 *cs_sct = -1.;
01579                 *cosb = -2.;
01580                 return;
01581         }
01582 
01583         frac = (wavlen-gd->wavlen[gd->cAxis][ind])/(gd->wavlen[gd->cAxis][ind+1]-gd->wavlen[gd->cAxis][ind]);
01584         ASSERT( frac > 0.-10.*DBL_EPSILON && frac < 1.+10.*DBL_EPSILON );
01585         nre = (1.-frac)*gd->n[gd->cAxis][ind].real() + frac*gd->n[gd->cAxis][ind+1].real();
01586         ASSERT( nre > 0. );
01587         nim = (1.-frac)*gd->n[gd->cAxis][ind].imag() + frac*gd->n[gd->cAxis][ind+1].imag();
01588         ASSERT( nim > 0. );
01589         nr1 = (1.-frac)*gd->nr1[gd->cAxis][ind] + frac*gd->nr1[gd->cAxis][ind+1];
01590         ASSERT( fabs(nre-1.-nr1) < 10.*MAX2(nre,1.)*DBL_EPSILON );
01591 
01592         
01593         area = PI*POW2(sd->cSize)*1.e-8;
01594 
01595         x = sd->cSize/wavlen*2.*PI;
01596 
01597         
01598 
01599 
01600         sinpar(nre,nim,x,&qext,&qphase,&qscatt,&ctbrqs,&qback,&iflag);
01601 
01602         
01603 
01604 
01605         if( iflag == 0 ) 
01606         {
01607                 *error = 0;
01608                 *cs_abs = area*(qext - qscatt);
01609                 *cs_sct = area*qscatt;
01610                 *cosb = ctbrqs/qscatt;
01611         }
01612         else 
01613         {
01614                 
01615                 if( x >= 100. && sqrt(nr1*nr1+nim*nim) <= 0.001 ) 
01616                 {
01617                         delta = -nr1;
01618                         beta = nim;
01619 
01620                         anomal(x,&aqext,&aqabs,&aqphas,&xistar,delta,beta);
01621 
01622                         
01623                         *error = 1;
01624                         *cs_abs = area*aqabs;
01625                         *cs_sct = area*(aqext - aqabs);
01626                         *cosb = -2.;
01627                 }
01628                 
01629                 else 
01630                 {
01631                         *error = 2;
01632                         *cs_abs = -1.;
01633                         *cs_sct = -1.;
01634                         *cosb = -2.;
01635                 }
01636         }
01637         if( *error < 2 ) 
01638         {
01639                 if( *cs_abs <= 0. || *cs_sct <= 0. ) 
01640                 {
01641                         fprintf( ioQQQ, " illegal opacity found: wavl=%.4e micron," , wavlen );
01642                         fprintf( ioQQQ, " abs_cs=%.2e, sct_cs=%.2e\n" , *cs_abs , *cs_sct );
01643                         fprintf( ioQQQ, " please check refractive index file...\n" );
01644                         cdEXIT(EXIT_FAILURE);
01645                 }
01646         }
01647         if( *error < 1 ) 
01648         {
01649                 if( fabs(*cosb) > 1.+10.*DBL_EPSILON ) 
01650                 {
01651                         fprintf( ioQQQ, " illegal asymmetry parameter found: wavl=%.4e micron," , wavlen );
01652                         fprintf( ioQQQ, " cosb=%.2e\n" , *cosb );
01653                         fprintf( ioQQQ, " please check refractive index file...\n" );
01654                         cdEXIT(EXIT_FAILURE);
01655                 }
01656         }
01657 
01658         return;
01659 }
01660 
01661 
01662 
01663 
01664 
01665 
01666 
01667 static const double pah1_strength[7]={1.4e-21,1.8e-21,1.2e-20,6.0e-21,4.0e-20,1.9e-20,1.9e-20};
01668 static const double pah1_wlBand[7]={3.3, 6.18, 7.7, 8.6, 11.3, 12.0, 13.3};
01669 static const double pah1_width[7]={0.024, 0.102, 0.24, 0.168, 0.086, 0.174, 0.174};
01670 
01671 STATIC void pah1_fun(double wavl,    
01672                       sd_data *sd,
01673                       grain_data *gd,
01674                       double *cs_abs,
01675                       double *cs_sct,
01676                       double *cosb,
01677                       int *error)
01678 {
01679         long int j;
01680         double cval1,
01681           pah1_fun_v,
01682           term,
01683           term1,
01684           term2,
01685           term3,
01686           x;
01687 
01688         const double p1 = 4.0e-18;
01689         const double p2 = 1.1e-18;
01690         const double p3 = 3.3e-21;
01691         const double p4 = 6.0e-21;
01692         const double p5 = 2.4e-21;
01693         const double wl1a = 5.0;
01694         const double wl1b = 7.0;
01695         const double wl1c = 9.0;
01696         const double wl1d = 9.5;
01697         const double wl2a = 11.0;
01698         const double delwl2 = 0.3;
01699         
01700         const double wl2b = wl2a + delwl2;
01701         const double wl2c = 15.0;
01702         const double wl3a = 3.2;
01703         const double wl3b = 3.57;
01704         const double wl3m = (wl3a+wl3b)/2.;
01705         const double wl3sig = 0.1476;
01706         const double x1 = 4.0;
01707         const double x2 = 5.9;
01708         const double x2a = RYD_INF/1.e4;
01709         const double x3 = 0.1;
01710 
01711         
01712         double vol = 4.*PI/3.*POW3(sd->cSize)*1.e-12;
01713         
01714         double xnc = floor(vol*gd->rho/(ATOMIC_MASS_UNIT*dense.AtomicWeight[ipCARBON]));
01715         
01716         
01717         double xnh = floor(sqrt(6.*xnc));
01718         
01719         double xnhoc = xnh/xnc;
01720         
01721         double ftoc3p3 = 100.;
01722 
01723         double csVal1 = 0.;
01724         double csVal2 = 0.;
01725 
01726         DEBUG_ENTRY( "pah1_fun()" );
01727 
01728 
01729 
01733         x = 1./wavl;
01734 
01735         if( x >= x2a )
01736         {
01737                 
01738                 double anu_ev = x/x2a*EVRYD;
01739 
01740                 
01741                 t_ADfA::Inst().set_version( PHFIT95 );
01742 
01743                 term1 = t_ADfA::Inst().phfit(ipHYDROGEN+1,1,1,anu_ev);
01744                 term2 = 0.;
01745                 for( j=1; j <= 3; ++j )
01746                         term2 += t_ADfA::Inst().phfit(ipCARBON+1,6,j,anu_ev);
01747 
01748                 csVal1 = (xnh*term1 + xnc*term2)*1.e-18;
01749         }
01750 
01751         if( x <= 2.*x2a )
01752         {
01753                 cval1 = log(sqrt(xnc)*ftoc3p3/1.2328)/12.2;
01754 
01755                 term = POW2(MIN2(x,x1))*(3.*x1 - 2.*MIN2(x,x1))/POW3(x1);
01756 
01757                 term1 = (0.1*x + 0.41)*POW2(MAX2(x-x2,0.));
01758 
01759                 
01760 
01761 
01762 
01763 
01764 
01765 
01766 
01767 
01768 
01769 
01770 
01771 
01772 
01773 
01774 
01775 
01776 
01777 
01778 
01779 
01780 
01781                 term2 = exp(cval1*(1. - (x1/MIN2(x,x1))));
01782 
01783                 term3 = p3*exp(-POW2(x/x3))*MIN2(x,x3)/x3;
01784 
01785                 csVal2 = xnc*((p1*term + p2*term1)*term2 + term3);
01786         }
01787 
01788         if( x2a <= x && x <= 2.*x2a )
01789         {
01790                 
01791                 double frac = POW2(2.-x/x2a);
01792                 pah1_fun_v = exp((1.-frac)*log(csVal1) + frac*log(csVal2));
01793         }
01794         else
01795         {
01796                 
01797                 pah1_fun_v = csVal1 + csVal2;
01798         }
01799 
01800         
01801 
01802         if( wl1a <= wavl && wl1d >= wavl )
01803         {
01804                 if( wavl < wl1b )
01805                         term = p4*(wavl - wl1a)/(wl1b - wl1a);
01806                 else
01807                         term = ( wavl > wl1c ) ? p4*(wl1d - wavl)/(wl1d - wl1c) : p4;
01808                 pah1_fun_v += term*xnc;
01809         }
01810         if( wl2a <= wavl && wl2c >= wavl )
01811         {
01812                 term = ( wavl < wl2b ) ? p5*((wavl - wl2a)/delwl2) : p5*sqrt(1.-POW2((wavl-wl2a)/(wl2c-wl2a)));
01813                 pah1_fun_v += term*xnc;
01814         }
01815         if( wl3m-10.*wl3sig <= wavl && wavl <= wl3m+10.*wl3sig )
01816         {
01817                 
01818 
01819                 term = 1.1*pah1_strength[0]*exp(-0.5*POW2((wavl-wl3m)/wl3sig));
01820                 pah1_fun_v += term*xnh;
01821         }
01822 
01823         
01824         for( j=0; j < 7; j++ )
01825         {
01826                 term1 = (wavl - pah1_wlBand[j])/pah1_width[j];
01827                 term = 0.;
01828                 if( j == 2 )
01829                 {
01830                         
01831 
01832 
01833 
01834                         if( term1 >= -1. && term1 < -0.5 )
01835                         {
01836                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01837                                 term *= 2. + 2.*term1;
01838                         }
01839                         if( term1 >= -0.5 && term1 <= 1.5 )
01840                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01841                         if( term1 > 1.5 && term1 <= 3. )
01842                         {
01843                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01844                                 term *= 2. - term1*2./3.;
01845                         }
01846                 }
01847                 else
01848                 {
01849                         
01850 
01851 
01852 
01853                         if( term1 >= -2. && term1 < -1. )
01854                         {
01855                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01856                                 term *= 2. + term1;
01857                         }
01858                         if( term1 >= -1. && term1 <= 1. )
01859                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01860                         if( term1 > 1. && term1 <= 2. )
01861                         {
01862                                 term = pah1_strength[j]/(3.*pah1_width[j]);
01863                                 term *= 2. - term1;
01864                         }
01865                 }
01866                 if( j == 0 || j > 2 )
01867                         term *= xnhoc;
01868                 pah1_fun_v += term*xnc;
01869         }
01870 
01871         *cs_abs = pah1_fun_v;
01872         
01873         
01874         *cs_sct = 0.1*pah1_fun_v;
01875         *cosb = 0.;
01876         *error = 0;
01877 
01878         return;
01879 }
01880 
01881 
01882 STATIC void tbl_fun(double wavl,    
01883                      sd_data *sd, 
01884                      grain_data *gd,
01885                      double *cs_abs,
01886                      double *cs_sct,
01887                      double *cosb,
01888                      int *error)
01889 {
01890         bool lgOutOfBounds;
01891         long int ind;
01892         double anu = WAVNRYD/wavl*1.e4;
01893 
01894         DEBUG_ENTRY( "tbl_fun()" );
01895 
01896         
01897         if( sd == NULL )
01898                 TotalInsanity();
01899 
01903         find_arr(anu,gd->opcAnu,gd->nOpcData,&ind,&lgOutOfBounds);
01904         if( !lgOutOfBounds ) 
01905         {
01906                 double a1g;
01907                 double frac = log(anu/gd->opcAnu[ind])/log(gd->opcAnu[ind+1]/gd->opcAnu[ind]);
01908 
01909                 *cs_abs = exp((1.-frac)*log(gd->opcData[0][ind])+frac*log(gd->opcData[0][ind+1]));
01910                 ASSERT( *cs_abs > 0. );
01911                 if( gd->nOpcCols > 1 )
01912                         *cs_sct = exp((1.-frac)*log(gd->opcData[1][ind])+frac*log(gd->opcData[1][ind+1]));
01913                 else
01914                         *cs_sct = 0.1*(*cs_abs);
01915                 ASSERT( *cs_sct > 0. );
01916                 if( gd->nOpcCols > 2 )
01917                         a1g = exp((1.-frac)*log(gd->opcData[2][ind])+frac*log(gd->opcData[2][ind+1]));
01918                 else
01919                         a1g = 1.;
01920                 ASSERT( a1g > 0. );
01921                 *cosb = 1. - a1g;
01922                 *error = 0;
01923         }
01924         else
01925         {
01926                 *cs_abs = -1.;
01927                 *cs_sct = -1.;
01928                 *cosb = -2.;
01929                 *error = 3;
01930         }
01931         return;
01932 }
01933 
01934 
01935 STATIC double size_distr(double size,
01936                           sd_data *sd)
01937 {
01938         bool lgOutOfBounds;
01939         long ind;
01940         double frac,
01941           res,
01942           x;
01943 
01944         DEBUG_ENTRY( "size_distr()" );
01945 
01946         if( size >= sd->lim[ipBLo] && size <= sd->lim[ipBHi] )
01947                 switch( sd->sdCase ) 
01948                 {
01949                 case SD_SINGLE_SIZE:
01950                         res = 1.; 
01951                         break;
01952                 case SD_POWERLAW:
01953                         
01954                 case SD_EXP_CUTOFF1:
01955                 case SD_EXP_CUTOFF2:
01956                 case SD_EXP_CUTOFF3:
01957                         
01958 
01959                         res = pow(size,sd->a[ipExp]);
01960                         if( sd->a[ipBeta] < 0. )
01961                                 res /= (1. - sd->a[ipBeta]*size);
01962                         else if( sd->a[ipBeta] > 0. )
01963                                 res *= (1. + sd->a[ipBeta]*size);
01964                         if( size < sd->a[ipBLo] && sd->a[ipSLo] > 0. )
01965                                 res *= exp(-powi((sd->a[ipBLo]-size)/sd->a[ipSLo],nint(sd->a[ipAlpha])));
01966                         if( size > sd->a[ipBHi] && sd->a[ipSHi] > 0. )
01967                                 res *= exp(-powi((size-sd->a[ipBHi])/sd->a[ipSHi],nint(sd->a[ipAlpha])));
01968                         break;
01969                 case SD_LOG_NORMAL:
01970                         x = log(size/sd->a[ipGCen])/sd->a[ipGSig];
01971                         res = exp(-0.5*POW2(x))/size;
01972                         break;
01973                 case SD_LIN_NORMAL:
01974                         x = (size-sd->a[ipGCen])/sd->a[ipGSig];
01975                         res = exp(-0.5*POW2(x))/size;
01976                         break;
01977                 case SD_TABLE:
01978                         find_arr(log(size),sd->ln_a,sd->npts,&ind,&lgOutOfBounds);
01979                         if( lgOutOfBounds )
01980                         {
01981                                 fprintf( ioQQQ, " size distribution table has insufficient range\n" );
01982                                 fprintf( ioQQQ, " requested size: %.5f table range %.5f - %.5f\n",
01983                                          size, exp(sd->ln_a[0]), exp(sd->ln_a[sd->npts-1]) );
01984                                 cdEXIT(EXIT_FAILURE);
01985                         }                               
01986                         frac = (log(size)-sd->ln_a[ind])/(sd->ln_a[ind+1]-sd->ln_a[ind]);
01987                         ASSERT( frac > 0.-10.*DBL_EPSILON && frac < 1.+10.*DBL_EPSILON );
01988                         res = (1.-frac)*sd->ln_a4dNda[ind] + frac*sd->ln_a4dNda[ind+1];
01989                         
01990                         res = exp(res)/POW4(size);
01991                         break;
01992                 case SD_ILLEGAL:
01993                 default:
01994                         fprintf( ioQQQ, " insane case for grain size distribution: %d\n" , sd->sdCase );
01995                         ShowMe();
01996                         cdEXIT(EXIT_FAILURE);
01997                 }
01998         else
01999                 res = 0.;
02000         return res;
02001 }
02002 
02003 
02004 
02005 
02006 
02007  
02008 STATIC double search_limit(double ref,
02009                            double step,
02010                            double rel_cutoff,
02011                            sd_data sd)
02012 {
02013         long i;
02014         double f1,
02015           f2,
02016           fmid,
02017           renorm,
02018           x1,
02019           x2 = DBL_MAX,
02020           xmid = DBL_MAX;
02021 
02022         
02023         const double TOLER = 1.e-6;
02024 
02025         DEBUG_ENTRY( "search_limit()" );
02026 
02027         
02028         ASSERT( rel_cutoff > 0. && rel_cutoff < 1. );
02029 
02030         if( step == 0. )
02031         {
02032                 return ref;
02033         }
02034 
02035         
02036 
02037 
02038         sd.lim[ipBLo] = 0.;
02039         sd.lim[ipBHi] = DBL_MAX;
02040 
02041         x1 = ref;
02042         
02043         f1 = -log(rel_cutoff);
02044         renorm = f1 - log(POW4(x1)*size_distr(x1,&sd));
02045 
02046         
02047         f2 = 1.;
02048         for( i=0; i < 20 && f2 > 0.; ++i )
02049         {
02050                 x2 = MAX2(ref + step,SMALLEST_GRAIN);
02051                 f2 = log(POW4(x2)*size_distr(x2,&sd)) + renorm;
02052                 if( f2 >= 0. )
02053                 {
02054                         x1 = x2;
02055                         f1 = f2;
02056                 }
02057                 step *= 2.;
02058         }
02059         if( f2 > 0. )
02060         {
02061                 fprintf( ioQQQ, " Could not bracket solution\n" );
02062                 cdEXIT(EXIT_FAILURE);
02063         }
02064 
02065         
02066         while( 2.*fabs(x1-x2)/(x1+x2) > TOLER )
02067         {
02068                 xmid = (x1+x2)/2.;
02069                 fmid = log(POW4(xmid)*size_distr(xmid,&sd)) + renorm;
02070 
02071                 if( fmid == 0. )
02072                         break;
02073 
02074                 if( f1*fmid > 0. )
02075                 {
02076                         x1 = xmid;
02077                         f1 = fmid;
02078                 }
02079                 else
02080                 {
02081                         x2 = xmid;
02082                         f2 = fmid;
02083                 }
02084         }
02085         return (x1+x2)/2.;
02086 }
02087 
02088 
02089 STATIC void mie_calc_ial( grain_data *gd,
02090                          long int n,
02091                           double invlen[],  
02092                           const char *chString,
02093                           bool *lgWarning)
02094 {
02095         
02096         int *ErrorIndex;
02097         bool lgErrorOccurred=true,
02098           lgOutOfBounds;
02099         long int i,
02100           ind,
02101           j;
02102         double frac,
02103           InvDep,
02104           nim,
02105           wavlen;
02106 
02107         DEBUG_ENTRY( "mie_calc_ial()" );
02108 
02109         
02110         ASSERT( gd->rfiType == RFI_TABLE );
02111 
02112         
02113         ErrorIndex = (int*)MALLOC(sizeof(int)*(unsigned)rfield.nupper);
02114 
02115         for( i=0; i < n; i++ ) 
02116         {
02117                 wavlen = WAVNRYD/rfield.anu[i]*1.e4;
02118 
02119                 ErrorIndex[i] = 0;
02120                 lgErrorOccurred = false;
02121                 invlen[i] = 0.;
02122 
02123                 for( j=0; j < gd->nAxes; j++ ) 
02124                 {
02125                         
02126                         find_arr(wavlen,gd->wavlen[j],gd->ndata[j],&ind,&lgOutOfBounds);
02127                         if( lgOutOfBounds ) 
02128                         {
02129                                 ErrorIndex[i] = 3;
02130                                 lgErrorOccurred = true;
02131                                 invlen[i] = 0.;
02132                                 break;
02133                         }
02134                         frac = (wavlen-gd->wavlen[j][ind])/(gd->wavlen[j][ind+1]-gd->wavlen[j][ind]);
02135                         nim = (1.-frac)*gd->n[j][ind].imag() + frac*gd->n[j][ind+1].imag();
02136                         
02137 
02138                         InvDep = PI4*nim/wavlen*1.e4;
02139                         ASSERT( InvDep > 0. );
02140 
02141                         invlen[i] += InvDep*gd->wt[j];
02142                 }
02143         }
02144 
02145         if( lgErrorOccurred ) 
02146         {
02147                 mie_repair(chString,n,3,3,rfield.anu,invlen,ErrorIndex,false,lgWarning);
02148         }
02149 
02150         free( ErrorIndex );
02151         return;
02152 }
02153 
02154 
02155 
02156 #define NPTS_DERIV 8
02157 #define NPTS_COMB  (NPTS_DERIV*(NPTS_DERIV-1)/2)
02158 
02159 
02160 STATIC void mie_repair( const char *chString,
02161                        long int n,
02162                        int val,
02163                        int del,
02164                         realnum anu[],      
02165                        double data[],             
02166                         int ErrorIndex[], 
02167                        bool lgRound,
02168                         bool *lgWarning)
02169 {
02170         bool lgExtrapolate,
02171           lgVerbose;
02172         long int i1,
02173           i2,
02174           ind1,
02175           ind2,
02176           j;
02177         double dx,
02178           sgn,
02179           slp1,
02180           xlg1,
02181           xlg2,
02182           y1lg1,
02183           y1lg2;
02184 
02185         
02186         const long BIG_INTERPOLATION = 10;
02187 
02188         DEBUG_ENTRY( "mie_repair()" );
02189 
02190         lgVerbose = ( chString[0] != '\0' );
02191 
02192         for( ind1=0; ind1 < n; ) 
02193         {
02194                 if( ErrorIndex[ind1] == val ) 
02195                 {
02196                         
02197                         ind2 = ind1;
02198                         while( ind2 < n && ErrorIndex[ind2] == val )
02199                                 ind2++;
02200 
02201                         if( lgVerbose )
02202                                 fprintf( ioQQQ, "    %s", chString );
02203 
02204                         if( ind1 == 0 ) 
02205                         {
02206                                 
02207                                 i1 = ind2;
02208                                 i2 = ind2+NPTS_DERIV-1;
02209                                 lgExtrapolate = true;
02210                                 sgn = +1.;
02211                                 if( lgVerbose ) 
02212                                 {
02213                                         fprintf( ioQQQ, " extrapolated below %.4e Ryd\n",anu[i1] );
02214                                 }
02215                         }
02216                         else if( ind2 == n ) 
02217                         {
02218                                 
02219                                 i1 = ind1-NPTS_DERIV;
02220                                 i2 = ind1-1;
02221                                 lgExtrapolate = true;
02222                                 sgn = -1.;
02223                                 if( lgVerbose ) 
02224                                 {
02225                                         fprintf( ioQQQ, " extrapolated above %.4e Ryd\n",anu[i2] );
02226                                 }
02227                         }
02228                         else 
02229                         {
02230                                 
02231                                 i1 = ind1-1;
02232                                 i2 = ind2;
02233                                 lgExtrapolate = false;
02234                                 sgn = 0.;
02235                                 if( lgVerbose ) 
02236                                 {
02237                                         fprintf( ioQQQ, " interpolated between %.4e and %.4e Ryd\n",
02238                                                  anu[i1],anu[i2] );
02239                                 }
02240                                 if( i2-i1-1 > BIG_INTERPOLATION )
02241                                 {
02242                                         if( lgVerbose )
02243                                         {
02244                                                 fprintf( ioQQQ, " ***Warning: extensive interpolation used\n" );
02245                                         }
02246                                         *lgWarning = true;
02247                                 }
02248                         }
02249 
02250                         if( i1 < 0 || i2 >= n ) 
02251                         {
02252                                 fprintf( ioQQQ, " Insufficient data for extrapolation\n" );
02253                                 cdEXIT(EXIT_FAILURE);
02254                         }
02255 
02256                         xlg1 = log(anu[i1]);
02257                         y1lg1 = log(data[i1]);
02258                         
02259                         if( lgExtrapolate )
02260                                 slp1 = mie_find_slope(anu,data,ErrorIndex,i1,i2,val,lgVerbose,lgWarning);
02261                         else
02262                         {
02263                                 xlg2 = log(anu[i2]);
02264                                 y1lg2 = log(data[i2]);
02265                                 slp1 = (y1lg2-y1lg1)/(xlg2-xlg1);
02266                         }
02267                         if( lgRound && lgExtrapolate && sgn > 0. ) 
02268                         {
02269                                 
02270 
02271 
02272                                 slp1 = MAX2(slp1,0.);
02273                         }
02274                         
02275                         else if( lgExtrapolate && sgn*slp1 < 0. ) 
02276                         {
02277                                 fprintf( ioQQQ, " Illegal value for slope in extrapolation %.6e\n", slp1 );
02278                                 cdEXIT(EXIT_FAILURE);
02279                         }
02280 
02281                         for( j=ind1; j < ind2; j++ ) 
02282                         {
02283                                 dx = log(anu[j]) - xlg1;
02284                                 data[j] = exp(y1lg1 + dx*slp1);
02285                                 ErrorIndex[j] -= del;
02286                         }
02287 
02288                         ind1 = ind2;
02289                 }
02290                 else 
02291                 {
02292                         ind1++;
02293                 }
02294         }
02295         
02296         for( j=0; j < n; j++ )
02297         {
02298                 if( ErrorIndex[j] > val-del ) 
02299                 {
02300                         fprintf( ioQQQ, " Internal error in mie_repair, index=%ld, val=%d\n",j,ErrorIndex[j] );
02301                         ShowMe();
02302                         cdEXIT(EXIT_FAILURE);
02303                 }
02304         }
02305         return;
02306 }
02307 
02308 
02309 STATIC double mie_find_slope( const realnum anu[],
02310                               const double data[],
02311                               const int ErrorIndex[],
02312                              long i1,
02313                              long i2,
02314                              int val,
02315                              bool lgVerbose,
02316                               bool *lgWarning)
02317 {
02318         long i,
02319           j,
02320           k;
02321         double s1,
02322           s2,
02323           slope,
02324           slp1[NPTS_COMB],
02325           stdev;
02326 
02327         
02328 
02329         const double LARGE_STDEV = 0.2;
02330 
02331         DEBUG_ENTRY( "mie_find_slope()" );
02332 
02333         
02334         ASSERT( i2-i1 == NPTS_DERIV-1 );
02335         for( i=i1; i <= i2; i++ )
02336         {
02337                 ASSERT( ErrorIndex[i] < val );
02338                 ASSERT( anu[i] > 0. && data[i] > 0. );
02339         }
02340 
02341         
02342         for( i=0; i < NPTS_COMB; i++ )
02343         {
02344                 slp1[i] = -DBL_MAX;
02345         }
02346 
02347         k = 0;
02348         
02349         
02350         for( i=i1; i < i2; i++ )
02351         {
02352                 for( j=i+1; j <= i2; j++ )
02353                 {
02354                         slp1[k++] = log(data[j]/data[i])/log(anu[j]/anu[i]);
02355                 }
02356         }
02357         
02358         for( i=0; i <= NPTS_COMB/2; i++ )
02359         {
02360                 for( j=i+1; j < NPTS_COMB; j++ )
02361                 {
02362                         if( slp1[i] > slp1[j] )
02363                         {
02364                                 double xxx = slp1[i];
02365                                 slp1[i] = slp1[j];
02366                                 slp1[j] = xxx;
02367                         }
02368                 }
02369         }
02370         
02371         slope = ( NPTS_COMB%2 == 1 ) ? slp1[NPTS_COMB/2] : (slp1[NPTS_COMB/2-1] + slp1[NPTS_COMB/2])/2.;
02372 
02373         
02374         s1 = s2 = 0.;
02375         for( i=0; i < NPTS_COMB; i++ )
02376         {
02377                 s1 += slp1[i];
02378                 s2 += POW2(slp1[i]);
02379         }
02380         
02381         stdev = MAX2(s2/(double)NPTS_COMB - POW2(s1/(double)NPTS_COMB),0.);
02382         stdev = sqrt(stdev);
02383 
02384 #if 0
02385         for( i=i1; i <= i2; i++ )
02386                 printf("input: %ld %.4e %.4e\n",i,anu[i],data[i]);
02387         for( i=0; i < NPTS_COMB; i++ )
02388                 printf("%.3f ",slp1[i]);
02389         printf("\n");
02390         printf("slope %.3f +/- %.3f\n",slope,stdev);
02391 #endif
02392 
02393         
02394         if( stdev > LARGE_STDEV )
02395         {
02396                 if( lgVerbose )
02397                 {
02398                         fprintf( ioQQQ, " ***Warning: slope for extrapolation may be unreliable\n" );
02399                 }
02400                 *lgWarning = true;
02401         }
02402         return slope;
02403 }
02404 
02405 
02406 
02407 STATIC void mie_read_rfi(  const char *chFile,
02408                           grain_data *gd)
02409 {
02410         bool lgLogData=false;
02411         long int dl,
02412           help,
02413           i,
02414           nelem,
02415           j,
02416           nridf,
02417           sgn = 0;
02418         double eps1,
02419           eps2,
02420           LargestLog,
02421           molw,
02422           nAtoms,
02423           nr,
02424           ni,
02425           tmp1,
02426           tmp2,
02427           total = 0.;
02428         char chLine[FILENAME_PATH_LENGTH_2],
02429           chWord[FILENAME_PATH_LENGTH_2];
02430         FILE *io2;
02431 
02432         DEBUG_ENTRY( "mie_read_rfi()" );
02433 
02434         io2 = open_data( chFile, "r", AS_LOCAL_ONLY );
02435 
02436         dl = 0; 
02437 
02438         
02439         mie_next_data(chFile,io2,chLine,&dl);
02440         mie_read_long(chFile,chLine,&gd->magic,true,dl);
02441         if( gd->magic != MAGIC_RFI ) 
02442         {
02443                 fprintf( ioQQQ, " Refractive index file %s has obsolete magic number\n",chFile );
02444                 fprintf( ioQQQ, " I found %ld, but expected %ld on line #%ld\n",gd->magic,MAGIC_RFI,dl );
02445                 fprintf( ioQQQ, " Please replace this file with an up to date version\n" );
02446                 cdEXIT(EXIT_FAILURE);
02447         }
02448 
02449         
02450         mie_next_data(chFile,io2,chLine,&dl);
02451         mie_read_word(chLine,chWord,FILENAME_PATH_LENGTH_2,false);
02452         mie_read_form(chWord,gd->elmAbun,&nAtoms,&molw);
02453 
02454         
02455         gd->mol_weight = molw;
02456         gd->atom_weight = gd->mol_weight/nAtoms;
02457 
02458         
02459         mie_next_data(chFile,io2,chLine,&dl);
02460         mie_read_double(chFile,chLine,&gd->abun,true,dl);
02461 
02462         
02463         mie_next_data(chFile,io2,chLine,&dl);
02464         mie_read_double(chFile,chLine,&gd->depl,true,dl);
02465         if( gd->depl > 1. ) 
02466         {
02467                 fprintf( ioQQQ, " Illegal value for default depletion in %s\n",chFile );
02468                 fprintf( ioQQQ, " Line #%ld, depl=%14.6e\n",dl,gd->depl);
02469                 cdEXIT(EXIT_FAILURE);
02470         }
02471 
02472         for( nelem=0; nelem < LIMELM; nelem++ )
02473                 gd->elmAbun[nelem] *= gd->abun*gd->depl;
02474 
02475         
02476         mie_next_data(chFile,io2,chLine,&dl);
02477         mie_read_double(chFile,chLine,&gd->rho,false,dl);
02478 
02479         
02480         mie_next_data(chFile,io2,chLine,&dl);
02481         mie_read_long(chFile,chLine,&help,true,dl);
02482         gd->matType = (mat_type)help;
02483         if( gd->matType >= MAT_TOP ) 
02484         {
02485                 fprintf( ioQQQ, " Illegal value for material type in %s\n",chFile );
02486                 fprintf( ioQQQ, " Line #%ld, type=%d\n",dl,gd->matType);
02487                 cdEXIT(EXIT_FAILURE);
02488         }
02489 
02490         
02491         mie_next_data(chFile,io2,chLine,&dl);
02492         mie_read_double(chFile,chLine,&gd->work,true,dl);
02493 
02494         
02495         mie_next_data(chFile,io2,chLine,&dl);
02496         mie_read_double(chFile,chLine,&gd->bandgap,false,dl);
02497         if( gd->bandgap >= gd->work ) 
02498         {
02499                 fprintf( ioQQQ, " Illegal value for bandgap in %s\n",chFile );
02500                 fprintf( ioQQQ, " Line #%ld, bandgap=%.4e, work function=%.4e\n",dl,gd->bandgap,gd->work);
02501                 fprintf( ioQQQ, " Bandgap should always be less than work function\n");
02502                 cdEXIT(EXIT_FAILURE);
02503         }
02504 
02505         
02506         mie_next_data(chFile,io2,chLine,&dl);
02507         mie_read_double(chFile,chLine,&gd->therm_eff,true,dl);
02508         if( gd->therm_eff > 1.f ) 
02509         {
02510                 fprintf( ioQQQ, " Illegal value for thermionic efficiency in %s\n",chFile );
02511                 fprintf( ioQQQ, " Line #%ld, value=%.4e\n",dl,gd->therm_eff);
02512                 fprintf( ioQQQ, " Allowed values are 0. < efficiency <= 1.\n");
02513                 cdEXIT(EXIT_FAILURE);
02514         }
02515 
02516         
02517         mie_next_data(chFile,io2,chLine,&dl);
02518         mie_read_double(chFile,chLine,&gd->subl_temp,true,dl);
02519 
02520         
02521         mie_next_data(chFile,io2,chLine,&dl);
02522         mie_read_word(chLine,chWord,WORDLEN,true);
02523 
02524         if( nMatch( "RFI_", chWord ) )
02525                 gd->rfiType = RFI_TABLE;
02526         else if( nMatch( "OPC_", chWord ) )
02527                 gd->rfiType = OPC_TABLE;
02528         else if( nMatch( "GREY", chWord ) )
02529                 gd->rfiType = OPC_GREY;
02530         else if( nMatch( "PAH1", chWord ) )
02531                 gd->rfiType = OPC_PAH1;
02532         else
02533         {
02534                 fprintf( ioQQQ, " Illegal keyword in %s\n",chFile );
02535                 fprintf( ioQQQ, " Line #%ld, value=%s\n",dl,chWord);
02536                 fprintf( ioQQQ, " Allowed values are: RFI_TBL, OPC_TBL, GREY, PAH1\n");
02537                 cdEXIT(EXIT_FAILURE);
02538         }
02539 
02540         switch( gd->rfiType )
02541         {
02542         case RFI_TABLE:
02543                 
02544 
02545                 mie_next_data(chFile,io2,chLine,&dl);
02546                 mie_read_long(chFile,chLine,&nridf,true,dl);
02547                 if( nridf > 3 ) 
02548                 {
02549                         fprintf( ioQQQ, " Illegal data code in %s\n",chFile );
02550                         fprintf( ioQQQ, " Line #%ld, data code=%ld\n",dl,nridf);
02551                         cdEXIT(EXIT_FAILURE);
02552                 }
02553 
02554                 
02555 
02556                 mie_next_data(chFile,io2,chLine,&dl);
02557                 mie_read_long(chFile,chLine,&gd->nAxes,true,dl);
02558                 if( gd->nAxes > NAX ) 
02559                 {
02560                         fprintf( ioQQQ, " Illegal no. of axes in %s\n",chFile );
02561                         fprintf( ioQQQ, " Line #%ld, number=%ld\n",dl,gd->nAxes);
02562                         cdEXIT(EXIT_FAILURE);
02563                 }
02564 
02565                 
02566                 mie_next_data(chFile,io2,chLine,&dl);
02567                 switch( gd->nAxes ) 
02568                 {
02569                 case 1:
02570                         mie_read_double(chFile,chLine,&gd->wt[0],true,dl);
02571                         total = gd->wt[0];
02572                         break;
02573                 case 2:
02574                         if( sscanf( chLine, "%lf %lf", &gd->wt[0], &gd->wt[1] ) != 2 ) 
02575                         {
02576                                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02577                                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02578                                 cdEXIT(EXIT_FAILURE);
02579                         }
02580                         if( gd->wt[0] <= 0. || gd->wt[1] <= 0. ) 
02581                         {
02582                                 fprintf( ioQQQ, " Illegal data in %s\n",chFile);
02583                                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02584                                 cdEXIT(EXIT_FAILURE);
02585                         }
02586                         total = gd->wt[0] + gd->wt[1];
02587                         break;
02588                 case 3:
02589                         if( sscanf( chLine, "%lf %lf %lf", &gd->wt[0], &gd->wt[1], &gd->wt[2] ) != 3 ) 
02590                         {
02591                                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02592                                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02593                                 cdEXIT(EXIT_FAILURE);
02594                         }
02595                         if( gd->wt[0] <= 0. || gd->wt[1] <= 0. || gd->wt[2] <= 0. ) 
02596                         {
02597                                 fprintf( ioQQQ, " Illegal data in %s\n",chFile);
02598                                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02599                                 cdEXIT(EXIT_FAILURE);
02600                         }
02601                         total = gd->wt[0] + gd->wt[1] + gd->wt[2];
02602                         break;
02603                 default:
02604                         fprintf( ioQQQ, " insane case for gd->nAxes: %ld\n", gd->nAxes );
02605                         ShowMe();
02606                         cdEXIT(EXIT_FAILURE);
02607                 }
02608                 for( j=0; j < gd->nAxes; j++ ) 
02609                 {
02610                         gd->wt[j] /= total;
02611 
02612                         
02613                         mie_next_data(chFile,io2,chLine,&dl);
02614                         mie_read_long(chFile,chLine,&gd->ndata[j],false,dl);
02615                         if( gd->ndata[j] < 2 ) 
02616                         {
02617                                 fprintf( ioQQQ, " Illegal number of data points in %s\n",chFile );
02618                                 fprintf( ioQQQ, " Line #%ld, number=%ld\n",dl,gd->ndata[j]);
02619                                 cdEXIT(EXIT_FAILURE);
02620                         }
02621 
02622                         
02623 
02624                         gd->wavlen[j] = (double*)MALLOC(sizeof(double)*(unsigned)gd->ndata[j]);
02625                         gd->n[j] = (complex<double>*)MALLOC(sizeof(complex<double>)*(unsigned)gd->ndata[j]);
02626                         gd->nr1[j] = (double*)MALLOC(sizeof(double)*(unsigned)gd->ndata[j]);
02627 
02628                         for( i=0; i < gd->ndata[j]; i++ ) 
02629                         {
02630                                 
02631 
02632                                 mie_next_data(chFile,io2,chLine,&dl);
02633                                 if( sscanf( chLine, "%lf %lf %lf", gd->wavlen[j]+i, &nr, &ni ) != 3 ) 
02634                                 {
02635                                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02636                                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02637                                         cdEXIT(EXIT_FAILURE);
02638                                 }
02639                                 if( gd->wavlen[j][i] <= 0. ) 
02640                                 {
02641                                         fprintf( ioQQQ, " Illegal value for wavelength in %s\n",chFile);
02642                                         fprintf( ioQQQ, " Line #%ld, wavl=%14.6e\n",dl,gd->wavlen[j][i]);
02643                                         cdEXIT(EXIT_FAILURE);
02644                                 }
02645                                 
02646 
02647                                 if( i == 1 )
02648                                 {
02649                                         sgn = sign3(gd->wavlen[j][1]-gd->wavlen[j][0]);
02650                                         if( sgn == 0 ) 
02651                                         {
02652                                                 fprintf( ioQQQ, " Illegal value for wavelength in %s\n",chFile);
02653                                                 fprintf( ioQQQ, " Line #%ld, wavl=%14.6e\n",dl,gd->wavlen[j][i]);
02654                                                 cdEXIT(EXIT_FAILURE);
02655                                         }
02656                                 }
02657                                 else if( i > 1 ) 
02658                                 {
02659                                         if( sign3(gd->wavlen[j][i]-gd->wavlen[j][i-1]) != sgn ) 
02660                                         {
02661                                                 fprintf( ioQQQ, " Illegal value for wavelength in %s\n",chFile);
02662                                                 fprintf( ioQQQ, " Line #%ld, wavl=%14.6e\n",dl,gd->wavlen[j][i]);
02663                                                 cdEXIT(EXIT_FAILURE);
02664                                         }
02665                                 }
02666                                 
02667 
02668 
02669                                 switch( nridf ) 
02670                                 {
02671                                 case 1:
02672                                         eps1 = nr;
02673                                         eps2 = ni;
02674                                         dftori(&nr,&ni,eps1,eps2);
02675                                         gd->nr1[j][i] = nr - 1.;
02676                                         break;
02677                                 case 2:
02678                                         gd->nr1[j][i] = nr;
02679                                         nr += 1.;
02680                                         break;
02681                                 case 3:
02682                                         gd->nr1[j][i] = nr - 1.;
02683                                         break;
02684                                 default:
02685                                         fprintf( ioQQQ, " insane case for nridf: %ld\n", nridf );
02686                                         ShowMe();
02687                                         cdEXIT(EXIT_FAILURE);
02688                                 }
02689                                 gd->n[j][i] = complex<double>(nr,ni);
02690 
02691                                 
02692                                 if( nr <= 0. || ni < 0. ) 
02693                                 {
02694                                         fprintf( ioQQQ, " Illegal value for refractive index in %s\n",chFile);
02695                                         fprintf( ioQQQ, " Line #%ld, (nr,ni)=(%14.6e,%14.6e)\n",dl,nr,ni);
02696                                         cdEXIT(EXIT_FAILURE);
02697                                 }
02698                                 ASSERT( fabs(nr-1.-gd->nr1[j][i]) < 10.*nr*DBL_EPSILON );
02699                         }
02700                 }
02701                 break;
02702         case OPC_TABLE:
02703                 
02704 
02705 
02706 
02707 
02708 
02709                 mie_next_data(chFile,io2,chLine,&dl);
02710                 mie_read_long(chFile,chLine,&gd->nOpcCols,true,dl);
02711                 if( gd->nOpcCols > NDAT ) 
02712                 {
02713                         fprintf( ioQQQ, " Illegal no. of data columns in %s\n",chFile );
02714                         fprintf( ioQQQ, " Line #%ld, number=%ld\n",dl,gd->nOpcCols);
02715                         cdEXIT(EXIT_FAILURE);
02716                 }
02717 
02718                 
02719                 mie_next_data(chFile,io2,chLine,&dl);
02720                 mie_read_word(chLine,chWord,WORDLEN,true);
02721 
02722                 if( nMatch( "LINE", chWord ) )
02723                         lgLogData = false;
02724                 else if( nMatch( "LOG", chWord ) )
02725                         lgLogData = true;
02726                 else
02727                 {
02728                         fprintf( ioQQQ, " Keyword not recognized in %s\n",chFile );
02729                         fprintf( ioQQQ, " Line #%ld, keyword=%s\n",dl,chWord);
02730                         cdEXIT(EXIT_FAILURE);
02731                 }
02732 
02733 
02734                 
02735                 mie_next_data(chFile,io2,chLine,&dl);
02736                 mie_read_long(chFile,chLine,&gd->nOpcData,false,dl);
02737                 if( gd->nOpcData < 2 ) 
02738                 {
02739                         fprintf( ioQQQ, " Illegal number of data points in %s\n",chFile );
02740                         fprintf( ioQQQ, " Line #%ld, number=%ld\n",dl,gd->nOpcData);
02741                         cdEXIT(EXIT_FAILURE);
02742                 }
02743 
02744                 
02745 
02746                 gd->opcAnu = (double*)MALLOC(sizeof(double)*(unsigned)gd->nOpcData);
02747                 for( j=0; j < gd->nOpcCols; j++ ) 
02748                 {
02749                         gd->opcData[j] = (double*)MALLOC(sizeof(double)*(unsigned)gd->nOpcData);
02750                 }
02751 
02752                 tmp1 = -log10(1.01*DBL_MIN);
02753                 tmp2 = log10(0.99*DBL_MAX);
02754                 LargestLog = MIN2(tmp1,tmp2);
02755 
02756                 
02757 
02758 
02759 
02760 
02761 
02762 
02763 
02764 
02765                 for( i=0; i < gd->nOpcData; i++ ) 
02766                 {
02767                         mie_next_data(chFile,io2,chLine,&dl);
02768                         switch( gd->nOpcCols )
02769                         {
02770                         case 1:
02771                                 if( sscanf( chLine, "%lf %lf", &gd->opcAnu[i], &gd->opcData[0][i] ) != 2 ) 
02772                                 {
02773                                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02774                                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02775                                         cdEXIT(EXIT_FAILURE);
02776                                 }
02777                                 break;
02778                         case 2:
02779                                 if( sscanf( chLine, "%lf %lf %lf", &gd->opcAnu[i], &gd->opcData[0][i],
02780                                             &gd->opcData[1][i] ) != 3 ) 
02781                                 {
02782                                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02783                                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02784                                         cdEXIT(EXIT_FAILURE);
02785                                 }
02786                                 break;
02787                         case 3:
02788                                 if( sscanf( chLine, "%lf %lf %lf %lf", &gd->opcAnu[i], &gd->opcData[0][i],
02789                                             &gd->opcData[1][i], &gd->opcData[2][i] ) != 4 ) 
02790                                 {
02791                                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02792                                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02793                                         cdEXIT(EXIT_FAILURE);
02794                                 }
02795                                 break;
02796                         case 4:
02797                                 if( sscanf( chLine, "%lf %lf %lf %lf %lf", &gd->opcAnu[i], &gd->opcData[0][i],
02798                                             &gd->opcData[1][i], &gd->opcData[2][i], &gd->opcData[3][i] ) != 5 ) 
02799                                 {
02800                                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
02801                                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
02802                                         cdEXIT(EXIT_FAILURE);
02803                                 }
02804                                 break;
02805                         default:
02806                                 fprintf( ioQQQ, " insane case for gd->nOpcCols: %ld\n", gd->nOpcCols );
02807                                 ShowMe();
02808                                 cdEXIT(EXIT_FAILURE);
02809                         }
02810                         if( lgLogData )
02811                         {
02812                                 
02813                                 if( fabs(gd->opcAnu[i]) > LargestLog )
02814                                 {
02815                                         fprintf( ioQQQ, " Illegal value for frequency in %s\n",chFile );
02816                                         fprintf( ioQQQ, " Line #%ld, freq=%14.6e\n",dl,gd->opcAnu[i] );
02817                                         cdEXIT(EXIT_FAILURE);
02818                                 }
02819                                 gd->opcAnu[i] = pow(10.,gd->opcAnu[i]);
02820                                 for( j=0; j < gd->nOpcCols; j++ )
02821                                 {
02822                                         if( fabs(gd->opcData[j][i]) > LargestLog )
02823                                         {
02824                                                 fprintf( ioQQQ, " Illegal data value in %s\n",chFile );
02825                                                 fprintf( ioQQQ, " Line #%ld, value=%14.6e\n",dl,gd->opcData[j][i] );
02826                                                 cdEXIT(EXIT_FAILURE);
02827                                         }
02828                                         gd->opcData[j][i] = pow(10.,gd->opcData[j][i]);
02829                                 }
02830                         }
02831                         if( gd->opcAnu[i] <= 0. )
02832                         {
02833                                 fprintf( ioQQQ, " Illegal value for frequency in %s\n",chFile );
02834                                 fprintf( ioQQQ, " Line #%ld, freq=%14.6e\n",dl,gd->opcAnu[i] );
02835                                 cdEXIT(EXIT_FAILURE);
02836                         }
02837                         for( j=0; j < gd->nOpcCols; j++ )
02838                         {
02839                                 if( gd->opcData[j][i] <= 0. )
02840                                 {
02841                                         fprintf( ioQQQ, " Illegal data value in %s\n",chFile );
02842                                         fprintf( ioQQQ, " Line #%ld, value=%14.6e\n",dl,gd->opcData[j][i] );
02843                                         cdEXIT(EXIT_FAILURE);
02844                                 }
02845                         }
02846                         
02847 
02848                         if( i == 1 )
02849                         {
02850                                 sgn = sign3(gd->opcAnu[1]-gd->opcAnu[0]);
02851                                 if( sgn == 0 ) 
02852                                 {
02853                                         double dataVal = lgLogData ? log10(gd->opcAnu[1]) : gd->opcAnu[1];
02854                                         fprintf( ioQQQ, " Illegal value for frequency in %s\n",chFile );
02855                                         fprintf( ioQQQ, " Line #%ld, freq=%14.6e\n",dl,dataVal );
02856                                         cdEXIT(EXIT_FAILURE);
02857                                 }
02858                         }
02859                         else if( i > 1 ) 
02860                         {
02861                                 if( sign3(gd->opcAnu[i]-gd->opcAnu[i-1]) != sgn ) 
02862                                 {
02863                                         double dataVal = lgLogData ? log10(gd->opcAnu[i]) : gd->opcAnu[i];
02864                                         fprintf( ioQQQ, " Illegal value for frequency in %s\n",chFile);
02865                                         fprintf( ioQQQ, " Line #%ld, freq=%14.6e\n",dl,dataVal);
02866                                         cdEXIT(EXIT_FAILURE);
02867                                 }
02868                         }
02869                 }
02870                 gd->nAxes = 1;
02871                 break;
02872         case OPC_GREY:
02873         case OPC_PAH1:
02874                 
02875 
02876                 gd->nAxes = 1;
02877                 break;
02878         default:
02879                 fprintf( ioQQQ, " Insane value for gd->rfiType: %d, bailing out\n", gd->rfiType );
02880                 ShowMe();
02881                 cdEXIT(EXIT_FAILURE);
02882         }
02883 
02884         fclose(io2);
02885         return;
02886 }
02887 
02888 
02889 
02890 STATIC void mie_read_mix(  const char *chFile,
02891                           grain_data *gd)
02892 {
02893         emt_type EMTtype;
02894         long int dl,
02895           i,
02896           j,
02897           k,
02898           l,
02899           nelem,
02900           nMaterial,
02901           sumAxes;
02902         double *delta,
02903           *frac,
02904           *frac2,
02905           *frdelta,
02906           maxIndex = DBL_MAX,
02907           minIndex = DBL_MAX,
02908           nAtoms,
02909           sum,
02910           sum2,
02911           wavHi,
02912           wavLo,
02913           wavStep;
02914         complex<double> *eps,
02915           eps_eff(-DBL_MAX,-DBL_MAX);
02916         char chLine[FILENAME_PATH_LENGTH_2],
02917           chWord[FILENAME_PATH_LENGTH_2],
02918           *str;
02919         grain_data *gdArr;
02920         FILE *io2;
02921 
02922         DEBUG_ENTRY( "mie_read_mix()" );
02923 
02924         io2 = open_data( chFile, "r", AS_LOCAL_ONLY );
02925 
02926         dl = 0; 
02927 
02928         
02929         mie_next_data(chFile,io2,chLine,&dl);
02930         mie_read_long(chFile,chLine,&gd->magic,true,dl);
02931         if( gd->magic != MAGIC_MIX ) 
02932         {
02933                 fprintf( ioQQQ, " Mixed grain file %s has obsolete magic number\n",chFile );
02934                 fprintf( ioQQQ, " I found %ld, but expected %ld on line #%ld\n",gd->magic,MAGIC_MIX,dl );
02935                 fprintf( ioQQQ, " Please replace this file with an up to date version\n" );
02936                 cdEXIT(EXIT_FAILURE);
02937         }
02938 
02939         
02940         mie_next_data(chFile,io2,chLine,&dl);
02941         mie_read_double(chFile,chLine,&gd->depl,true,dl);
02942         if( gd->depl > 1. ) 
02943         {
02944                 fprintf( ioQQQ, " Illegal value for default depletion in %s\n",chFile );
02945                 fprintf( ioQQQ, " Line #%ld, depl=%14.6e\n",dl,gd->depl);
02946                 cdEXIT(EXIT_FAILURE);
02947         }
02948 
02949         
02950         mie_next_data(chFile,io2,chLine,&dl);
02951         mie_read_long(chFile,chLine,&nMaterial,true,dl);
02952         if( nMaterial < 2 ) 
02953         {
02954                 fprintf( ioQQQ, " Illegal number of materials in mixed grain file %s\n",chFile );
02955                 fprintf( ioQQQ, " I found %ld on line #%ld\n",nMaterial,dl );
02956                 fprintf( ioQQQ, " This number should be at least 2\n" );
02957                 cdEXIT(EXIT_FAILURE);
02958         }
02959 
02960         frac = (double*)MALLOC(sizeof(double)*(unsigned)nMaterial);
02961         frac2 = (double*)MALLOC(sizeof(double)*(unsigned)nMaterial);
02962         gdArr = (grain_data*)MALLOC(sizeof(grain_data)*(unsigned)nMaterial);
02963 
02964         sum = 0.;
02965         sum2 = 0.;
02966         sumAxes = 0;
02967         for( i=0; i < nMaterial; i++ )
02968         {
02969                 char chFile2[FILENAME_PATH_LENGTH_2];
02970 
02971                 gdArr[i].nAxes = 0;
02972                 for( j=0; j < NAX; j++ ) 
02973                 {
02974                         gdArr[i].wavlen[j] = NULL;
02975                         gdArr[i].n[j] = NULL;
02976                         gdArr[i].nr1[j] = NULL;
02977                 }
02978                 gdArr[i].nOpcCols = 0;
02979                 gdArr[i].opcAnu = NULL;
02980                 for( j=0; j < NDAT; j++ )
02981                 {
02982                         gdArr[i].opcData[j] = NULL;
02983                 }
02984 
02985                 
02986 
02987                 mie_next_data(chFile,io2,chLine,&dl);
02988                 mie_read_double(chFile,chLine,&frac[i],true,dl);
02989 
02990                 sum += frac[i];
02991 
02992                 str = strchr( chLine, '\"' );
02993                 if( str != NULL )
02994                 {
02995                         strcpy( chFile2, ++str );
02996                         str = strchr( chFile2, '\"' );
02997                         if( str != NULL )
02998                                 *str = '\0';
02999                 }
03000                 if( str == NULL )
03001                 {
03002                         fprintf( ioQQQ, " No pair of double quotes was found on line #%ld of file %s\n",dl,chFile );
03003                         fprintf( ioQQQ, " Please supply the refractive index file name between double quotes\n" );
03004                         cdEXIT(EXIT_FAILURE);
03005                 }
03006 
03007                 mie_read_rfi( chFile2, &gdArr[i] );
03008                 if( gdArr[i].rfiType != RFI_TABLE )
03009                 {
03010                         fprintf( ioQQQ, " Input error on line #%ld of file %s\n",dl,chFile );
03011                         fprintf( ioQQQ, " File %s is not of type RFI_TBL, this is illegal\n",chFile2 );
03012                         cdEXIT(EXIT_FAILURE);
03013                 }
03014 
03015                 
03016                 if( i == nMaterial-1 && gdArr[i].mol_weight == 0. )
03017                 {
03018                         fprintf( ioQQQ, " Input error on line #%ld of file %s\n",dl,chFile );
03019                         fprintf( ioQQQ, " Last entry in list of materials is vacuum, this is not allowed\n" );
03020                         fprintf( ioQQQ, " Please move this entry to an earlier position in the file\n" );
03021                         cdEXIT(EXIT_FAILURE);
03022                 }
03023 
03024                 frac2[i] = ( gdArr[i].mol_weight > 0. ) ? frac[i] : 0.;
03025                 sum2 += frac2[i];
03026 
03027                 sumAxes += gdArr[i].nAxes;
03028         }
03029 
03030         
03031         mie_next_data(chFile,io2,chLine,&dl);
03032         mie_read_word(chLine,chWord,WORDLEN,true);
03033 
03034         if( nMatch( "FA00", chWord ) )
03035                 EMTtype = FARAFONOV00;
03036         else if( nMatch( "ST95", chWord ) )
03037                 EMTtype = STOGNIENKO95;
03038         else if( nMatch( "BR35", chWord ) )
03039                 EMTtype = BRUGGEMAN35;
03040         else
03041         {
03042                 fprintf( ioQQQ, " Keyword not recognized in %s\n",chFile );
03043                 fprintf( ioQQQ, " Line #%ld, keyword=%s\n",dl,chWord);
03044                 cdEXIT(EXIT_FAILURE);
03045         }
03046 
03047         
03048         for( i=0; i < nMaterial; i++ )
03049         {
03050                 frac[i] /= sum;
03051                 frac2[i] /= sum2;
03052                 
03053                 for( nelem=0; nelem < LIMELM; nelem++ )
03054                 {
03055                         gdArr[i].elmAbun[nelem] /= gdArr[i].abun*gdArr[i].depl;
03056                 }
03057         }
03058 
03059         wavLo = 0.;
03060         wavHi = DBL_MAX;
03061         gd->abun = DBL_MAX;
03062         for( nelem=0; nelem < LIMELM; nelem++ )
03063         {
03064                 gd->elmAbun[nelem] = 0.;
03065         }
03066         gd->mol_weight = 0.;
03067         gd->rho = 0.;
03068         gd->work = DBL_MAX;
03069         gd->bandgap = DBL_MAX;
03070         gd->therm_eff = 0.;
03071         gd->subl_temp = DBL_MAX;
03072         gd->nAxes = 1;
03073         gd->wt[0] = 1.;
03074         gd->ndata[0] = MIX_TABLE_SIZE;
03075         gd->rfiType = RFI_TABLE;
03076 
03077         for( i=0; i < nMaterial; i++ )
03078         {
03079                 for( k=0; k < gdArr[i].nAxes; k++ )
03080                 {
03081                         double wavMin = MIN2(gdArr[i].wavlen[k][0],gdArr[i].wavlen[k][gdArr[i].ndata[k]-1]);
03082                         double wavMax = MAX2(gdArr[i].wavlen[k][0],gdArr[i].wavlen[k][gdArr[i].ndata[k]-1]);
03083                         wavLo = MAX2(wavLo,wavMin);
03084                         wavHi = MIN2(wavHi,wavMax);
03085                 }
03086                 minIndex = DBL_MAX;
03087                 maxIndex = 0.;
03088                 for( nelem=0; nelem < LIMELM; nelem++ )
03089                 {
03090                         gd->elmAbun[nelem] += frac[i]*gdArr[i].elmAbun[nelem];
03091                         if( gd->elmAbun[nelem] > 0. )
03092                         {
03093                                 minIndex = MIN2(minIndex,gd->elmAbun[nelem]);
03094                         }
03095                         maxIndex = MAX2(maxIndex,gd->elmAbun[nelem]);
03096                 }
03097                 gd->mol_weight += frac[i]*gdArr[i].mol_weight;
03098                 gd->rho += frac[i]*gdArr[i].rho;
03099                 
03100                 if( gdArr[i].mol_weight > 0. )
03101                 {
03102                         gd->abun = MIN2(gd->abun,gdArr[i].abun/frac[i]);
03103                         switch( EMTtype )
03104                         {
03105                         case FARAFONOV00:
03106                                 
03107                                 gd->work = gdArr[i].work;
03108                                 gd->bandgap = gdArr[i].bandgap;
03109                                 gd->therm_eff = gdArr[i].therm_eff;
03110                                 break;
03111                         case STOGNIENKO95:
03112                         case BRUGGEMAN35:
03113                                 
03114                                 gd->work = MIN2(gd->work,gdArr[i].work);
03115                                 gd->bandgap = MIN2(gd->bandgap,gdArr[i].bandgap);
03116                                 gd->therm_eff += frac2[i]*gdArr[i].therm_eff;
03117                                 break;
03118                         default:
03119                                 fprintf( ioQQQ, " Insanity in mie_read_mix\n" );
03120                                 ShowMe();
03121                                 cdEXIT(EXIT_FAILURE);
03122                         }
03123                         gd->matType = gdArr[i].matType;
03124                         gd->subl_temp = MIN2(gd->subl_temp,gdArr[i].subl_temp);
03125                 }
03126         }
03127 
03128         if( gd->rho <= 0. )
03129         {
03130                 fprintf( ioQQQ, " Illegal value for the density: %.3e\n", gd->rho );
03131                 cdEXIT(EXIT_FAILURE);
03132         }
03133         if( gd->mol_weight <= 0. )
03134         {
03135                 fprintf( ioQQQ, " Illegal value for the molecular weight: %.3e\n", gd->mol_weight );
03136                 cdEXIT(EXIT_FAILURE);
03137         }
03138         if( maxIndex <= 0. )
03139         {
03140                 fprintf( ioQQQ, " No atoms were found in the grain molecule\n" );
03141                 cdEXIT(EXIT_FAILURE);
03142         }
03143 
03144         
03145         ASSERT( wavLo > 0. && wavHi < DBL_MAX && wavLo < wavHi );
03146         ASSERT( gd->abun > 0. && gd->abun < DBL_MAX );
03147         ASSERT( gd->work > 0. && gd->work < DBL_MAX );
03148         ASSERT( gd->bandgap >= 0. && gd->bandgap < gd->work );
03149         ASSERT( gd->therm_eff > 0. && gd->therm_eff <= 1. );
03150         ASSERT( gd->subl_temp > 0. && gd->subl_temp < DBL_MAX );
03151         ASSERT( minIndex > 0. && minIndex < DBL_MAX );
03152 
03153         
03154         wavLo *= 1. + 10.*DBL_EPSILON;
03155         wavHi *= 1. - 10.*DBL_EPSILON;
03156 
03157         
03158         nAtoms = 0.;
03159         for( nelem=0; nelem < LIMELM; nelem++ )
03160         {
03161                 gd->elmAbun[nelem] /= minIndex;
03162                 nAtoms += gd->elmAbun[nelem];
03163         }
03164         ASSERT( nAtoms > 0. );
03165         gd->abun *= minIndex;
03166         gd->mol_weight /= minIndex;
03167         
03168         gd->atom_weight = gd->mol_weight/nAtoms;
03169 
03170         mie_write_form(gd->elmAbun,chWord);
03171         fprintf( ioQQQ, "\n The chemical formula of the new grain molecule is: %s\n", chWord );
03172         fprintf( ioQQQ, " The abundance wrt H at maximum depletion of this molecule is: %.3e\n",
03173                  gd->abun );
03174         fprintf( ioQQQ, " The abundance wrt H at standard depletion of this molecule is: %.3e\n",
03175                  gd->abun*gd->depl );
03176 
03177         
03178         for( nelem=0; nelem < LIMELM; nelem++ )
03179         {
03180                 gd->elmAbun[nelem] *= gd->abun*gd->depl;
03181         }
03182 
03183         delta = (double*)MALLOC(sizeof(double)*(unsigned)sumAxes);
03184         frdelta = (double*)MALLOC(sizeof(double)*(unsigned)sumAxes);
03185         eps = (complex<double>*)MALLOC(sizeof(complex<double>)*(unsigned)sumAxes);
03186 
03187         l = 0;
03188         for( i=0; i < nMaterial; i++ )
03189         {
03190                 for( k=0; k < gdArr[i].nAxes; k++ )
03191                 {
03192                         frdelta[l] = gdArr[i].wt[k]*frac[i];
03193                         delta[l] = ( l == 0 ) ? frdelta[l] : delta[l-1] + frdelta[l];
03194                         ++l;
03195                 }
03196         }
03197         ASSERT( l == sumAxes && fabs(delta[l-1]-1.) < 10.*DBL_EPSILON );
03198 
03199         
03200 
03201         gd->wavlen[0] = (double*)MALLOC(sizeof(double)*(unsigned)gd->ndata[0]);
03202         gd->n[0] = (complex<double>*)MALLOC(sizeof(complex<double>)*(unsigned)gd->ndata[0]);
03203         gd->nr1[0] = (double*)MALLOC(sizeof(double)*(unsigned)gd->ndata[0]);
03204 
03205         wavStep = log(wavHi/wavLo)/(double)(gd->ndata[0]-1);
03206 
03207         switch( EMTtype )
03208         {
03209         case FARAFONOV00:
03210                 
03211 
03212 
03213 
03214 
03215 
03216                 for( j=0; j < gd->ndata[0]; j++ )
03217                 {
03218                         double nre,nim;
03219                         complex<double> a1,a2,a1c,a2c,a11,a12,a21,a22,ratio;
03220 
03221                         gd->wavlen[0][j] = wavLo*exp((double)j*wavStep);
03222 
03223                         init_eps(gd->wavlen[0][j],nMaterial,gdArr,eps);
03224 
03225                         ratio = eps[0]/eps[1];
03226 
03227                         a1 = (ratio+2.)/3.;
03228                         a2 = (1.-ratio)*delta[0];
03229 
03230                         for( l=1; l < sumAxes-1; l++ )
03231                         {
03232                                 ratio = eps[l]/eps[l+1];
03233 
03234                                 a1c = a1;
03235                                 a2c = a2;
03236                                 a11 = (ratio+2.)/3.;
03237                                 a12 = (2.-2.*ratio)/(9.*delta[l]);
03238                                 a21 = (1.-ratio)*delta[l];
03239                                 a22 = (2.*ratio+1.)/3.;
03240 
03241                                 a1 = a11*a1c + a12*a2c;
03242                                 a2 = a21*a1c + a22*a2c;
03243                         }
03244 
03245                         a1c = a1;
03246                         a2c = a2;
03247                         a11 = 1.;
03248                         a12 = 1./3.;
03249                         a21 = eps[sumAxes-1];
03250                         a22 = -2./3.*eps[sumAxes-1];
03251 
03252                         a1 = a11*a1c + a12*a2c;
03253                         a2 = a21*a1c + a22*a2c;
03254 
03255                         ratio = a2/a1;
03256                         dftori(&nre,&nim,ratio.real(),ratio.imag());
03257 
03258                         gd->n[0][j] = complex<double>(nre,nim);
03259                         gd->nr1[0][j] = nre-1.;
03260                 }
03261                 break;
03262         case STOGNIENKO95:
03263         case BRUGGEMAN35:
03264                 for( j=0; j < gd->ndata[0]; j++ )
03265                 {
03266                         const double EPS_TOLER = 10.*DBL_EPSILON;
03267                         double nre,nim;
03268                         complex<double> eps0;
03269 
03270                         gd->wavlen[0][j] = wavLo*exp((double)j*wavStep);
03271 
03272                         init_eps(gd->wavlen[0][j],nMaterial,gdArr,eps);
03273 
03274                         
03275                         if( j == 0 )
03276                         {
03277                                 
03278                                 eps0 = 0.;
03279                                 for( l=0; l < sumAxes; l++ )
03280                                         eps0 += frdelta[l]*eps[l];
03281                         }
03282                         else
03283                         {
03284                                 
03285                                 eps0 = eps_eff;
03286                         }
03287 
03288                         if( EMTtype == STOGNIENKO95 )
03289                                 
03290 
03291                                 eps_eff = cnewton( Stognienko, frdelta, eps, sumAxes, eps0, EPS_TOLER );
03292                         else if( EMTtype == BRUGGEMAN35 )
03293                                 
03294 
03295                                 eps_eff = cnewton( Bruggeman, frdelta, eps, sumAxes, eps0, EPS_TOLER );
03296                         else
03297                         {
03298                                 fprintf( ioQQQ, " Insanity in mie_read_mix\n" );
03299                                 ShowMe();
03300                                 cdEXIT(EXIT_FAILURE);
03301                         }
03302 
03303                         dftori(&nre,&nim,eps_eff.real(),eps_eff.imag());
03304 
03305                         gd->n[0][j] = complex<double>(nre,nim);
03306                         gd->nr1[0][j] = nre-1.;
03307                 }
03308                 break;
03309         default:
03310                 fprintf( ioQQQ, " Insanity in mie_read_mix\n" );
03311                 ShowMe();
03312                 cdEXIT(EXIT_FAILURE);
03313         }
03314 
03315         
03316         for( i=0; i < nMaterial; i++ )
03317         {
03318                 for( j=0; j < gdArr[i].nOpcCols; j++ ) 
03319                 {
03320                         if( gdArr[i].opcData[j] != NULL )
03321                                 free(gdArr[i].opcData[j]);
03322                 }
03323                 if( gdArr[i].opcAnu != NULL )
03324                         free(gdArr[i].opcAnu);
03325                 for( j=0; j < gdArr[i].nAxes; j++ ) 
03326                 {
03327                         if( gdArr[i].nr1[j] != NULL )
03328                                 free(gdArr[i].nr1[j]);
03329                         if( gdArr[i].n[j] != NULL )
03330                                 free(gdArr[i].n[j]);
03331                         if( gdArr[i].wavlen[j] != NULL )
03332                                 free(gdArr[i].wavlen[j]);
03333                 }
03334         }
03335         
03336         free(eps);
03337         free(frdelta);
03338         free(delta);
03339         free(gdArr);
03340         free(frac2);
03341         free(frac);
03342         return;
03343 }
03344 
03345 
03346 
03347 STATIC void init_eps(double wavlen,
03348                      long nMaterial,
03349                       grain_data gdArr[],  
03350                       complex<double> eps[])      
03351 {
03352         long i,
03353           k;
03354 
03355         long l = 0;
03356 
03357         DEBUG_ENTRY( "init_eps()" );
03358         for( i=0; i < nMaterial; i++ )
03359         {
03360                 for( k=0; k < gdArr[i].nAxes; k++ )
03361                 {
03362                         bool lgErr;
03363                         long ind;
03364                         double eps1,eps2,frc,nim,nre;
03365 
03366                         find_arr(wavlen,gdArr[i].wavlen[k],gdArr[i].ndata[k],&ind,&lgErr);
03367                         ASSERT( !lgErr );
03368                         frc = (wavlen-gdArr[i].wavlen[k][ind])/(gdArr[i].wavlen[k][ind+1]-gdArr[i].wavlen[k][ind]);
03369                         ASSERT( frc > 0.-10.*DBL_EPSILON && frc < 1.+10.*DBL_EPSILON );
03370                         nre = (1.-frc)*gdArr[i].n[k][ind].real() + frc*gdArr[i].n[k][ind+1].real();
03371                         ASSERT( nre > 0. );
03372                         nim = (1.-frc)*gdArr[i].n[k][ind].imag() + frc*gdArr[i].n[k][ind+1].imag();
03373                         ASSERT( nim >= 0. );
03374                         ritodf(nre,nim,&eps1,&eps2);
03375                         eps[l++] = complex<double>(eps1,eps2);
03376                 }
03377         }
03378         return;
03379 }
03380 
03381 
03382 
03383 
03384 
03385 
03386 
03387 
03388 
03389 
03390 
03391 STATIC complex<double> cnewton(
03392         void(*fun)(complex<double>,double[],complex<double>[],long,complex<double>*,double*,double*),
03393          double frdelta[],         
03394          complex<double> eps[],    
03395         long sumAxes,
03396         complex<double> x0,
03397         double tol)
03398 {
03399         int i;
03400 
03401         const int LOOP_MAX = 100;
03402         const double TINY = 1.e-12;
03403 
03404         DEBUG_ENTRY( "cnewton()" );
03405         for( i=0; i < LOOP_MAX; i++ )
03406         {
03407                 complex<double> x1,y;
03408                 double dudx,dudy,norm2;
03409 
03410                 (*fun)(x0,frdelta,eps,sumAxes,&y,&dudx,&dudy);
03411 
03412                 norm2 = POW2(dudx) + POW2(dudy);
03413                 
03414                 if( norm2 < TINY*norm(y) )
03415                 {
03416                         fprintf( ioQQQ, " cnewton - zero divide error\n" );
03417                         ShowMe();
03418                         cdEXIT(EXIT_FAILURE);
03419                 }
03420                 x1 = x0 - complex<double>( y.real()*dudx-y.imag()*dudy, y.imag()*dudx+y.real()*dudy )/norm2;
03421 
03422                 
03423                 if( fabs(x0.real()/x1.real()-1.) + fabs(x0.imag()/x1.imag()-1.) < tol )
03424                 {
03425                         return x1;
03426                 }
03427 
03428                 x0 = x1;
03429         }
03430 
03431         fprintf( ioQQQ, " cnewton did not converge\n" );
03432         ShowMe();
03433         cdEXIT(EXIT_FAILURE);
03434 }
03435 
03436 
03437 
03438 
03439 
03440 STATIC void Stognienko(complex<double> x,
03441                         double frdelta[],       
03442                         complex<double> eps[],  
03443                        long sumAxes,
03444                         complex<double> *f,
03445                         double *dudx,
03446                         double *dudy)
03447 {
03448         long i,
03449           l;
03450 
03451         static const double L[4] = { 0., 1./2., 1., 1./3. };
03452         static const double fl[4] = { 5./9., 2./9., 2./9., 1. };
03453 
03454         DEBUG_ENTRY( "Stognienko()" );
03455         *f = complex<double>(0.,0.);
03456         *dudx = 0.;
03457         *dudy = 0.;
03458         for( l=0; l < sumAxes; l++ )
03459         {
03460                 complex<double> hlp = eps[l] - x;
03461                 double h1 = eps[l].imag()*x.real() - eps[l].real()*x.imag();
03462 
03463                 for( i=0; i < 4; i++ )
03464                 {
03465                         double f1 = fl[i]*frdelta[l];
03466                         double xx = ( i < 3 ) ? sin(PI*frdelta[l]) : cos(PI*frdelta[l]);
03467                         complex<double> f2 = f1*xx*xx;
03468                         complex<double> one = x + hlp*L[i];
03469                         complex<double> two = f2*hlp/one;
03470                         double h2 = norm(one);
03471                         *f += two;
03472                         *dudx -= f2.real()*(eps[l].real()*h2 + h1*2.*one.imag()*(1.-L[i]))/POW2(h2);
03473                         *dudy -= f2.real()*(eps[l].imag()*h2 - h1*2.*one.real()*(1.-L[i]))/POW2(h2);
03474                 }
03475         }
03476         return;
03477 }
03478 
03479 
03480 
03481 
03482 STATIC void Bruggeman(complex<double> x,
03483                        double frdelta[], 
03484                        complex<double> eps[],    
03485                       long sumAxes,
03486                        complex<double> *f,
03487                        double *dudx,
03488                        double *dudy)
03489 {
03490         long l;
03491 
03492         static const double L = 1./3.;
03493 
03494         DEBUG_ENTRY( "Bruggeman()" );
03495         *f = complex<double>(0.,0.);
03496         *dudx = 0.;
03497         *dudy = 0.;
03498         for( l=0; l < sumAxes; l++ )
03499         {
03500                 complex<double> hlp = eps[l] - x;
03501                 double h1 = eps[l].imag()*x.real() - eps[l].real()*x.imag();
03502                 complex<double> f2 = frdelta[l];
03503                 complex<double> one = x + hlp*L;
03504                 complex<double> two = f2*hlp/one;
03505                 double h2 = norm(one);
03506                 *f += two;
03507                 *dudx -= f2.real()*(eps[l].real()*h2 + h1*2.*one.imag()*(1.-L))/POW2(h2);
03508                 *dudy -= f2.real()*(eps[l].imag()*h2 - h1*2.*one.real()*(1.-L))/POW2(h2);
03509         }
03510         return;
03511 }
03512 
03513 
03514 
03515 STATIC void mie_read_szd(  const char *chFile,
03516                           sd_data *sd)
03517 {
03518         bool lgTryOverride = false;
03519         long int dl,
03520           i;
03521         double mul = 0.,
03522           ref_neg = DBL_MAX,
03523           ref_pos = DBL_MAX,
03524           step_neg = DBL_MAX,
03525           step_pos = DBL_MAX;
03526         char chLine[FILENAME_PATH_LENGTH_2],
03527           chWord[WORDLEN];
03528         FILE *io2;
03529 
03530         
03531 
03532 
03533 
03534 
03535         const double FRAC_CUTOFF = 1.e-4;
03536         const double MUL_CO1 = -log(FRAC_CUTOFF);
03537         const double MUL_CO2 = sqrt(MUL_CO1);
03538         const double MUL_CO3 = pow(MUL_CO1,1./3.);
03539         const double MUL_LND = sqrt(-2.*log(FRAC_CUTOFF));
03540         const double MUL_NRM = MUL_LND;
03541 
03542         DEBUG_ENTRY( "mie_read_szd()" );
03543 
03544         io2 = open_data( chFile, "r", AS_LOCAL_ONLY );
03545 
03546         dl = 0; 
03547 
03548         
03549         mie_next_data(chFile,io2,chLine,&dl);
03550         mie_read_long(chFile,chLine,&sd->magic,true,dl);
03551         if( sd->magic != MAGIC_SZD ) 
03552         {
03553                 fprintf( ioQQQ, " Size distribution file %s has obsolete magic number\n",chFile );
03554                 fprintf( ioQQQ, " I found %ld, but expected %ld on line #%ld\n",sd->magic,MAGIC_SZD,dl );
03555                 fprintf( ioQQQ, " Please replace this file with an up to date version\n" );
03556                 cdEXIT(EXIT_FAILURE);
03557         }
03558 
03559         
03560         mie_next_data(chFile,io2,chLine,&dl);
03561         mie_read_word(chLine,chWord,WORDLEN,true);
03562 
03563         if( nMatch( "SSIZ", chWord ) )
03564         {
03565                 sd->sdCase = SD_SINGLE_SIZE;
03566         }
03567         else if( nMatch( "POWE", chWord ) )
03568         {
03569                 sd->sdCase = SD_POWERLAW;
03570         }
03571         else if( nMatch( "EXP1", chWord ) )
03572         {
03573                 sd->sdCase = SD_EXP_CUTOFF1;
03574                 sd->a[ipAlpha] = 1.;
03575                 mul = MUL_CO1;
03576         }
03577         else if( nMatch( "EXP2", chWord ) )
03578         {
03579                 sd->sdCase = SD_EXP_CUTOFF2;
03580                 sd->a[ipAlpha] = 2.;
03581                 mul = MUL_CO2;
03582         }
03583         else if( nMatch( "EXP3", chWord ) )
03584         {
03585                 sd->sdCase = SD_EXP_CUTOFF3;
03586                 sd->a[ipAlpha] = 3.;
03587                 mul = MUL_CO3;
03588         }
03589         else if( nMatch( "LOGN", chWord ) )
03590         {
03591                 sd->sdCase = SD_LOG_NORMAL;
03592                 mul = MUL_LND;
03593         }
03594         
03595         else if( nMatch( "NORM", chWord ) )
03596         {
03597                 sd->sdCase = SD_LIN_NORMAL;
03598                 mul = MUL_NRM;
03599         }
03600         else if( nMatch( "TABL", chWord ) )
03601         {
03602                 sd->sdCase = SD_TABLE;
03603         }
03604         else
03605         {
03606                 sd->sdCase = SD_ILLEGAL;
03607         }
03608 
03609         switch( sd->sdCase ) 
03610         {
03611         case SD_SINGLE_SIZE:
03612                 
03613                 mie_next_data(chFile,io2,chLine,&dl);
03614                 mie_read_double(chFile,chLine,&sd->a[ipSize],true,dl);
03615                 if( sd->a[ipSize] < SMALLEST_GRAIN || sd->a[ipSize] > LARGEST_GRAIN ) 
03616                 {
03617                         fprintf( ioQQQ, " Illegal value for grain size\n" );
03618                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03619                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03620                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03621                         cdEXIT(EXIT_FAILURE);
03622                 }
03623                 break;
03624         case SD_POWERLAW:
03625                 
03626                 mie_next_data(chFile,io2,chLine,&dl);
03627                 mie_read_double(chFile,chLine,&sd->a[ipBLo],true,dl);
03628                 if( sd->a[ipBLo] < SMALLEST_GRAIN || sd->a[ipBLo] > LARGEST_GRAIN ) 
03629                 {
03630                         fprintf( ioQQQ, " Illegal value for grain size (lower limit)\n" );
03631                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03632                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03633                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03634                         cdEXIT(EXIT_FAILURE);
03635                 }
03636 
03637                 
03638                 mie_next_data(chFile,io2,chLine,&dl);
03639                 mie_read_double(chFile,chLine,&sd->a[ipBHi],true,dl);
03640                 if( sd->a[ipBHi] < SMALLEST_GRAIN || sd->a[ipBHi] > LARGEST_GRAIN ||
03641                     sd->a[ipBHi] <= sd->a[ipBLo] ) 
03642                 {
03643                         fprintf( ioQQQ, " Illegal value for grain size (upper limit)\n" );
03644                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03645                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03646                         fprintf( ioQQQ, " and upper limit should be greater than lower limit\n" );
03647                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03648                         cdEXIT(EXIT_FAILURE);
03649                 }
03650 
03651                 
03652                 mie_next_data(chFile,io2,chLine,&dl);
03653                 if( sscanf( chLine, "%lf", &sd->a[ipExp] ) != 1 ) 
03654                 {
03655                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03656                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03657                         cdEXIT(EXIT_FAILURE);
03658                 }
03659 
03660                 sd->a[ipBeta] = 0.;
03661                 sd->a[ipSLo] = 0.;
03662                 sd->a[ipSHi] = 0.;
03663 
03664                 sd->lim[ipBLo] = sd->a[ipBLo];
03665                 sd->lim[ipBHi] = sd->a[ipBHi];
03666                 break;
03667         case SD_EXP_CUTOFF1:
03668         case SD_EXP_CUTOFF2:
03669         case SD_EXP_CUTOFF3:
03670                 
03671 
03672                 
03673                 mie_next_data(chFile,io2,chLine,&dl);
03674                 mie_read_double(chFile,chLine,&sd->a[ipBLo],true,dl);
03675 
03676                 
03677                 mie_next_data(chFile,io2,chLine,&dl);
03678                 mie_read_double(chFile,chLine,&sd->a[ipBHi],true,dl);
03679 
03680                 
03681                 mie_next_data(chFile,io2,chLine,&dl);
03682                 if( sscanf( chLine, "%lf", &sd->a[ipExp] ) != 1 ) 
03683                 {
03684                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03685                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03686                         cdEXIT(EXIT_FAILURE);
03687                 }
03688 
03689                 
03690                 mie_next_data(chFile,io2,chLine,&dl);
03691                 if( sscanf( chLine, "%lf", &sd->a[ipBeta] ) != 1 ) 
03692                 {
03693                         fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03694                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03695                         cdEXIT(EXIT_FAILURE);
03696                 }
03697 
03698                 
03699                 mie_next_data(chFile,io2,chLine,&dl);
03700                 mie_read_double(chFile,chLine,&sd->a[ipSLo],false,dl);
03701 
03702                 
03703                 mie_next_data(chFile,io2,chLine,&dl);
03704                 mie_read_double(chFile,chLine,&sd->a[ipSHi],false,dl);
03705 
03706                 ref_neg = sd->a[ipBLo];
03707                 step_neg = -mul*sd->a[ipSLo];
03708                 ref_pos = sd->a[ipBHi];
03709                 step_pos = mul*sd->a[ipSHi];
03710                 lgTryOverride = true;
03711                 break;
03712         case SD_LOG_NORMAL:
03713                 
03714                 mie_next_data(chFile,io2,chLine,&dl);
03715                 mie_read_double(chFile,chLine,&sd->a[ipGCen],true,dl);
03716 
03717                 
03718                 mie_next_data(chFile,io2,chLine,&dl);
03719                 mie_read_double(chFile,chLine,&sd->a[ipGSig],true,dl);
03720 
03721                 
03722                 ref_neg = ref_pos = sd->a[ipGCen]*exp(3.*POW2(sd->a[ipGSig]));
03723                 step_neg = sd->a[ipGCen]*(exp(-mul*sd->a[ipGSig]) - 1.);
03724                 step_pos = sd->a[ipGCen]*(exp(mul*sd->a[ipGSig]) - 1.);
03725                 lgTryOverride = true;
03726                 break;
03727         case SD_LIN_NORMAL:
03728                 
03729                 mie_next_data(chFile,io2,chLine,&dl);
03730                 mie_read_double(chFile,chLine,&sd->a[ipGCen],true,dl);
03731 
03732                 
03733                 mie_next_data(chFile,io2,chLine,&dl);
03734                 mie_read_double(chFile,chLine,&sd->a[ipGSig],true,dl);
03735 
03736                 
03737                 ref_neg = ref_pos = (sd->a[ipGCen] + sqrt(POW2(sd->a[ipGCen]) + 12.*POW2(sd->a[ipGSig])))/2.;
03738                 step_neg = -mul*sd->a[ipGSig];
03739                 step_pos = mul*sd->a[ipGSig];
03740                 lgTryOverride = true;
03741                 break;
03742         case SD_TABLE:
03743                 
03744                 mie_next_data(chFile,io2,chLine,&dl);
03745                 mie_read_double(chFile,chLine,&sd->a[ipBLo],true,dl);
03746                 if( sd->a[ipBLo] < SMALLEST_GRAIN || sd->a[ipBLo] > LARGEST_GRAIN ) 
03747                 {
03748                         fprintf( ioQQQ, " Illegal value for grain size (lower limit)\n" );
03749                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03750                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03751                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03752                         cdEXIT(EXIT_FAILURE);
03753                 }
03754 
03755                 
03756                 mie_next_data(chFile,io2,chLine,&dl);
03757                 mie_read_double(chFile,chLine,&sd->a[ipBHi],true,dl);
03758                 if( sd->a[ipBHi] < SMALLEST_GRAIN || sd->a[ipBHi] > LARGEST_GRAIN ||
03759                     sd->a[ipBHi] <= sd->a[ipBLo] ) 
03760                 {
03761                         fprintf( ioQQQ, " Illegal value for grain size (upper limit)\n" );
03762                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03763                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03764                         fprintf( ioQQQ, " and upper limit should be greater than lower limit\n" );
03765                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03766                         cdEXIT(EXIT_FAILURE);
03767                 }
03768 
03769                 
03770                 mie_next_data(chFile,io2,chLine,&dl);
03771                 mie_read_long(chFile,chLine,&sd->npts,true,dl);
03772                 if( sd->npts < 2 )
03773                 {
03774                         fprintf( ioQQQ, " Illegal value for no. of points in table\n" );
03775                         fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03776                         cdEXIT(EXIT_FAILURE);
03777                 }
03778 
03779                 
03780                 sd->ln_a = (double *)MALLOC(sizeof(double)*(unsigned)sd->npts);
03781                 sd->ln_a4dNda = (double *)MALLOC(sizeof(double)*(unsigned)sd->npts);
03782 
03783                 
03784                 for( i=0; i < sd->npts; ++i )
03785                 {
03786                         double help1, help2;
03787 
03788                         mie_next_data(chFile,io2,chLine,&dl);
03789                         
03790                         if( sscanf( chLine, "%le %le", &help1, &help2 ) != 2 ) 
03791                         {
03792                                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03793                                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03794                                 cdEXIT(EXIT_FAILURE);
03795                         }
03796 
03797                         if( help1 <= 0. || help2 <= 0. )
03798                         {
03799                                 fprintf( ioQQQ, " Reading table failed on line #%ld of %s\n",dl,chFile );
03800                                 fprintf( ioQQQ, " Illegal data value %.6e or %.6e\n", help1, help2 );
03801                                 cdEXIT(EXIT_FAILURE);
03802                         }
03803 
03804                         sd->ln_a[i] = log(help1);
03805                         sd->ln_a4dNda[i] = log(help2);
03806 
03807                         if( i > 0 && sd->ln_a[i] <= sd->ln_a[i-1] )
03808                         {
03809                                 fprintf( ioQQQ, " Reading table failed on line #%ld of %s\n",dl,chFile );
03810                                 fprintf( ioQQQ, " Grain radii should be monotonically increasing\n" );
03811                                 cdEXIT(EXIT_FAILURE);
03812                         }
03813                 }
03814 
03815                 sd->lim[ipBLo] = sd->a[ipBLo];
03816                 sd->lim[ipBHi] = sd->a[ipBHi];
03817                 break;
03818         case SD_ILLEGAL:
03819         default:
03820                 fprintf( ioQQQ, " unimplemented case for grain size distribution in file %s\n" , chFile );
03821                 fprintf( ioQQQ, " Line #%ld: value %s\n",dl,chWord);
03822                 cdEXIT(EXIT_FAILURE);
03823         }
03824 
03825         
03826 
03827         
03828 
03829 
03830 
03831         if( lgTryOverride )
03832         {
03833                 double help;
03834 
03835                 mie_next_data(chFile,io2,chLine,&dl);
03836                 mie_read_double(chFile,chLine,&help,false,dl);
03837                 sd->lim[ipBLo] = ( help <= 0. ) ? search_limit(ref_neg,step_neg,FRAC_CUTOFF,*sd) : help;
03838 
03839                 mie_next_data(chFile,io2,chLine,&dl);
03840                 mie_read_double(chFile,chLine,&help,false,dl);
03841                 sd->lim[ipBHi] = ( help <= 0. ) ? search_limit(ref_pos,step_pos,FRAC_CUTOFF,*sd) : help;
03842 
03843                 if( sd->lim[ipBLo] < SMALLEST_GRAIN || sd->lim[ipBHi] > LARGEST_GRAIN ||
03844                     sd->lim[ipBHi] <= sd->lim[ipBLo] ) 
03845                 {
03846                         fprintf( ioQQQ, " Illegal size limits: lower %.5f and/or upper %.5f\n",
03847                                  sd->lim[ipBLo], sd->lim[ipBHi] );
03848                         fprintf( ioQQQ, " Grain sizes should be between %.5f and %.0f micron\n",
03849                                  SMALLEST_GRAIN, LARGEST_GRAIN );
03850                         fprintf( ioQQQ, " and upper limit should be greater than lower limit\n" );
03851                         fprintf( ioQQQ, " Please alter the size distribution file\n" );
03852                         cdEXIT(EXIT_FAILURE);
03853                 }
03854         }
03855 
03856         fclose(io2);
03857         return;
03858 }
03859 
03860 
03861 STATIC void mie_read_long(  const char *chFile,
03862                             const char chLine[], 
03863                            long int *data,
03864                           bool lgZeroIllegal,
03865                           long int dl)
03866 {
03867         DEBUG_ENTRY( "mie_read_long()" );
03868         if( sscanf( chLine, "%ld", data ) != 1 )
03869         {
03870                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03871                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03872                 cdEXIT(EXIT_FAILURE);
03873         }
03874         if( *data < 0 || (*data == 0 && lgZeroIllegal) )
03875         {
03876                 fprintf( ioQQQ, " Illegal data value in %s\n",chFile);
03877                 fprintf( ioQQQ, " Line #%ld: %ld\n",dl,*data);
03878                 cdEXIT(EXIT_FAILURE);
03879         }
03880         return;
03881 }
03882 
03883 
03884 STATIC void mie_read_realnum(  const char *chFile,
03885                                const char chLine[], 
03886                               realnum *data,
03887                              bool lgZeroIllegal,
03888                              long int dl)
03889 {
03890         DEBUG_ENTRY( "mie_read_realnum()" );
03891         double help;
03892         if( sscanf( chLine, "%lf", &help ) != 1 )
03893         {
03894                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03895                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03896                 cdEXIT(EXIT_FAILURE);
03897         }
03898         *data = (realnum)help;
03899         if( *data < 0. || (*data == 0. && lgZeroIllegal) )
03900         {
03901                 fprintf( ioQQQ, " Illegal data value in %s\n",chFile);
03902                 fprintf( ioQQQ, " Line #%ld: %14.6e\n",dl,*data);
03903                 cdEXIT(EXIT_FAILURE);
03904         }
03905         return;
03906 }
03907 
03908 
03909 STATIC void mie_read_double(  const char *chFile,
03910                               const char chLine[], 
03911                              double *data,
03912                             bool lgZeroIllegal,
03913                             long int dl)
03914 {
03915         DEBUG_ENTRY( "mie_read_double()" );
03916         if( sscanf( chLine, "%lf", data ) != 1 )
03917         {
03918                 fprintf( ioQQQ, " Syntax error in %s\n",chFile);
03919                 fprintf( ioQQQ, " Line #%ld: %s\n",dl,chLine);
03920                 cdEXIT(EXIT_FAILURE);
03921         }
03922         if( *data < 0. || (*data == 0. && lgZeroIllegal) )
03923         {
03924                 fprintf( ioQQQ, " Illegal data value in %s\n",chFile);
03925                 fprintf( ioQQQ, " Line #%ld: %14.6e\n",dl,*data);
03926                 cdEXIT(EXIT_FAILURE);
03927         }
03928         return;
03929 }
03930 
03931 
03932 STATIC void mie_read_form(  const char chWord[], 
03933                            double elmAbun[],    
03934                            double *no_atoms,
03935                            double *mol_weight)
03936 {
03937         long int nelem,
03938           len;
03939         char chElmName[3];
03940         double frac;
03941 
03942         DEBUG_ENTRY( "mie_read_form()" );
03943 
03944         *no_atoms = 0.;
03945         *mol_weight = 0.;
03946         string strWord( chWord );
03947         for( nelem=0; nelem < LIMELM; nelem++ ) 
03948         {
03949                 frac = 0.;
03950                 strcpy(chElmName,elementnames.chElementSym[nelem]);
03951                 if( chElmName[1] == ' ' )
03952                         chElmName[1] = '\0';
03953                 string::size_type ptr = strWord.find( chElmName );
03954                 if( ptr != string::npos )
03955                 {
03956                         len = (long)strlen(chElmName);
03957                         
03958                         if( !islower((unsigned char)chWord[ptr+len]) ) 
03959                         {
03960                                 if( isdigit((unsigned char)chWord[ptr+len]) ) 
03961                                 {
03962                                         sscanf(chWord+ptr+len,"%lf",&frac);
03963                                 }
03964                                 else 
03965                                 {
03966                                         frac = 1.;
03967                                 }
03968                         }
03969                 }
03970                 elmAbun[nelem] = frac;
03971                 
03972                 if( nelem != ipHYDROGEN )
03973                         *no_atoms += frac;
03974                 *mol_weight += frac*dense.AtomicWeight[nelem];
03975         }
03976         
03977         if( *no_atoms == 0. ) 
03978                 *no_atoms = 1.;
03979         return;
03980 }
03981 
03982 
03983 STATIC void mie_write_form(  const double elmAbun[], 
03984                             char chWord[])          
03985 {
03986         long int len,
03987           nelem;
03988 
03989         DEBUG_ENTRY( "mie_write_form()" );
03990 
03991         len=0;
03992         for( nelem=0; nelem < LIMELM; nelem++ ) 
03993         {
03994                 if( elmAbun[nelem] > 0. )
03995                 {
03996                         char chElmName[3];
03997                         long index100 = nint(100.*elmAbun[nelem]);
03998 
03999                         strcpy(chElmName,elementnames.chElementSym[nelem]);
04000                         if( chElmName[1] == ' ' )
04001                                 chElmName[1] = '\0';
04002 
04003                         if( index100 == 100 )
04004                                 sprintf( &chWord[len], "%s", chElmName );
04005                         else if( index100%100 == 0 )
04006                                 sprintf( &chWord[len], "%s%ld", chElmName, index100/100 );
04007                         else
04008                         {
04009                                 double xIndex = (double)index100/100.;
04010                                 sprintf( &chWord[len], "%s%.2f", chElmName, xIndex );
04011                         }
04012                         len = (long)strlen( chWord );
04013                         ASSERT( len < FILENAME_PATH_LENGTH_2-25 );
04014                 }
04015         }
04016         return;
04017 }
04018 
04019 
04020 STATIC void mie_read_word(  const char chLine[], 
04021                            char chWord[],       
04022                           long n,
04023                           int toUpper)
04024 {
04025         long ip = 0,
04026           op = 0;
04027 
04028         DEBUG_ENTRY( "mie_read_word()" );
04029 
04030         
04031         while( chLine[ip] == ' ' || chLine[ip] == '"' )
04032                 ip++;
04033         
04034         while( op < n-1 && chLine[ip] != ' ' && chLine[ip] != '"' )
04035                 if( toUpper )
04036                         chWord[op++] = (char)toupper(chLine[ip++]);
04037                 else
04038                         chWord[op++] = chLine[ip++];
04039         
04040         chWord[op] = '\0';
04041         return;
04042 }
04043 
04044 
04045 STATIC void mie_next_data(  const char *chFile,
04046                             FILE *io,
04047                            char chLine[], 
04048                             long int *dl)
04049 {
04050         char *str;
04051 
04052         DEBUG_ENTRY( "mie_next_data()" );
04053 
04054         
04055 
04056 
04057 
04058         chLine[0] = '#';
04059         while( chLine[0] == '#' )
04060         {
04061                 mie_next_line(chFile,io,chLine,dl);
04062         }
04063 
04064         
04065         str = strstr(chLine,"#");
04066         if( str != NULL )
04067                 *str = '\0';
04068         return;
04069 }
04070 
04071 
04072 
04073 STATIC void mie_next_line(  const char *chFile,
04074                             FILE *io,
04075                            char chLine[], 
04076                             long int *dl)
04077 {
04078         DEBUG_ENTRY( "mie_next_line()" );
04079 
04080         if( read_whole_line( chLine, FILENAME_PATH_LENGTH_2, io ) == NULL ) 
04081         {
04082                 fprintf( ioQQQ, " Could not read from %s\n",chFile);
04083                 if( feof(io) )
04084                         fprintf( ioQQQ, " EOF reached\n");
04085                 cdEXIT(EXIT_FAILURE);
04086         }
04087         (*dl)++;
04088         return;
04089 }
04090 
04091 
04092 
04093 
04094 
04095 
04096 
04097 
04098 
04099 
04100 
04101 
04102 
04103 
04104 void gauss_init(long int nn,
04105             double xbot,
04106             double xtop,
04107             double x[],  
04108             double a[],  
04109             double rr[], 
04110             double ww[]) 
04111 {
04112         long int i;
04113         double bma,
04114           bpa;
04115 
04116         DEBUG_ENTRY( "gauss_init()" );
04117 
04118         bpa = (xtop+xbot)/2.;
04119         bma = (xtop-xbot)/2.;
04120 
04121         for( i=0; i < nn; i++ ) 
04122         {
04123                 rr[i] = bpa + bma*x[nn-1-i];
04124                 ww[i] = bma*a[i];
04125         }
04126         return;
04127 }
04128 
04129 
04130 
04131 
04132 void gauss_legendre(long int nn,
04133              double x[], 
04134              double a[]) 
04135 {
04136         long int i,
04137           iter,
04138           j;
04139         double *c,
04140           cc,
04141           csa,
04142           d,
04143           dp1,
04144           dpn = 0.,
04145           dq,
04146           fj,
04147           fn,
04148           pn,
04149           pn1 = 0.,
04150           q,
04151           xt = 0.;
04152 
04153         const double SAFETY = 5.;
04154 
04155 
04156         DEBUG_ENTRY( "gauss_legendre()" );
04157 
04158         if( nn%2 == 1 ) 
04159         {
04160                 fprintf( ioQQQ, " Illegal number of abcissas\n" );
04161                 cdEXIT(EXIT_FAILURE);
04162         }
04163 
04164         c = (double *)MALLOC(sizeof(double)*(unsigned)nn);
04165 
04166         fn = (double)nn;
04167         csa = 0.;
04168         cc = 2.;
04169         for( j=1; j < nn; j++ ) 
04170         {
04171                 fj = (double)j;
04172                 
04173 
04174 
04175                 c[j] = POW2(fj)/((fj-0.5)*(fj+0.5));
04176                 cc *= c[j];
04177         }
04178 
04179         for( i=0; i < nn/2; i++ ) 
04180         {
04181                 switch( i ) 
04182                 {
04183                 case 0:
04184                         xt = 1. - 2.78/(4. + POW2(fn));
04185                         break;
04186                 case 1:
04187                         xt = xt - 4.1*(1. + 0.06*(1. - 8./fn))*(1. - xt);
04188                         break;
04189                 case 2:
04190                         xt = xt - 1.67*(1. + 0.22*(1. - 8./fn))*(x[0] - xt);
04191                         break;
04192                 default:
04193                         xt = 3.*(x[i-1] - x[i-2]) + x[i-3];
04194                 }
04195                 d = 1.;
04196                 for( iter=1; (iter < 20) && (fabs(d) > DBL_EPSILON); iter++ ) 
04197                 {
04198                         
04199 
04200 
04201                         pn1 = 0.5;
04202                         pn = xt;
04203                         dp1 = 0.;
04204                         dpn = 1.;
04205                         for( j=1; j < nn; j++ )
04206                         {
04207                                 
04208 
04209                                 q = 2.*xt*pn - c[j]*pn1;
04210                                 dq = 2.*xt*dpn - c[j]*dp1 + 2.*pn;
04211                                 pn1 = pn;
04212                                 pn = q;
04213                                 dp1 = dpn;
04214                                 dpn = dq;
04215                         }
04216                         d = pn/dpn;
04217                         xt -= d;
04218                 }
04219                 x[i] = xt;
04220                 x[nn-1-i] = -xt;
04221                 
04222 
04223                 a[i] = cc/(dpn*2.*pn1);
04224                 a[nn-1-i] = a[i];
04225                 csa += a[i];
04226         }
04227 
04228         
04229 
04230         if( fabs(1.-csa) > SAFETY*fn*DBL_EPSILON ) 
04231         {
04232                 fprintf( ioQQQ, " gauss_legendre failed to converge: delta = %.4e\n",fabs(1.-csa) );
04233                 cdEXIT(EXIT_FAILURE);
04234         }
04235         free(c);
04236         return;
04237 }
04238 
04239 
04240 
04241 
04242 
04243 
04244 void find_arr(double x,
04245               double xa[],
04246               long int n,
04247                long int *ind,
04248                bool *lgOutOfBounds)
04249 {
04250         long int i1,
04251                 i2,
04252                 i3,
04253                 sgn,
04254                 sgn2;
04255 
04256         DEBUG_ENTRY( "find_arr()" );
04257         
04258 
04259         if( n < 2 ) 
04260         {
04261                 fprintf( ioQQQ, " Invalid array\n");
04262                 cdEXIT(EXIT_FAILURE);
04263         }
04264 
04265         i1 = 0;
04266         i3 = n-1;
04267         sgn = sign3(xa[i3]-xa[i1]);
04268         if( sgn == 0 ) 
04269         {
04270                 fprintf( ioQQQ, " Ill-ordered array\n");
04271                 cdEXIT(EXIT_FAILURE);
04272         }
04273 
04274         *lgOutOfBounds = x < MIN2(xa[0],xa[n-1]) || x > MAX2(xa[0],xa[n-1]);
04275         if( *lgOutOfBounds ) 
04276         {
04277                 *ind = -1;
04278                 return;
04279         }
04280 
04281         i2 = (n-1)/2;
04282         while( (i3-i1) > 1 ) 
04283         {
04284                 sgn2 = sign3(x-xa[i2]);
04285                 if( sgn2 != 0 )
04286                 {
04287                         if( sgn == sgn2 ) 
04288                         {
04289                                 i1 = i2;
04290                         }
04291                         else 
04292                         {
04293                                 i3 = i2;
04294                         }
04295                         i2 = (i1+i3)/2;
04296                 }
04297                 else 
04298                 {
04299                         *ind = i2;
04300                         return;
04301                 }
04302         }
04303         *ind = i1;
04304         return;
04305 }
04306 
04307 
04308 
04309 
04310 
04311 
04312 
04313 
04314 
04315 
04316 
04317 
04318 
04319 
04320 
04321 
04322 
04323 
04324 
04325 
04326 
04327 
04328 
04329 
04330 
04331 
04332 
04333 
04334 #define NMXLIM  16000
04335 
04336 STATIC void sinpar(double nre,
04337                    double nim,
04338                    double x,
04339                     double *qext,
04340                     double *qphase,
04341                     double *qscat,
04342                     double *ctbrqs,
04343                     double *qback,
04344                     long int *iflag)
04345 {
04346         long int n,
04347           nmx1,
04348           nmx2,
04349           nn,
04350           nsqbk;
04351         double ectb,
04352           eqext,
04353           eqpha,
04354           eqscat,
04355           error=0.,
04356           error1=0.,
04357           rx,
04358           t1,
04359           t2,
04360           t3,
04361           t4,
04362           t5,
04363           tx,
04364           x3,
04365           x5=0.,
04366           xcut,
04367           xrd;
04368         
04369 
04370 
04371         complex<double> *a;
04372         complex<double> cdum1,
04373           cdum2,
04374           ci,
04375           eqb,
04376           nc,
04377           nc2,
04378           nc212,
04379           qbck,
04380           rrf,
04381           rrfx,
04382           sman,
04383           sman1,
04384           smbn,
04385           smbn1,
04386           tc1,
04387           tc2,
04388           wn,
04389           wn1,
04390           wn2;
04391 
04392         DEBUG_ENTRY( "sinpar()" );
04393 
04394         a = (complex<double>*)MALLOC(sizeof(complex<double>)*(unsigned)NMXLIM);
04395 
04396         *iflag = 0;
04397         ci = complex<double>(0.,1.);
04398         nc = complex<double>(nre,-nim);
04399         nc2 = nc*nc;
04400         rrf = 1./nc;
04401         rx = 1./x;
04402         rrfx = rrf*rx;
04403 
04404         
04405 
04406 
04407 
04408 
04409 
04410 
04411 
04412 
04413 
04414 
04415 
04416 
04417 
04418 
04419         xrd = exp(log(x)/3.);
04420         
04421 
04422         t1 = x + 4.*xrd + 3.;
04423         
04424 
04425 
04426         if( !(x <= 8. || x >= 4200.) )
04427                 t1 += 0.05*xrd + 3.;
04428         t1 *= 1.01;
04429 
04430         
04431 
04432 
04433 
04434 
04435 
04436 
04437 
04438         t4 = x*sqrt(nre*nre+nim*nim);
04439         nmx1 = nint(MAX2(t1,t4)) + 15;
04440 
04441         if( nmx1 < NMXLIM ) 
04442         {
04443                 nmx2 = nint(t1);
04444                 
04445 
04446 
04447 
04448 
04449                 if( nmx2 <= 4 ) 
04450                 {
04451                         nmx2 = 4;
04452                         nmx1 = nint(MAX2(4.,t4)) + 15;
04453                 }
04454 
04455                 
04456                 a[nmx1] = 0.;
04457 
04458                 
04459 
04460 
04461                 for( n=0; n < nmx1; n++ )
04462                 {
04463                         nn = nmx1 - n;
04464                         a[nn-1] = (double)(nn+1)*rrfx - 1./((double)(nn+1)*rrfx+a[nn]);
04465                 }
04466 
04467                 t1 = cos(x);
04468                 t2 = sin(x);
04469                 wn2 = complex<double>(t1,-t2);
04470                 wn1 = complex<double>(t2,t1);
04471                 wn = rx*wn1 - wn2;
04472                 tc1 = a[0]*rrf + rx;
04473                 tc2 = a[0]*nc + rx;
04474                 sman = (tc1*wn.real() - wn1.real())/(tc1*wn - wn1);
04475                 smbn = (tc2*wn.real() - wn1.real())/(tc2*wn - wn1);
04476 
04477                 
04478 
04479 
04480                 xcut = 3.e-04;
04481                 if( x < xcut ) 
04482                 {
04483                         nc212 = (nc2-1.)/(nc2+2.);
04484                         x3 = POW3(x);
04485                         x5 = x3*POW2(x);
04486                         
04487                         sman = ci*2.*x3*nc212*(1./3.+x*x*0.2*(nc2-2.)/(nc2+2.)) + 4.*x5*x*nc212*nc212/9.;
04488                         smbn = ci*x5*(nc2-1.)/45.;
04489                 }
04490 
04491                 sman1 = sman;
04492                 smbn1 = smbn;
04493                 t1 = 1.5;
04494                 sman *= t1;
04495                 smbn *= t1;
04496                 
04497                 *qext = 2.*(sman.real() + smbn.real());
04498                 *qphase = 2.*(sman.imag() + smbn.imag());
04499                 nsqbk = -1;
04500                 qbck = -2.*(sman - smbn);
04501                 *qscat = (norm(sman) + norm(smbn))/.75;
04502 
04503                 *ctbrqs = 0.0;
04504                 n = 2;
04505 
04506                 
04507                 while( true ) 
04508                 {
04509                         t1 = 2.*(double)n - 1.;
04510                         t3 = 2.*(double)n + 1.;
04511                         wn2 = wn1;
04512                         wn1 = wn;
04513                         wn = t1*rx*wn1 - wn2;
04514                         cdum1 = a[n-1];
04515                         cdum2 = n*rx;
04516                         tc1 = cdum1*rrf + cdum2;
04517                         tc2 = cdum1*nc + cdum2;
04518                         sman = (tc1*wn.real() - wn1.real())/(tc1*wn - wn1);
04519                         smbn = (tc2*wn.real() - wn1.real())/(tc2*wn - wn1);
04520 
04521                         
04522 
04523                         if( x < xcut && n == 2 ) 
04524                         {
04525                                 
04526                                 sman = ci*x5*(nc2-1.)/(15.*(2.*nc2+3.));
04527                                 smbn = 0.;
04528                         }
04529 
04530                         eqext = t3*(sman.real() + smbn.real());
04531                         *qext += eqext;
04532                         eqpha = t3*(sman.imag() + smbn.imag());
04533                         *qphase += eqpha;
04534                         nsqbk = -nsqbk;
04535                         eqb = t3*(sman - smbn)*(double)nsqbk;
04536                         qbck += eqb;
04537                         tx = norm(sman) + norm(smbn);
04538                         eqscat = t3*tx;
04539                         *qscat += eqscat;
04540                         t2 = (double)(n - 1);
04541                         t5 = (double)n;
04542                         t4 = t1/(t5*t2);
04543                         t2 = (t2*(t5 + 1.))/t5;
04544                         ectb = t2*(sman1.real()*sman.real()+sman1.imag()*sman.imag() + smbn1.real()*smbn.real() +
04545                                    smbn1.imag()*smbn.imag()) +
04546                                 t4*(sman1.real()*smbn1.real()+sman1.imag()*smbn1.imag());
04547                         *ctbrqs += ectb;
04548 
04549                         
04550 
04551                         if( tx < 1.e-14 ) 
04552                         {
04553                                 
04554                                 eqext = fabs(eqext/ *qext);
04555                                 eqpha = fabs(eqpha/ *qphase);
04556                                 eqscat = fabs(eqscat/ *qscat);
04557                                 ectb = ( n == 2 ) ? 0. : fabs(ectb/ *ctbrqs);
04558                                 eqb = complex<double>( fabs(eqb.real()/qbck.real()), fabs(eqb.imag()/qbck.imag()) );
04559                                 
04560                                 error = MAX4(eqext,eqpha,eqscat,ectb);
04561                                 
04562                                 error1 = MAX2(eqb.real(),eqb.imag());
04563                                 if( error < 1.e-07 && error1 < 1.e-04 )
04564                                         break;
04565 
04566                                 
04567 
04568 
04569                                 if( x < xcut )
04570                                         break;
04571                         }
04572 
04573                         smbn1 = smbn;
04574                         sman1 = sman;
04575                         n++;
04576                         if( n > nmx2 ) 
04577                         {
04578                                 *iflag = 1;
04579                                 break;
04580                         }
04581                 }
04582                 
04583                 t1 = 2.*POW2(rx);
04584                 *qext *= t1;
04585                 *qphase *= t1;
04586                 *qback = norm(qbck)*POW2(rx);
04587                 *qscat *= t1;
04588                 *ctbrqs *= 2.*t1;
04589         }
04590         else 
04591         {
04592                 *iflag = 2;
04593         }
04594 
04595         free( a );
04596         return;
04597 }
04598 
04599 
04600 STATIC void anomal(double x,
04601                     double *qext,
04602                     double *qabs,
04603                     double *qphase,
04604                     double *xistar,
04605                    double delta,
04606                    double beta)
04607 {
04608         
04609 
04610 
04611 
04612 
04613 
04614 
04615         double xi,
04616           xii;
04617         complex<double> cbigk,
04618           ci,
04619           cw;
04620 
04621         DEBUG_ENTRY( "anomal()" );
04622         
04623 
04624         xi = 2.*x*delta;
04625         xii = 2.*x*beta;
04626         
04627         *xistar = sqrt(POW2(xi)+POW2(xii));
04628         
04629         ci = complex<double>(0.,1.);
04630         cw = -complex<double>(xi,xii)*ci;
04631         bigk(cw,&cbigk);
04632         *qext = 4.*cbigk.real();
04633         *qphase = 4.*cbigk.imag();
04634         cw = 2.*xii;
04635         bigk(cw,&cbigk);
04636         *qabs = 2.*cbigk.real();
04637         
04638         return;
04639 }
04640 
04641 
04642 STATIC void bigk(complex<double> cw,
04643                   complex<double> *cbigk)
04644 {
04645         
04646 
04647 
04648 
04649         DEBUG_ENTRY( "bigk()" );
04650         
04651         if( abs(cw) < 1.e-2 ) 
04652         {
04653                 
04654 
04655 
04656                 *cbigk = cw*((1./3.)-cw*((1./8.)-cw*((1./30.)-cw*((1./144.)-cw*((1./840.)-cw*(1./5760.))))));
04657         }
04658         else 
04659         {
04660                 *cbigk = 0.5 + (exp(-cw)*(1.+cw)-1.)/(cw*cw);
04661         }
04662         return;
04663 }
04664 
04665 
04666 
04667 STATIC void ritodf(double nr,
04668                    double ni,
04669                     double *eps1,
04670                     double *eps2)
04671 {
04672 
04673         DEBUG_ENTRY( "ritodf()" );
04674         
04675         *eps1 = nr*nr - ni*ni;
04676         *eps2 = 2.*nr*ni;
04677         return;
04678 }
04679 
04680 
04681 
04682 STATIC void dftori( double *nr,
04683                     double *ni,
04684                    double eps1,
04685                    double eps2)
04686 {
04687         double eps;
04688 
04689         DEBUG_ENTRY( "dftori()" );
04690         
04691         eps = sqrt(eps2*eps2+eps1*eps1);
04692         *nr = sqrt((eps+eps1)/2.);
04693         ASSERT( *nr > 0. );
04694         
04695 
04696         
04697         *ni = eps2/(2.*(*nr));
04698         return;
04699 }