Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

rootscan.h

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 *********************************************************************/

To get the sources or tarballs, please go to SourceForge or you can use the CVS repository.

More Info? Michael Peeters. Also, check our research website: www.alna.vub.ac.be

Last update: June 2002.


Looking for Open Source? Check out SourceForge Logo !