yanera_quadrature.c

Go to the documentation of this file.
00001 /*============================================================================
00002 Copyright 2006 Thad Harroun, Kevin Yager
00003 
00004 This file is part of "yanera 2.0".
00005 
00006 "yanera 2.0" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
00007 
00008 "yanera 2.0" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00009 
00010 You should have received a copy of the GNU General Public License along with "yanera 2.0"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 
00011 =============================================================================*/
00017 /*===========================================================================*/
00018 #define _CRT_SECURE_NO_DEPRECATE
00019 
00020 #include "yanera.h"
00021 #include "yanera_quadrature.h"
00022 #include "yanera_profile.h"
00023 /* -------------------------------------------------------------------------- */
00024 double slabs_trap(yanera_container *p, yanera_model *m, unsigned short i)
00025 {
00026   double tmp;
00027   
00028   tmp = (m->slabs.zpos[i+1] - m->slabs.zpos[i]) * \
00029         (p->profileFunctionReal(m->slabs.zpos[i+1], m, p)+ \
00030          p->profileFunctionReal(m->slabs.zpos[i],   m, p))/2.0;
00031   return tmp;
00032 }
00033 /* -------------------------------------------------------------------------- */
00034 double slabs_midp(yanera_container *p, yanera_model *m, unsigned short i)
00035 {
00036   double tmp1, tmp2;
00037   tmp1 = (m->slabs.zpos[i+1] + m->slabs.zpos[i])/2.0;
00038   tmp2 = (m->slabs.zpos[i+1] - m->slabs.zpos[i]) * \
00039           p->profileFunctionReal(tmp1, m, p);
00040   return tmp2;
00041 }
00042 /* -------------------------------------------------------------------------- */
00043 void slabs_insert(yanera_model *model, unsigned short j, double np)
00044 {
00045   unsigned short i;
00046   
00047   if ((model->slabs.number_of_slab_edges+1) >= USHRT_MAX) 
00048     yanera_error("Too many slabs.", __FILE__, __LINE__, NULL);
00049   
00050   for (i=model->slabs.number_of_slab_edges-1; i>j; i--)
00051   {
00052     model->slabs.zpos[i+1] = model->slabs.zpos[i];
00053   }
00054   model->slabs.zpos[j+1]              = np;
00055   model->slabs.number_of_slab_edges  += 1;
00056   model->slabs.number_of_slabs       += 1;
00057     
00058   return;
00059 }
00060 /* -------------------------------------------------------------------------- */
00061 void slabs_zero(yanera_model *model, double start, double end)
00062 {
00063   model->slabs.number_of_slab_edges = 1;
00064   model->slabs.number_of_slabs      = 2;
00065   model->slabs.zpos[0]              = start;
00066   model->slabs.thik[0]              = 0.0;
00067   
00068   slabs_insert(model, 0, end);
00069   
00070   return;
00071 }
00072 /* -------------------------------------------------------------------------- */
00073 void slabs_doit(yanera_model *m, yanera_container *p)
00074 {
00075   unsigned short i;
00076   double         tmp, zpos;
00077   
00078   i = 0;
00079   while (i != m->slabs.number_of_slab_edges-1)
00080   {
00081     tmp = fabs(slabs_trap(p,m,i)-slabs_midp(p,m,i));
00082     if (tmp > p->misc.quadrature_error)
00083     {
00084       zpos = (m->slabs.zpos[i] + m->slabs.zpos[i+1]) / 2.0;
00085       slabs_insert(m, i, zpos);
00086     }
00087     else
00088     {
00089       /* 
00090        * This bit here is to re-start the adaptive quadrature in the event
00091        * it makes a slab that is too big.
00092        * This can happen in periodic structures, when the quadarutre stretches
00093        * across an number of layers that happen to have the same rsld. In that
00094        * case, the integral difference (tmp) is very small, and the
00095        * subdivision stops.
00096        * 
00097        * First, if we reached here, the intregral difference (tmp) is smaller
00098        * than the tolerance. Normally, we would move to the next interval, and
00099        * consider the subdivision of this interval small enough.
00100        * But if the interval is bigger than quadrature_thik, 
00101        * then it really isn't small enough: divide it again 
00102        * and continue dividing as needed.
00103        * 
00104        * This puts an inherent limit on the total film thickness to about
00105        * USHRT_MAX * quadrature_thik. Is this enough? 
00106        */
00107       zpos = (m->slabs.zpos[i+1] - m->slabs.zpos[i]);
00108       if (zpos > p->misc.quadrature_thik)
00109       {
00110         zpos = m->slabs.zpos[i] + zpos/2.0;
00111         slabs_insert(m, i, zpos);
00112       }
00113       else
00114       {
00115         i += 1;
00116       }
00117     }
00118   }
00119  
00120   return;
00121 }
00122 /* -------------------------------------------------------------------------- */
00123 void doQuadrature(yanera_model *model, yanera_container *yanera)
00124 {
00125   double         start, end, zpos;
00126   short          i;
00127   
00128   /* Get the min/max of the rsld profile */
00129   minMaxProfile(&start, &end, model, yanera);
00130     
00131   /*
00132    *  Do the quadrature
00133    *  After, we have the edges of all the slabs.
00134    */
00135   slabs_zero(model, start, end);
00136   slabs_doit(model, yanera);
00137     
00138   /*
00139    * Since we store the edge and thickness together, define the edge (z)
00140    * of the slab as the high-z side.
00141    * 
00142    * Index slabs as : 0 to slabs.number_of_slabs-1
00143    * Index z points found by the quadrature (the slab edges) as:
00144    * 0 to slabs.number_of_slab_edges-1.
00145    *
00146    * Let : slabs.number_of_slabs = number_of_slab_edges + 1
00147    *
00148    * For slab 0 and n-1 there is no thickness.
00149    * For slab 0, z is the 'start' (see above) of the profile.
00150    * For slab n-2, z value is the 'end' (see above) of the profile.
00151    * For slab n-1, there is no z.
00152    */
00153   for (i=model->slabs.number_of_slabs-2; i>0; i--)
00154   {
00155     model->slabs.thik[i] = model->slabs.zpos[i] - model->slabs.zpos[i-1];
00156                                      
00157     zpos = (model->slabs.zpos[i] + model->slabs.zpos[i-1]) / 2.0;
00158     model->slabs.rsld[i] = yanera->profileFunctionReal(zpos, model, yanera);
00159     model->slabs.isld[i] = yanera->profileFunctionImag(zpos, model, yanera);
00160   }
00161   /* Set the rsld of (infinite fronting material) slab 0 */
00162   model->slabs.rsld[0] = yanera->profileFunctionReal(start, model, yanera);
00163   model->slabs.isld[0] = yanera->profileFunctionImag(start, model, yanera);
00164   /* Set the rsld of (infinite backing material) slab n-1 */
00165   model->slabs.rsld[model->slabs.number_of_slabs-1] = \
00166                    yanera->profileFunctionReal(end, model, yanera);
00167   model->slabs.isld[model->slabs.number_of_slabs-1] = \
00168                    yanera->profileFunctionImag(end, model, yanera);
00169    
00170   return;
00171 }
00172 /*============================================================================*/
00173 void yanera_write_slabs(yanera_container *yanera) 
00174 {
00175   double           zpos;
00176   char             filename[50];
00177   short            i2, i1;
00178   yanera_model    *model;
00179   FILE            *fp;
00180   
00181   for (i2=0; i2<yanera->number_of_models; i2++)
00182   {
00183     /* 
00184      * Make a filename for the reflectivity curve.
00185      */
00186     memset(filename, '\0', 50);
00187     if (yanera->data[i2].file_name == NULL) 
00188       { sprintf(filename, "result_%01d.slb", i2); }
00189     else sprintf(filename, "%s.slb", yanera->data[i2].file_name);
00190 
00191     /*
00192      * Break into slabs
00193      */
00194     doQuadrature(&yanera->models_complete[i2], yanera);
00195 
00196     /*
00197      * Open file and write to it.
00198      */    
00199     fp = NULL;
00200     fp = fopen(filename,"w");
00201     if (fp == NULL) 
00202     {
00203       yanera_error("Can't open reflectivity file for writing", \
00204                    __FILE__, __LINE__, yanera);
00205     }
00206     /*
00207      * Use the pointer "model" to keep the code simple:
00208      * else &yanera->models_complete[i2] would be appended to everything below.
00209      */
00210     model = &yanera->models_complete[i2];
00211     /*
00212      * Write the first slab, which is the infinite bakcing, as extending
00213      * one angstrom to higher z.
00214      */
00215     zpos = model->slabs.zpos[model->slabs.number_of_slabs-2];
00216     fprintf(fp, "%f\t%f\n", zpos+1.0, \
00217           model->slabs.rsld[model->slabs.number_of_slabs-1]);
00218     fprintf(fp, "%f\t%f\n", zpos, \
00219           model->slabs.rsld[model->slabs.number_of_slabs-1]);
00220     /*
00221      * Write the middle slabs. Start at the point last left off.
00222      */
00223     for (i1=model->slabs.number_of_slabs-2; i1>0; i1--)
00224     {
00225       fprintf(fp, "%f\t%f\n", zpos, model->slabs.rsld[i1]);
00226       zpos -= model->slabs.thik[i1];
00227       fprintf(fp, "%f\t%f\n", zpos, model->slabs.rsld[i1]);
00228     }
00229     /*
00230      * Write the final, infinite fronting slab as one angstrom thick.
00231      */
00232     fprintf(fp, "%f\t%f\n", zpos,     model->slabs.rsld[0]);    
00233     fprintf(fp, "%f\t%f\n", zpos-1.0, model->slabs.rsld[0]);
00234     /* --- */ 
00235     fclose(fp);
00236   }
00237    
00238   return;    
00239 }       

Generated on Thu May 29 10:56:33 2008 by  doxygen 1.5.5