Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

surfaceZ.cc

Go to the documentation of this file.
00001 // surfaceZ.cc
00002 // SuperMix version 1.0  C++ source file
00003 //
00004 // Copyright (c) 1999 California Institute of Technology.
00005 // All rights reserved.
00006 //
00007 // Redistribution and use in source and binary forms for noncommercial
00008 // purposes are permitted provided that the above copyright notice and
00009 // this paragraph are duplicated in all such forms and that any
00010 // documentation and other materials related to such distribution and
00011 // use acknowledge that the software was developed by California
00012 // Institute of Technology. Redistribution and/or use in source or
00013 // binary forms is not permitted for any commercial purpose. Use of
00014 // this software does not include a permitted use of the Institute's
00015 // name or trademark for any purpose.
00016 //
00017 // DISCLAIMER:
00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00022 // LICENSED PRODUCT, HOWEVER USED.  IN NO EVENT SHALL CALTECH/JPL BE
00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00027 // FACT SHALL KNOW OF THE POSSIBILITY.  THE USER BEARS ALL RISK
00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00029 // MATERIALS.
00030 //
00031 // Change history:
00032 // 6/13/00:  fixed the initialization in layer_list copy constructor
00033 // 11/15/99: combined super_film and super_film_interp into one class
00034 // 8/25/99: added parameter Zterm to local_film and layer_list classes
00035 // 7/6/99:  changed super_film_interp to use interpolator and adaptive
00036 // 1/11/99: FR added constructors, extended super_film_interp; general
00037 //          cleanup of code and comments
00038 // 9/15/98: Made the superfilm_interp message depend on error::message
00039 // 6/16/98: FR moved normal_film copy constructor from .cc file to .h
00040 
00041 #include <iostream.h>
00042 #include <math.h>
00043 #include "global.h"
00044 #include "units.h"
00045 #include "SIScmplx.h"
00046 #include "parameter.h"
00047 #include "error.h"
00048 #include "supcond.h"
00049 #include "surfaceZ.h"
00050 #include "adaptive.h"
00051 
00052 // **************************************************************
00053 // surfimp definitions
00054 
00055 double surfimp::thickness()
00056 {
00057   if (Thick < 0.0) {
00058     error::warning("surfimp::Thick < 0; using 0.");
00059     return 0.0;
00060   }
00061   else 
00062     return Thick.get();
00063 }
00064 
00065 // **************************************************************
00066 // local_film definitions
00067 
00068  // use free-space impedance as default backside termination
00069 local_film::local_film() : Zterm(ZVacuum) { }
00070 
00071 
00072 complex local_film::Zsurf(double freq, double Temp)
00073 {
00074 
00075   // Calculate wave vector in free space, metal; wave impedance in metal
00076   //
00077   double k0 = 2.*Pi*freq/cLight ; // k in free space 
00078   //
00079   complex factor = sqrt(1. - I*ZVacuum*sigma(freq, Temp)/k0);
00080   if(imag(factor) > 0.) {          // choose proper branch of sqrt    
00081     factor *= -1.;                // to make sure wave is attenuated 
00082   }                                // as it propagates                
00083   //
00084   complex k1 = k0*factor;         // k in metal      
00085   complex Z1 = ZVacuum/factor;    // wave impedance in metal 
00086 
00087   // now calculate surface impedance using transmission-line analogy
00088   //
00089   complex gamma = (Zterm - Z1)/(Zterm + Z1); // Termination imped. parameter Zterm
00090   gamma *= exp(-2.*I*k1*thickness());            // propagation factor 
00091   return Z1 * (1.+gamma)/(1.-gamma);             // surface impedance 
00092 }
00093 
00094 
00095 // **************************************************************
00096 // super_film definitions
00097 
00098 const double super_film::TOL_MAX = 0.01 ;      // 1% worst case tol
00099 const double super_film::TOL_MIN = 1.e-8 ;     // best case tol
00100 const double super_film::TOL_DEFAULT = 1.e-6 ; // default tol
00101 const int super_film::DEFAULT_MAXPTS = 1000 ;  // 1000 points max
00102 const int super_film::START_NPTS = 25 ;        // 25 points to start
00103 
00104 super_film::super_film()
00105   : Vgap_save(0.0), Tc_save(0.0), Temp_save(0.0), fmin(0.0), fmax(0.0),
00106     tol_save(0.0), interp_flag(true), initialized(false)
00107 {
00108   // set defaults
00109   tol =  TOL_DEFAULT ;
00110   tol.set_min(TOL_MIN) ;
00111   tol.set_max(TOL_MAX) ;
00112   maxpts = DEFAULT_MAXPTS ;
00113   maxpts.set_min(2*START_NPTS) ;
00114 }
00115 
00116 
00117 // generate interpolation tables
00118 //
00119 bool super_film::table_init()
00120 {
00121   // can we use the existing interpolator?
00122   if(initialized            && 
00123      Temp_calc == Temp_save &&
00124      Vgap      == Vgap_save &&
00125      Tc        == Tc_save   &&
00126      tol       >= tol_save ) {
00127     return false;
00128   }
00129 
00130   else {
00131     // we rebuild the table...
00132 
00133     // Let's perform a few sanity checks
00134     if(sanity_check())
00135       return true;        // uh-oh, some problems...
00136     
00137     // OK, let's regenerate the interpolation tables
00138     sigma_tab.clear().spline();
00139 
00140     fmin = fmax = VoltToFreq * Vgap;
00141     // just cover 3 orders of magnitude
00142     fmin /= 100.0;
00143     fmax *= 10.0;
00144 
00145     tol_save  = tol;
00146     Temp_save = Temp_calc;
00147     Vgap_save = Vgap ;
00148     Tc_save   = Tc;
00149 
00150     // the adaptive table builder setup:
00151     adaptive<complex> build(sigma_tab);
00152     build.min_x = log(fmin);   // we'll do log-log interpolation
00153     build.max_x = log(fmax);
00154     build.min_points = START_NPTS;
00155     build.max_points = maxpts;
00156     build.rel_tolerance = tol_save;
00157     build.abs_tolerance = tol_save;
00158     build.recursion_limit = 1000;
00159 
00160     // now adaptively fill the interpolator:
00161     if(build(member_function(&super_film::llsig, *this))) {
00162       error::warning("Interpolation for super_film object did not achieve"
00163                       " desired accuracy. Consider increasing maxpts") ;
00164     }
00165     else if (error::messages) {
00166       error::stream() << "Achieved desired accuracy for super_film" << endl
00167                       << "with  " << sigma_tab.size() << " points" << endl ;
00168     }
00169   }
00170   initialized = true;
00171   return false;
00172 }
00173 
00174 
00175 // extend interpolation tables
00176 //
00177 bool super_film::table_extend()
00178 {
00179   // can we use the existing interpolator?
00180   if(fmin <= freq_calc && freq_calc <= fmax) return false;
00181   
00182   else {
00183     // we extend the table...
00184     
00185     interpolator<complex> extra_tab;
00186     double f_low, f_high;
00187     if(freq_calc < fmin) {
00188       f_low = freq_calc/10.0; f_high = fmin; fmin = f_low;
00189       f_low = log(f_low); f_high = log(f_high);
00190       f_high -= sigma_tab.x(1)-sigma_tab.x(0);
00191     }
00192     else {
00193       f_low = fmax; f_high = freq_calc*10.0; fmax = f_high;
00194       f_low = log(f_low); f_high = log(f_high);
00195       unsigned m = sigma_tab.size()-1;
00196       f_low += sigma_tab.x(m)-sigma_tab.x(m-1);
00197     }
00198     
00199     // the adaptive table builder setup:
00200     adaptive<complex> build(extra_tab);
00201     build.min_x = f_low;   // we'll do log-log interpolation
00202     build.max_x = f_high;
00203     build.min_points = START_NPTS;
00204     build.max_points = maxpts;
00205     build.rel_tolerance = tol_save;
00206     build.abs_tolerance = tol_save;
00207     build.recursion_limit = 10;
00208     
00209     // now adaptively fill the interpolator extension:
00210     build(member_function(&super_film::llsig, *this));
00211     
00212     // now add the extension to the main interpolator and rebuild it:
00213     sigma_tab.add(extra_tab);
00214     sigma_tab.build();
00215     
00216     return false;
00217   }
00218 }
00219 
00220 
00221 // generate the normalized sigma data for the lookup table
00222 //
00223 complex super_film::llsig(double lf) const
00224 {
00225   return log(supcond(exp(lf),Temp_calc,Vgap,Tc));
00226 }
00227 
00228 
00229 // check parameter values
00230 //
00231 bool super_film::sanity_check() const
00232 {
00233   if(rho_normal <= 0.0) {
00234     error::warning(
00235     "rho_normal <= 0 for super_film object");
00236     return(true) ;         // error exit
00237   }
00238   else if(Vgap <= 0.0) {
00239     error::warning(
00240     "Vgap <= 0 for super_film object");
00241     return(true) ;         // error exit
00242   }
00243   else if(Tc <= 0.0) {
00244     error::warning(
00245     "Tc <= 0 for super_film object");
00246     return(true) ;         // error exit
00247   }
00248   else 
00249     return(false) ;  // all OK
00250 }
00251 
00252 //
00253 // Calculate complex conductivity using interpolation
00254 //
00255 complex super_film::sigma(double freq, double Temp)
00256 {
00257   // bad argument checks:
00258   if(freq < 0.) {
00259     error::warning(
00260     "Cannot calculate super_film object at negative frequency"
00261     );
00262     return(complex(0.)) ;
00263   }
00264   if(Temp < 0.) {
00265     error::warning(
00266     "Cannot calculate super_film object at negative temperature"
00267     );
00268     return(complex(0.)) ;
00269   }
00270 
00271   // maybe we won't use interpolator:
00272   if(rho_normal == 0.0) {
00273     error::warning("super_film object has normal-state resistivity of 0") ;
00274     return(complex(1./Tiny)) ;  // something huge
00275   }
00276   if(!interp_flag || freq == 0.0 || Temp == 0.0)
00277     return supcond(freq, Temp, Vgap, Tc)/rho_normal;
00278 
00279 
00280   // o.k., use the interpolator:
00281   freq_calc = freq;
00282   Temp_calc = Temp;
00283   if(table_init() || table_extend()) // checks parameters and builds table first time through
00284     // something went wrong...
00285     return(complex(0.)) ;
00286   else {
00287     // all is OK
00288     return exp(sigma_tab(log(freq)))/rho_normal ;  // doing log-log interpolation
00289   }
00290 }
00291 
00292 
00293 // **************************************************************
00294 // layerlist definitions
00295 
00296 layerList::layerList()
00297 {
00298   Zterm = ZVacuum ; // default backside termination
00299   this->head = 0;
00300 }
00301 
00302 layerList::layerList(const layerList & l) : surfimp((surfimp&)l)
00303 {
00304   // We're starting with nothing in the list
00305   head = 0;
00306 
00307   layerListNode *current;
00308 
00309   current = l.head;
00310 
00311   while(current != 0)
00312   {
00313     addlayer(*(current->layer));
00314     current = current->next;
00315   }
00316 }
00317 
00318 layerList::~layerList()
00319 {
00320   while(!isEmpty())
00321     remove();
00322 }
00323 
00324 int layerList::isEmpty()
00325 {
00326   if(head == 0)
00327     return TRUE;
00328   else
00329     return FALSE;
00330 }
00331 
00332 void layerList::addlayer(local_film &lay)
00333 {
00334     layerListNode *node = new layerListNode;
00335     node->layer = &lay;
00336     node->next = this->head;
00337     this->head = node;
00338 }
00339 
00340 local_film * layerList::remove()
00341 {
00342   local_film * tmplayer;
00343   layerListNode *tmpnode;
00344 
00345   // Don't do anything if the stack is empty.
00346   if(isEmpty())
00347     error::fatal("Attempt to call layerList::remove for an empty list.");
00348 
00349   // Pop the last layer added.
00350   tmpnode = head;
00351   head = tmpnode->next;
00352 
00353   // Don't lose the head's layer pointer
00354   tmplayer = tmpnode->layer;
00355 
00356   // Delete the old head node.
00357   delete tmpnode;
00358 
00359   return tmplayer;
00360 }
00361 
00362 layerList& layerList::operator=(const layerList & l)
00363 {
00364   // Beware of self assignment l = l
00365   if(this != &l)
00366   {
00367     // Delete the current layerList
00368     while(!isEmpty())
00369       remove();
00370 
00371     layerListNode *current;
00372 
00373     current = l.head;
00374 
00375     while(current != 0)
00376     {
00377       addlayer(*(current->layer));
00378       current = current->next;
00379     }
00380   }
00381   return *this;
00382 }
00383 
00384 
00385 //
00386 // layerList::Zsurf()
00387 // Calculates surface impedance of a multilayer metal film
00388 // for local conductors
00389 //
00390 complex layerList::Zsurf(double freq, double Temp)
00391 {
00392   complex sig, factor, k0, k1, Z1, gamA, gamB, Zs ;
00393   double th ;
00394 //
00395   layerListNode *current ;
00396 
00397  //
00398  // Calculate wave vector in free space
00399  //
00400    k0 = 2.*Pi*freq/cLight ;       // k in free space 
00401    //
00402    // Loop over the layers, starting with outermost layer
00403    //
00404    current = head ;
00405    Zs = Zterm ;  // start with termination imedance paramter Zterm
00406    //
00407    while(current != 0) {
00408        sig = (current->layer)->sigma(freq, Temp); // get conductivity 
00409        th = (current->layer)->thickness() ; // get thickness 
00410        //
00411        // Calculate wave vector, wave impedance in metal
00412        //
00413        factor = sqrt(1. - I*ZVacuum*sig/k0);
00414        if(imag(factor) > 0.) {        // choose proper branch of sqrt    
00415          factor *= -1. ;              // to make sure wave is attenuated 
00416        }                              // as it propagates                
00417        //
00418        k1 = k0*factor ;               // k in metal      
00419        Z1 = ZVacuum/factor ;          // wave impedance in metal 
00420        //
00421        // now calculate surface impedance using transmission-line analogy
00422        //
00423        gamA = (Zs - Z1)/(Zs + Z1) ;
00424        gamB = gamA * exp(-2.*I*k1*th) ; // propagation factor in metal 
00425        Zs = Z1 * (1.+gamB)/(1.-gamB) ;     // surface impedance 
00426        //
00427        // next layer...
00428        current = current->next ;
00429    }
00430    return(Zs) ;                        //  that's it ! 
00431  }
00432 
00433  //
00434  // layerList::thickness()
00435  // Calculates total thickness of a multilayer metal film
00436  //
00437  double layerList::thickness()
00438  {
00439    //
00440    // Loop over the layers, starting with outermost layer
00441    //
00442    layerListNode *current ;
00443    current = head ;
00444 
00445    double total = 0. ;
00446    while(current != 0) {
00447        total += (current->layer)->thickness() ; // add thickness 
00448        current = current->next ;                // next layer... 
00449    }
00450    return(total) ;                              // that's it ! 
00451  }

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7