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
1.2.7