00001 /*************************************************************************** 00002 rootscan.h 00003 ----------- 00004 00005 begin : Fri Sep 15 12:22:11 CEST 2000 00006 author : (C) 2000 by Michael Peeters 00007 email : Michael.Peeters@vub.ac.be 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 #ifndef ROOTSCAN_H 00020 #define ROOTSCAN_H 00021 00022 #include "numvector.h" 00023 #include "numvectorprint.h" 00024 #include "numerictraits.h" 00025 #include "vectorfunction.h" 00026 #include <string> 00027 #include "parameter.h" 00028 #include <list> 00029 #include <iostream> 00030 #include <map> 00031 #include "vfwithbump.h" 00032 #include "eigenvalues.h" 00033 #include "newtonroot.h" 00034 #include "jacobian.h" 00035 00036 namespace MODEL 00037 { 00041 template<integer dims, typename nelem=number, class NT = 00042 NumericTraits<nelem,dims> > 00043 class ScanList 00044 { 00045 public: 00046 typedef typename NT::vect vect; 00047 00053 typedef vector< NumVector<dims,nelem,NT> > parpoint; 00054 00059 typedef list<parpoint> parpointlist; 00060 typedef map<number,parpointlist> datalist; 00061 00063 typedef bool criteria(const parpoint&); 00064 00068 void clear() {dat.clear();} 00069 00071 parpointlist get_solution(number param) 00072 { 00073 datalist::iterator here=dat.upper_bound(param); 00074 return here->second; 00075 } 00076 00078 void add_point(const vect& v) 00079 { 00080 p.push_back(v); 00081 } 00082 00085 void add_param(const number& param) 00086 { 00087 dat[param].push_back(p); 00088 p.clear(); 00089 } 00090 00094 ScanList select(criteria ifthis) const 00095 { 00096 // make a copy 00097 ScanList selected(*this); 00098 00099 // Run thru it, removing all bad elements 00100 for(datalist::iterator p=selected.dat.begin(); 00101 p!=selected.dat.end();++p) 00102 { 00103 parpointlist::iterator pp=p->second.begin(); 00104 while(pp!=p->second.end()) 00105 if(!ifthis(*pp)) pp=p->second.erase(pp); 00106 else ++pp; 00107 } 00108 00109 return selected; 00110 } 00111 00115 void print_raw(ostream& out) 00116 { 00117 out << "# Raw data -----------------------" << endl; 00118 00119 for(datalist::iterator parr=dat.begin(); 00120 parr!=dat.end(); 00121 ++parr) 00122 { 00123 00124 for(parpointlist::iterator pointlist=parr->second.begin(); 00125 pointlist!=parr->second.end(); 00126 ++pointlist) 00127 { 00128 out << parr->first; // Write parameter value 00129 for(parpoint::iterator point=pointlist->begin(); 00130 point!=pointlist->end(); 00131 ++point) 00132 out << "\t" << *point; 00133 out << endl; 00134 } 00135 } 00136 } 00137 00140 ScanList operator+=(const ScanList<dims,nelem>& extra) 00141 { 00142 const datalist& other=extra.dat; 00143 00144 for(datalist::const_iterator parr=other.begin(); 00145 parr!=other.end(); 00146 ++parr) 00147 { 00148 00149 for(parpointlist::const_iterator pointlist=parr->second.begin(); 00150 pointlist!=parr->second.end(); 00151 ++pointlist) 00152 { 00153 // out << parr->first; // Write parameter value 00154 for(parpoint::const_iterator point=pointlist->begin(); 00155 point!=pointlist->end(); 00156 ++point) 00157 add_point(*point); // out << "\t" << *point; 00158 add_param(parr->first); // out << endl; 00159 } 00160 } 00161 return *this; 00162 } 00163 00164 00174 void print_list(ostream& out, const number& accuracy=1.) 00175 { 00176 datalist toprint(dat); 00177 00178 out << "# Scanlist output --------------------" << endl; 00179 00180 counter pieces(0); 00181 00182 // 1) Find a starting parameter value 00183 00184 datalist::iterator parrunner(toprint.begin()); 00185 while(parrunner!=toprint.end()) { // while there are parameters left 00186 00187 // 2) Find a starting point 00188 parpointlist::iterator varrunner(parrunner->second.begin()); 00189 00190 while (varrunner!=parrunner->second.end()) { // if there are any 00191 datalist::iterator nextrunner(parrunner); 00192 number param=nextrunner->first; // get first = KEY 00193 00194 // write comment 00195 out << "# -------------------------------" 00196 << " Start of list starting at " << param <<endl; 00197 00198 // We have a starting point, remove it from the list 00199 parpoint previous(*varrunner); 00200 number previousparam(param); 00201 00202 parpointlist::iterator diepiggy(varrunner); 00203 00204 parrunner->second.erase(diepiggy); // first erase, 00205 varrunner=parrunner->second.begin(); // then find another 00206 00207 // Add it to our list: 00208 out << param; 00209 for(parpoint::iterator i=previous.begin(); 00210 i!=previous.end();++i) 00211 out << "\t" << *i; 00212 out << endl; 00213 00214 // Find a next point (a higher par value) 00215 ++nextrunner; 00216 while (nextrunner!=toprint.end()){ // loopy - we have points 00217 // find someone to love 00218 bool loved=false; 00219 number nextparam=nextrunner->first; 00220 00221 parpointlist::iterator inrunner=nextrunner->second.begin(); 00222 00223 // calculate match requirements 00224 number maxchange=accuracy*nextparam/previousparam; 00225 00226 while (inrunner!=nextrunner->second.end()) { // find match 00227 00228 // Ok, we have one 00229 parpoint match(previous); 00230 parpoint gotcha(*inrunner); 00231 bool matched=true; 00232 00233 // Is it any good: calculate all differences 00234 for(parpoint::iterator 00235 i=match.begin(), 00236 j=gotcha.begin(), 00237 k=previous.begin(); 00238 i!=match.end(); 00239 ++i,++j,++k) 00240 { 00241 *i -= *j; 00242 *i /=length(*k); // normalized difference 00243 00244 // the abs is to make sure it works for complex 00245 // types 00248 matched= matched && abs(length(*i)) <maxchange; 00249 } 00250 00253 if(matched) { // we have a match 00254 previous=gotcha; 00255 00256 // Remove it from the list 00257 parrunner->second.erase(inrunner); 00258 00259 // Add it to our list: 00260 out << nextparam; 00261 for(parpoint::iterator i=previous.begin(); 00262 i!=previous.end();++i) 00263 out << "\t" << *i; 00264 out << endl; 00265 00266 loved=true; 00267 break; // We are happy, go to next parval 00268 } 00269 else ++inrunner; 00270 00271 } // while find match 00272 00273 if(loved) { 00274 // try it with the next parval 00275 ++nextrunner; 00276 } 00277 else { 00278 // All exhausted, close our list 00279 // cout << "#----------------------------" << endl; 00280 ++nextrunner; 00281 00282 // break; 00283 } 00284 00285 previousparam=nextparam; 00286 00287 } // loopy 00288 // close the list 00289 out << "# -------------------------------" 00290 << " End of list starting at " << param <<endl<<endl<<endl; 00291 ++pieces; 00292 00293 // three endl's for gnuplot 00294 00295 } // if we had any 00296 00297 00298 // Go to next parameter value, as we are exhausted here 00299 ++parrunner; 00300 00301 } // while parameters left 00302 out << "# Number of distict pieces: " << pieces << endl; 00303 } 00304 00305 datalist& get_data(void) 00306 { 00307 return dat; 00308 } 00309 00310 private: 00311 datalist dat; 00312 parpoint p; 00313 }; 00314 00315 //------------------------------------------------------------ 00316 00325 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> > 00326 class RootScan 00327 { 00328 public: 00329 typedef typename NT::vf vf; 00330 typedef typename NT::vect vect; 00331 00333 RootScan(vf& tobescanned, const string& param, vect starter=1.) : f(&tobescanned) 00334 { 00335 Parameter p=f->get_parameter(param); 00336 _p=&p; 00337 00338 // Generate some plausible starting points 00339 def_starters.push_back(starter); 00340 } 00341 00342 00346 RootScan(vf& tobescanned) : f(&tobescanned) 00347 { 00348 _p=&dummy; 00349 } 00350 00352 void add_start(const vect start) 00353 { 00354 def_starters.push_back(start); 00355 } 00356 00358 const ScanList<dims,nelem,NT>& scan(const number& from, 00359 const number& to, 00360 const counter& n) 00361 { 00362 // Clear out previous scan 00363 roots.clear(); 00364 00365 number delta=(to-from)/number(n-1); 00366 00367 // A starting value list 00368 list< NumVector<dims,nelem,NT> > starters(def_starters); 00369 00370 for(*_p=from;*_p<=to;*_p+=delta) { 00371 #ifdef ROOTSCAN_DEBUG 00372 cerr << "PARAMETER SCAN: " << *_p << endl; 00373 #endif 00374 // Add a bumpy layer, to find other zeroes 00375 VFwithBump<dims,nelem,NT> bumpy(*f); 00376 // Find stationary solution (the zeroes) 00377 NewtonRoot<dims,nelem,NT> stat(bumpy); 00378 Jacobian<dims> J(*f,1E-6); 00379 00380 NumVector<dims,nelem,NT> solution; 00381 00382 // Get the list of starting points, defined from the 00383 // previous parameter value. 00384 list< NumVector<dims,nelem,NT> > oldstarters(starters); 00385 00386 starters.clear(); 00387 starters=def_starters; 00388 00389 // Loop until no more points 00390 00391 list< NumVector<dims,nelem,NT> >::iterator 00392 start=oldstarters.begin(); 00393 while(start!=oldstarters.end()){ 00394 while(true){ 00395 try { 00396 solution=stat(*start); 00397 } 00398 catch (logic_error le) {++start; break;} 00399 00400 //debug : 00401 // cerr << *_p << ":\t" << solution << endl; 00402 00403 if(stat.wrong_min()) {++start; break;} 00404 if(stat.no_root()) {++start; break;} 00405 00406 // Oh goody, a root ! 00407 00408 // Find stability 00409 NumVector<dims,nelem,NT> reals=Eigenvalues<dims,nelem,NT>(J.calculate(solution)).real(); 00410 NumVector<dims,nelem,NT> imags=Eigenvalues<dims,nelem,NT>(J.calculate(solution)).imag(); 00411 00412 // Define the data 00413 #ifdef ROOTSCAN_DEBUG 00414 cerr << "STATPOINT:" << solution << endl; 00415 #endif 00416 roots.add_point(solution); 00417 roots.add_point(reals); 00418 roots.add_point(imags); 00419 // Save the data 00420 roots.add_param(*_p); 00421 00422 // add the solution to the bumplist 00423 bumpy.AddBump(solution); 00424 00425 // add to next try for next point 00426 starters.push_back( solution ); 00427 00432 // // define new starting point 00433 // for(integer i=0;i<dims;i++) 00434 // { 00435 // NumVector<dims,nelem,NT> nsplus(solution); 00436 // NumVector<dims,nelem,NT> nsmin(solution); 00437 // nsplus[i]+= (delta / *_p)*solution[i]; // Linear 00438 // // Interpol 00439 // nsmin[i]-= (delta / *_p)*solution[i]; // Linear Interpol 00440 // starters.push_back(nsplus); 00441 // starters.push_back(nsmin); 00442 00443 // } 00444 00445 } 00446 00447 } 00448 } 00449 return roots; 00450 } 00451 00452 // A few examples of criteria 00454 static bool all(const ScanList<dims,nelem,NT>::parpoint& p) {return true;} 00458 static bool stable(const ScanList<dims,nelem,NT>::parpoint& p) 00459 { 00460 bool stab=true; 00461 for(counter i=0;i<dims;++i) stab=stab&&(p[1][i]<0); 00462 00463 return stab; 00464 } 00466 static bool unstable(const ScanList<dims,nelem,NT>::parpoint& p) 00467 { 00468 return !stable(p); 00469 } 00472 static bool positive(const ScanList<dims,nelem,NT>::parpoint &p) 00473 { 00474 bool pos=true; 00475 for(counter i=0;i<dims;++i) pos=pos&&(p[0][i]>-1E-4); 00476 // Agree, this is still negative, but still... Just to remove 00477 // rounding errors which play hell on the routines 00478 00479 return pos; 00480 } 00481 00482 static bool negative(const ScanList<dims,nelem,NT>::parpoint &p) 00483 { 00484 return !positive(p); 00485 } 00486 00487 00488 private: 00489 vf* f; 00490 number* _p; 00491 ScanList<dims,nelem,NT> roots; 00492 00493 // if we don't have a parameter to scan 00494 number dummy; 00495 00496 public: 00498 list< NumVector<dims,nelem,NT> > def_starters; 00499 }; 00500 00501 00502 00503 00504 00505 } // end namespace 00506 00507 #endif 00508 00509 /********************************************************************* 00510 $Id: rootscan.h,v 1.3.2.2 2002/06/19 13:19:07 mpeeters Exp $ 00511 ********************************************************************** 00512 00513 $Log: rootscan.h,v $ 00514 Revision 1.3.2.2 2002/06/19 13:19:07 mpeeters 00515 Made the select member const, so one can make a subselection of a const list. 00516 00517 Revision 1.3.2.1 2001/08/30 14:46:04 mpeeters 00518 Added #ifdef ROOTSCAN_DEBUG to surpress outputting ridiculous amounts of info to cerr. 00519 00520 Revision 1.3 2001/08/23 20:24:00 mpeeters 00521 Modified docs to provide correct version info. 00522 00523 Revision 1.2 2001/07/26 12:01:22 mpeeters 00524 Make start point selection easier (add_start). Removed some bugs. 00525 00526 Revision 1.1 2001/05/22 10:54:55 mpeeters 00527 Moved sources and headers for libModel to model/ subdirectory, in an attempt to rationalize the source tree. This should make things "netter". 00528 00529 Revision 1.5 2001/05/21 11:53:16 mpeeters 00530 Removed Makefile.in, which is automatically generated anyway. 00531 00532 Revision 1.4 2000/09/29 08:56:28 mpeeters 00533 Inserted into print_raw: write the parameter on EVERY line, otherwise gnuplot flips. 00534 00535 Revision 1.3 2000/09/22 08:50:03 mpeeters 00536 Changed dependencies causing trouble. 00537 00538 Revision 1.2 2000/09/15 10:26:31 mpeeters 00539 Cleaned out header and added CVS tails to files, removed superfuous 00540 @author comments, inserted dates 00541 00542 *********************************************************************/
More Info? Michael Peeters. Also, check our research website: www.alna.vub.ac.be
Last update: June 2002.