Ignore:
Timestamp:
Jan 8, 2010, 3:02:48 PM (14 years ago)
Author:
garnier
Message:

update to geant4.9.3

Location:
trunk/examples/extended/electromagnetic/TestEm7/include
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/examples/extended/electromagnetic/TestEm7/include/DetectorConstruction.hh

    r807 r1230  
    2525//
    2626// $Id: DetectorConstruction.hh,v 1.2 2006/06/29 16:57:29 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/DetectorMessenger.hh

    r807 r1230  
    2525//
    2626// $Id: DetectorMessenger.hh,v 1.3 2006/06/29 16:57:31 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/EventAction.hh

    r807 r1230  
    2525//
    2626// $Id: EventAction.hh,v 1.2 2006/06/29 16:57:34 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/EventActionMessenger.hh

    r807 r1230  
    2525//
    2626// $Id: EventActionMessenger.hh,v 1.3 2006/06/29 16:57:36 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/G4ScreenedNuclearRecoil.hh

    r807 r1230  
    2525//
    2626//
    27 // $Id: G4ScreenedNuclearRecoil.hh,v 1.3 2007/12/07 17:51:10 vnivanch Exp $
    28 // GEANT4 tag $Name:  $
     27// G4ScreenedNuclearRecoil.hh,v 1.24 2008/05/01 19:58:59 marcus Exp
     28// GEANT4 tag
    2929//
    3030//
     
    4545//
    4646// First version, April 2004, Marcus H. Mendenhall, Vanderbilt University
     47// May 1, 2008 -- Added code to allow process to have zero cross section above max energy, to coordinate with G4MSC.  -- mhm
    4748//
    4849// Class Description - End
     
    5455#include "globals.hh"
    5556#include "G4VDiscreteProcess.hh"
     57#include "G4ParticleChange.hh"
    5658#include "c2_function.hh"
    5759
     
    5961#include <vector>
    6062
    61 class G4VParticleChange;
     63class G4VNIELPartition;
     64
     65typedef c2_const_ptr<G4double> G4_c2_const_ptr;
     66typedef c2_ptr<G4double> G4_c2_ptr;
     67typedef c2_function<G4double> G4_c2_function;
    6268
    6369typedef struct G4ScreeningTables {
    6470        G4double z1, z2, m1, m2, au, emin;
    65         c2_function<G4double> *EMphiData;
     71        G4_c2_const_ptr EMphiData;
    6672} G4ScreeningTables;
    6773
     
    7076{
    7177public:
    72         G4ScreenedCoulombCrossSectionInfo() { }
    73         ~G4ScreenedCoulombCrossSectionInfo() { }
    74 
    75         const char *CVSHeaderVers() { return
    76                 "";
    77         }
    78 
    79         const char *CVSFileVers() { return ""; }
     78        G4ScreenedCoulombCrossSectionInfo() { }
     79        ~G4ScreenedCoulombCrossSectionInfo() { }
     80       
     81        static const char* CVSHeaderVers() { return
     82                "G4ScreenedNuclearRecoil.hh,v 1.24 2008/05/01 19:58:59 marcus Exp GEANT4 tag ";
     83        }
     84        static const char* CVSFileVers();
    8085};
    8186
     
    114119       
    115120        // get the mean-free-path table for the indexed material
    116         c2_function<G4double> * operator [] (G4int materialIndex) {
    117                         return MFPTables.find(materialIndex)!=MFPTables.end() ? MFPTables[materialIndex] : (c2_function<G4double> *)0;
     121        const G4_c2_function * operator [] (G4int materialIndex) {
     122                        return MFPTables.find(materialIndex)!=MFPTables.end() ? &(MFPTables[materialIndex].get()) : (G4_c2_function *)0;
    118123                }
    119124       
     
    122127        ParticleCache targetMap;
    123128        G4int verbosity;
    124         std::map<G4int, c2_function<G4double> *> sigmaMap; // total cross section for each element
    125         std::map<G4int, c2_function<G4double> *> MFPTables; // MFP for each material
     129        std::map<G4int, G4_c2_const_ptr > sigmaMap; // total cross section for each element
     130        std::map<G4int, G4_c2_const_ptr > MFPTables; // MFP for each material
    126131       
    127132private:
     
    134139        G4ScreenedCoulombCrossSection *crossSection;
    135140        G4double a1, a2, sinTheta, cosTheta, sinZeta, cosZeta, eRecoil;
    136         G4ParticleDefinition *recoilIon;        } G4CoulombKinematicsInfo;
     141        G4ParticleDefinition *recoilIon;       
     142        const G4Material *targetMaterial;
     143} G4CoulombKinematicsInfo;
    137144
    138145class G4ScreenedCollisionStage {
     
    146153
    147154public:
    148         G4ScreenedCoulombClassicalKinematics() { }
     155        G4ScreenedCoulombClassicalKinematics();
    149156        virtual void DoCollisionStep(class G4ScreenedNuclearRecoil *master,
    150157                const class G4Track& aTrack, const class G4Step& aStep);
     
    153160                const G4ScreeningTables *screen,
    154161                G4double eps, G4double beta);
    155         virtual ~G4ScreenedCoulombClassicalKinematics() {}
     162        virtual ~G4ScreenedCoulombClassicalKinematics() { }
     163protected:
     164        // the c2_functions we need to do the work.
     165        c2_const_plugin_function_p<G4double> &phifunc;
     166        c2_linear_p<G4double> &xovereps;
     167        G4_c2_ptr diff;
     168       
    156169};
    157170
     
    165178};
    166179
     180/**
     181        \brief A process which handles screened Coulomb collisions between nuclei
     182 
     183*/
     184
    167185class G4ScreenedNuclearRecoil : public G4ScreenedCoulombCrossSectionInfo, public G4VDiscreteProcess
    168186{
     
    171189        friend class G4ScreenedCollisionStage;
    172190
     191        /// \brief Construct the process and set some physics parameters for it.
     192        /// \param processName the name to assign the process
     193        /// \param ScreeningKey the name of a screening function to use. 
     194        /// The default functions are "zbl" (recommended for soft scattering),
     195        /// "lj" (recommended for backscattering) and "mol" (Moliere potential)
     196        /// \param GenerateRecoils if frue, ions struck by primary are converted into new moving particles.
     197        /// If false, energy is deposited, but no new moving ions are created.
     198        /// \param RecoilCutoff energy below which no new moving particles will be created,
     199        /// even if \a GenerateRecoils is true.
     200        /// Also, a moving primary particle will be stopped if its energy falls below this limit.
     201        /// \param PhysicsCutoff the energy transfer to which screening tables are calucalted. 
     202        /// There is no really
     203        /// compelling reason to change it from the 10.0 eV default.  However, see the paper on running this
     204        /// in thin targets for further discussion, and its interaction with SetMFPScaling()
    173205        G4ScreenedNuclearRecoil(const G4String& processName = "ScreenedElastic",
    174206                        const G4String &ScreeningKey="zbl", G4bool GenerateRecoils=1,
    175207                        G4double RecoilCutoff=100.0*eV, G4double PhysicsCutoff=10.0*eV);
    176        
     208        /// \brief destructor
    177209        virtual ~G4ScreenedNuclearRecoil();
    178        
     210        /// \brief used internally by Geant4 machinery
    179211        virtual G4double GetMeanFreePath(const G4Track&, G4double, G4ForceCondition* );
    180        
     212        /// \brief used internally by Geant4 machinery
    181213        virtual G4VParticleChange* PostStepDoIt(const G4Track& aTrack, const G4Step& aStep);
    182        
     214        /// \brief test if a prticle of type \a aParticleType can use this process
     215        /// \param aParticleType the particle to test
    183216        virtual G4bool IsApplicable(const G4ParticleDefinition& aParticleType);
    184        
     217        /// \brief Build physics tables in advance.  Not Implemented.
     218        /// \param aParticleType the type of particle to build tables for
    185219        virtual void BuildPhysicsTable(const G4ParticleDefinition&) { }
    186        
     220        /// \brief Export physics tables for persistency.  Not Implemented.
     221        /// \param aParticleType the type of particle to build tables for
    187222        virtual void DumpPhysicsTable(const G4ParticleDefinition& aParticleType);
    188        
     223        /// \brief deterine if the moving particle is within  the strong force range of the selected nucleus
     224        /// \param A the nucleon number of the beam
     225        /// \param A1 the nucleon number of the target
     226        /// \param apsis the distance of closest approach
    189227        virtual G4bool CheckNuclearCollision(G4double A, G4double A1, G4double apsis); // return true if hard collision
    190228
    191229        virtual G4ScreenedCoulombCrossSection *GetNewCrossSectionHandler(void);
    192230       
    193         G4double GetNIEL() const { return NIEL; } // Get non-ionizing energy loss for last step
    194        
     231        /// \brief Get non-ionizing energy loss for last step
     232        G4double GetNIEL() const { return NIEL; }
     233       
     234        /// \brief clear precomputed screening tables
    195235        void ResetTables(); // clear all data tables to allow changing energy cutoff, materials, etc.
    196        
     236
     237        /// \brief set the upper energy beyond which this process has no cross section
     238        ///
     239        /// This funciton is used to coordinate this process with G4MSC.  Typically, G4MSC should
     240        ///  not be allowed to operate in a range which overlaps that of this process.  The criterion which is most reasonable
     241        /// is that the transition should be somewhere in the modestly relativistic regime (500 MeV/u for example).
     242        /// \param energy energy per nucleon for the cutoff
     243        void SetMaxEnergyForScattering(G4double energy) { processMaxEnergy=energy; }
     244        /// \brief find out what screening funciton we are using
    197245        std::string GetScreeningKey() const { return screeningKey; }
     246        /// \brief enable or disable all energy deposition by this process
     247        /// \param flag if true, enable deposition of energy (the default).  If false, disable deposition.
    198248        void AllowEnergyDeposition(G4bool flag) { registerDepositedEnergy=flag; }
     249        /// \brief get flag indicating whether deposition is enabled
    199250        G4bool GetAllowEnergyDeposition() const { return registerDepositedEnergy; }
     251        /// \brief enable or disable the generation of recoils. 
     252        /// If recoils are disabled, the energy they would have received is just deposited.
     253        /// \param flag if true, create recoil ions in cases in which the energy is above the recoilCutoff. 
     254        /// If false, just deposit the energy.
    200255        void EnableRecoils(G4bool flag) { generateRecoils=flag; }
     256        /// \brief find out if generation of recoils is enabled.
    201257        G4bool GetEnableRecoils() const { return generateRecoils; }
     258        /// \brief set the mean free path scaling as specified
     259        /// \param scale the factor by which the default MFP will be scaled. 
     260        /// Set to less than 1 for very thin films, typically, to sample multiple scattering,
     261        /// or to greater than 1 for quick simulaitons with a very long flight path.
    202262        void SetMFPScaling(G4double scale) { MFPScale=scale; }
     263        /// \brief get the MFPScaling parameter
    203264        G4double GetMFPScaling() const { return MFPScale; }
     265        /// \brief enable or disable whether this process will skip collisions
     266        /// which are close enough they need hadronic phsyics. Default is true (skip close collisions).
     267        /// Disabling this results in excess nuclear stopping power.
     268        /// \param flag true results in hard collisions being skipped.  false allows hard collisions.
    204269        void AvoidNuclearReactions(G4bool flag) { avoidReactions=flag; }
     270        /// \brief get the flag indicating whether hadronic collisions are ignored.
    205271        G4bool GetAvoidNuclearReactions() const { return avoidReactions; }
     272        /// \brief set the minimum energy (per nucleon) at which recoils can be generated,
     273        /// and the energy (per nucleon) below which all ions are stopped.
     274        /// \param energy energy per nucleon
    206275        void SetRecoilCutoff(G4double energy) { recoilCutoff=energy; }
     276        /// \brief get the recoil cutoff
    207277        G4double GetRecoilCutoff() const { return recoilCutoff; }
     278        /// \brief set the energy to which screening tables are computed.  Typically, this is 10 eV or so, and not often changed.
     279        /// \param energy the cutoff energy
    208280        void SetPhysicsCutoff(G4double energy) { physicsCutoff=energy; ResetTables(); }
     281        /// \brief get the physics cutoff energy.
    209282        G4double GetPhysicsCutoff() const { return physicsCutoff; }
    210         class G4ParticleChange &GetParticleChange() { return aParticleChange; }
    211         void AddToNIEL(G4double energy) { NIEL+=energy; }
     283        /// \brief set the pointer to a class for paritioning energy into NIEL
     284        /// \brief part the pointer to the class.
     285        void SetNIELPartitionFunction(const G4VNIELPartition *part);
     286        /// \brief set the cross section boost to provide faster computation of backscattering
     287        /// \param fraction the fraction of particles to have their cross section boosted.
     288        /// \param HardeningFactor the factor by which to boost the scattering cross section.
    212289        void SetCrossSectionHardening(G4double fraction, G4double HardeningFactor) {
    213290                hardeningFraction=fraction;
    214291                hardeningFactor=HardeningFactor;
    215292        }
     293        /// \brief get the fraction of particles which will have boosted scattering
    216294        G4double GetHardeningFraction() const { return hardeningFraction; }
     295        /// \brief get the boost factor in use.
    217296        G4double GetHardeningFactor() const { return hardeningFactor; }
     297        /// \brief the the interaciton length used in the last scattering.
    218298        G4double GetCurrentInteractionLength() const { return currentInteractionLength; }
     299        /// \brief set a function to compute screening tables, if the user needs non-standard behavior.
     300        /// \param cs a class which constructs the screening tables.
    219301        void SetExternalCrossSectionHandler(G4ScreenedCoulombCrossSection *cs) {
    220302                externalCrossSectionConstructor=cs;
    221303        }
     304        /// \brief get the verbosity.
    222305        G4int GetVerboseLevel() const { return verboseLevel; }
     306
    223307        std::map<G4int, G4ScreenedCoulombCrossSection*> &GetCrossSectionHandlers()
    224308                { return crossSectionHandlers; }
     
    228312        void SetValidCollision(G4bool flag) { validCollision=flag; }
    229313        G4bool GetValidCollision() const { return validCollision; }
     314
     315        /// \brief get the pointer to our ParticleChange object.  for internal use, primarily.
     316        class G4ParticleChange &GetParticleChange() { return static_cast<G4ParticleChange &>(*pParticleChange); }
     317        /// \brief take the given energy, and use the material information to partition it into NIEL and ionizing energy.
     318        void DepositEnergy(G4int z1, G4double a1, const G4Material *material, G4double energy);
    230319       
    231320protected:
    232         G4double highEnergyLimit, lowEnergyLimit;
     321        /// \brief the energy per nucleon above which the MFP is constant
     322        G4double highEnergyLimit;
     323        /// \brief the energy per nucleon below which the MFP is zero
     324        G4double lowEnergyLimit;
     325        /// \brief the energy per nucleon beyond which the cross section is zero, to cross over to G4MSC
     326        G4double processMaxEnergy;
    233327        G4String screeningKey;
    234328        G4bool generateRecoils, avoidReactions;
    235329        G4double recoilCutoff, physicsCutoff;
    236330        G4bool registerDepositedEnergy;
    237         G4double NIEL;
     331        G4double IonizingLoss, NIEL;
    238332        G4double MFPScale;
    239333        G4double hardeningFraction, hardeningFactor;
     
    243337       
    244338        std::map<G4int, G4ScreenedCoulombCrossSection*> crossSectionHandlers;           
    245         std::map<G4int, c2_function<G4double>*> meanFreePathTables;
    246339       
    247340        G4bool validCollision;
    248341        G4CoulombKinematicsInfo kinematics;
    249 
     342        const G4VNIELPartition *NIELPartitionFunction;
    250343};
    251344
     
    268361        std::vector<G4String> GetScreeningKeys() const;
    269362       
    270         typedef c2_function<G4double> &(*ScreeningFunc)(G4int z1, G4int z2, size_t nPoints, G4double rMax, G4double *au);
     363        typedef G4_c2_function &(*ScreeningFunc)(G4int z1, G4int z2, size_t nPoints, G4double rMax, G4double *au);
    271364       
    272365        void AddScreeningFunction(G4String name, ScreeningFunc fn) {
     
    279372};
    280373
    281 
     374G4_c2_function &ZBLScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval);
     375G4_c2_function &MoliereScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval);
     376G4_c2_function &LJScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval);
     377G4_c2_function &LJZBLScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval);
    282378
    283379#endif
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysListEmLivermore.hh

    r807 r1230  
    2626//
    2727// $Id: PhysListEmLivermore.hh,v 1.1 2006/11/22 18:56:20 vnivanch Exp $
    28 // GEANT4 tag $Name: $
     28// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2929//
    3030//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysListEmPenelope.hh

    r807 r1230  
    2626//
    2727// $Id: PhysListEmPenelope.hh,v 1.1 2006/11/22 18:56:21 vnivanch Exp $
    28 // GEANT4 tag $Name: $
     28// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2929//
    3030//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysListEmStandard.hh

    r807 r1230  
    2626//
    2727// $Id: PhysListEmStandard.hh,v 1.3 2006/06/29 16:57:44 gunter Exp $
    28 // GEANT4 tag $Name: $
     28// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2929//
    3030//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysListEmStandardNR.hh

    r807 r1230  
    2525//
    2626// $Id: PhysListEmStandardNR.hh,v 1.1 2008/01/14 12:11:38 vnivanch Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysListEmStandardSS.hh

    r807 r1230  
    2525//
    2626// $Id: PhysListEmStandardSS.hh,v 1.1 2006/10/24 11:37:56 vnivanch Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysicsList.hh

    r807 r1230  
    2525//
    2626//
    27 // $Id: PhysicsList.hh,v 1.6 2006/11/22 18:56:21 vnivanch Exp $
    28 // GEANT4 tag $Name: $
     27// $Id: PhysicsList.hh,v 1.8 2008/11/20 20:34:50 vnivanch Exp $
     28// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2929//
    3030//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    3939
    4040#include "G4VModularPhysicsList.hh"
     41#include "G4EmConfigurator.hh"
    4142#include "globals.hh"
    4243
     
    5051{
    5152public:
     53
    5254  PhysicsList();
    5355  virtual ~PhysicsList();
     
    6769
    6870private:
     71
     72  G4EmConfigurator em_config;
     73
    6974  G4double cutForGamma;
    7075  G4double cutForElectron;
     
    7782  G4String                             emName;
    7883  G4VPhysicsConstructor*               emPhysicsList;
     84  G4VPhysicsConstructor*               decPhysicsList;
    7985  std::vector<G4VPhysicsConstructor*>  hadronPhys;
    8086   
  • trunk/examples/extended/electromagnetic/TestEm7/include/PhysicsListMessenger.hh

    r807 r1230  
    2525//
    2626// $Id: PhysicsListMessenger.hh,v 1.3 2006/06/29 16:57:52 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PrimaryGeneratorAction.hh

    r807 r1230  
    2525//
    2626// $Id: PrimaryGeneratorAction.hh,v 1.3 2006/06/29 16:57:54 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/PrimaryGeneratorMessenger.hh

    r807 r1230  
    2525//
    2626// $Id: PrimaryGeneratorMessenger.hh,v 1.3 2006/06/29 16:57:56 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/RunAction.hh

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: RunAction.hh,v 1.12 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: RunAction.hh,v 1.14 2008/08/22 18:30:27 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    4040class PrimaryGeneratorAction;
    4141class G4Run;
    42 
    43 namespace AIDA {
    44  class IAnalysisFactory;
    45  class ITree;
    46  class IHistogram1D;
    47 }
     42class Histo;
    4843
    4944//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    5247{
    5348public:
    54   RunAction(DetectorConstruction*, PhysicsList*,PrimaryGeneratorAction*);
     49  RunAction(DetectorConstruction*, PhysicsList*,
     50            PrimaryGeneratorAction*);
    5551  virtual ~RunAction();
    5652
     
    5854  void   EndOfRunAction(const G4Run*);
    5955   
    60   void FillTallyEdep(G4int n, G4double e) {tallyEdep[n] += e;};
     56  void FillTallyEdep(G4int n, G4double e)  {tallyEdep[n] += e;};
    6157  void FillEdep(G4double de, G4double eni) {edeptot += de; eniel += eni;};
    6258       
    6359  G4double GetBinLength() {return binLength;};
    6460  G4double GetLength()    {return length;};
    65   G4double GetOffsetX()   {return offsetX;}
    66   void     FillHisto(G4int id, G4double x, G4double weight = 1.0);
     61  G4double GetOffsetX()   {return offsetX;}
     62 
     63  void FillHisto(G4int id, G4double x, G4double weight = 1.0);
    6764   
    68   void AddProjRange (G4double x) {projRange += x; projRange2 += x*x;};
     65  void AddProjRange (G4double x)
     66  {projRange += x; projRange2 += x*x; nRange++;};
    6967  void AddPrimaryStep() {nPrimarySteps++;};
    7068                   
    7169private: 
    72   void bookHisto();
    73   void cleanHisto();
    7470   
    75 private:
    7671  DetectorConstruction*   detector;
    7772  PhysicsList*            physics;
     
    8479  G4double                edeptot, eniel;
    8580  G4int                   nPrimarySteps;
    86            
    87   AIDA::IAnalysisFactory* af; 
    88   AIDA::ITree*            tree;
    89   AIDA::IHistogram1D*     histo[1];       
     81  G4int                   nRange;
     82
     83  Histo*                  histo;
    9084};
    9185
  • trunk/examples/extended/electromagnetic/TestEm7/include/StepMax.hh

    r807 r1230  
    2525//
    2626// $Id: StepMax.hh,v 1.3 2006/06/29 16:58:01 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/StepMaxMessenger.hh

    r807 r1230  
    2525//
    2626// $Id: StepMaxMessenger.hh,v 1.2 2006/06/29 16:58:03 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/SteppingAction.hh

    r807 r1230  
    2525//
    2626// $Id: SteppingAction.hh,v 1.2 2006/06/29 16:58:05 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/SteppingVerbose.hh

    r807 r1230  
    2525//
    2626// $Id: SteppingVerbose.hh,v 1.2 2006/06/29 16:58:07 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/TrackingAction.hh

    r807 r1230  
    2525//
    2626// $Id: TrackingAction.hh,v 1.2 2006/06/29 16:58:09 gunter Exp $
    27 // GEANT4 tag $Name: $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/include/c2_function.hh

    r807 r1230  
     1//
     2// ********************************************************************
     3// * License and Disclaimer                                           *
     4// *                                                                  *
     5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
     6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
     7// * conditions of the Geant4 Software License,  included in the file *
     8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
     9// * include a list of copyright holders.                             *
     10// *                                                                  *
     11// * Neither the authors of this software system, nor their employing *
     12// * institutes,nor the agencies providing financial support for this *
     13// * work  make  any representation or  warranty, express or implied, *
     14// * regarding  this  software system or assume any liability for its *
     15// * use.  Please see the license in the file  LICENSE  and URL above *
     16// * for the full disclaimer and the limitation of liability.         *
     17// *                                                                  *
     18// * This  code  implementation is the result of  the  scientific and *
     19// * technical work of the GEANT4 collaboration.                      *
     20// * By using,  copying,  modifying or  distributing the software (or *
     21// * any work based  on the software)  you  agree  to acknowledge its *
     22// * use  in  resulting  scientific  publications,  and indicate your *
     23// * acceptance of all terms of the Geant4 Software license.          *
     24// ********************************************************************
     25//
     26//
    127/**
    228 *  \file
     
    733 *  \author Copyright 2005 __Vanderbilt University__. All rights reserved.
    834 *
    9  *      \version c2_function.hh,v 1.53 2007/11/12 13:58:57 marcus Exp
     35 *      \version c2_function.hh,v 1.238 2008/05/22 12:45:19 marcus Exp
     36 *  \see \ref c2_factory "Factory Functions" for information on constructing things in here 
    1037 */
    1138
    12 #ifndef __has_C2Functions_c2_h
    13 #define __has_C2Functions_c2_h 1
     39#ifndef __has_c2_function_hh
     40#define __has_c2_function_hh 1
     41
     42// MSVC does not automatically define numerical constants such as M_PI without this.
     43// this came from the msdn website, so it should be right...
     44#ifdef _MSC_VER
     45#define _USE_MATH_DEFINES
     46#define c2_isnan _isnan
     47#define c2_isfinite _finite
     48#else
     49#define c2_isnan std::isnan
     50#define c2_isfinite std::isfinite
     51#endif
    1452
    1553#include <cmath>
    1654#include <vector>
     55#include <utility>
    1756#include <string>
     57#include <stdexcept>
     58#include <typeinfo>
     59#include <sstream>
    1860
    1961/// \brief the exception class for c2_function operations.
     
    3274
    3375// put these forward references here, and with a bogus typename to make swig happy.
    34 template <typename float_type> class c2_composed_function;
    35 template <typename float_type> class c2_sum;
    36 template <typename float_type> class c2_diff;
    37 template <typename float_type> class c2_product;
    38 template <typename float_type> class c2_ratio;
     76template <typename float_type> class c2_composed_function_p;
     77template <typename float_type> class c2_sum_p;
     78template <typename float_type> class c2_diff_p;
     79template <typename float_type> class c2_product_p;
     80template <typename float_type> class c2_ratio_p;
     81template <typename float_type> class c2_piecewise_function_p;
     82template <typename float_type> class c2_quadratic_p;
     83template <typename float_type> class c2_ptr;
     84/**
     85        \defgroup abstract_classes Abstract Classes
     86        \defgroup arithmetic_functions Arithmetic Functions
     87        \defgroup math_functions Mathemetical Functions
     88        \defgroup parametric_functions Parametric Families of Functions
     89        \defgroup interpolators Interpolating Functions
     90        \defgroup containers Functions which are containers for, or functions of, other functions
     91        \defgroup factories Factory classes which reduce silly template typing
     92        \defgroup transforms Classes which provide coordinate system transformations, wih derivatives
     93*/
     94
     95/// \brief structure used to hold evaluated function data at a point. 
     96///
     97/// Contains all the information for the function at one point.
     98template <typename float_type> class c2_fblock
     99{       
     100public:
     101        /// \brief the abscissa
     102        float_type x;
     103        /// \brief the value of the function at \a x
     104        float_type y;
     105        /// \brief the derivative at \a x
     106        float_type yp;
     107        /// \brief the second derivative at \a x
     108        float_type ypp;
     109        /// flag, filled in by c2_function::fill_fblock(), indicating the derivative is NaN of Inf
     110        bool ypbad;
     111        /// flag, filled in by c2_function::fill_fblock(), indicating the second derivative is NaN of Inf
     112        bool yppbad;
     113};
    39114
    40115/**
    41116 \brief the parent class for all c2_functions.
    42 
     117 \ingroup abstract_classes
    43118  c2_functions know their value, first, and second derivative at almost every point.
    44119  They can be efficiently combined with binary operators, via c2_binary_function,
    45   composed via c2_composed_function,
     120  composed via c2_composed_function_,
    46121  have their roots found via find_root(),
    47122  and be adaptively integrated via partial_integrals() or integral().
     
    53128    log_log_interpolating_function, and arrhenius_interpolating_function,
    54129    as well as the template functions
    55     inverse_integrated_density().
     130    inverse_integrated_density_function().
    56131 
    57  \warning
    58  The composite flavors of c2_functions (c2_sum, c2_composed_function, c2_binary_function, e.g.) make no effort to manage
    59  deletion of their component functions.
    60  These are just container classes, and the user (along with normal automatic variable semantics)
    61  is responsible for the lifetime of components.
    62  Inappropriate attention to this can cause massive memory leaks. 
    63  However, in most cases these do exactly what is intended.
    64  The classes will be left this way since the only other option is to use copy constructors on everything,
    65  which would make this all very slow.
     132 For a discussion of memory management, see \ref memory_management
    66133 
    67134 */
     
    71138    /// \return the CVS Id string
    72139        const std::string cvs_header_vers() const { return
    73                 "c2_function.hh,v 1.53 2007/11/12 13:58:57 marcus Exp";
     140                "c2_function.hh,v 1.238 2008/05/22 12:45:19 marcus Exp";
    74141        }
    75142       
     
    80147public:
    81148    /// \brief destructor
    82         virtual ~c2_function() { if(sampling_grid && !no_overwrite_grid) delete sampling_grid; }
     149        virtual ~c2_function() {
     150                if(sampling_grid && !no_overwrite_grid) delete sampling_grid;   
     151                if(root_info) delete root_info;
     152                if(owner_count) {
     153                        std::ostringstream outstr;
     154                        outstr << "attempt to delete an object with non-zero ownership in class ";
     155                        outstr << typeid(*this).name() << std::endl;
     156                        throw c2_exception(outstr.str().c_str());
     157                }
     158        }
    83159       
    84160        /// \brief get the value and derivatives.
     
    97173        inline float_type operator () (float_type x) const throw(c2_exception)
    98174        { return value_with_derivatives(x, (float_type *)0, (float_type *)0); }
    99 
    100     /// \brief compose this function outside another.
    101     /// \param inner the inner function
    102     /// \return the composed function
    103         c2_composed_function<float_type> & operator ()(const c2_function<float_type> &inner) const
    104                 { return *new c2_composed_function<float_type>((*this), inner); }
    105175
    106176        /// \brief get the value and derivatives.
     
    130200    /// \param[out] final_yprime2 If pointer is not zero, return second derivative of function at root
    131201    /// \return the position of the root.
     202        /// \see \ref rootfinder_subsec "Root finding sample"
    132203        float_type find_root(float_type lower_bracket, float_type upper_bracket, float_type start,
    133204        float_type value, int *error=0,
     
    151222    /// with no error checking.
    152223    /// \param extrapolate if true, use simple Richardson extrapolation on the final 2 steps to reduce the error.
    153     /// \return sum of partial integrals, whcih is the definite integral from the first value in \a xgrid to the last.
     224    /// \return sum of partial integrals, which is the definite integral from the first value in \a xgrid to the last.
    154225        float_type partial_integrals(std::vector<float_type> xgrid, std::vector<float_type> *partials = 0,
    155           float_type abs_tol=1e-12, float_type rel_tol=1e-12, int derivs=2, bool adapt=true, bool extrapolate=true) const;
     226          float_type abs_tol=1e-12, float_type rel_tol=1e-12, int derivs=2, bool adapt=true, bool extrapolate=true)
     227                const throw(c2_exception);
    156228       
    157229    /// \brief a fully-automated integrator which uses the information provided by the get_sampling_grid() function
     
    164236        /// \param xmax upper bound of the domain for integration
    165237    /// \param partials if non-NULL, a vector in which to receive the partial integrals.
    166         /// It will automatically be sized apprpropriately, if provided, to contain \a n - 1 elements where \a n is the length of \a xgrid 
     238        /// It will automatically be sized appropriately, if provided, to contain \a n - 1 elements where \a n is the length of \a xgrid 
    167239    /// \param abs_tol the absolute error bound for each segment
    168240    /// \param rel_tol the fractional error bound for each segment. 
     
    173245    /// with no error checking.
    174246    /// \param extrapolate if true, use simple Richardson extrapolation on the final 2 steps to reduce the error.
    175     /// \return sum of partial integrals, whcih is the definite integral from the first value in \a xgrid to the last.
     247    /// \return sum of partial integrals, which is the definite integral from the first value in \a xgrid to the last.
    176248        float_type integral(float_type xmin, float_type xmax, std::vector<float_type> *partials = 0,
    177              float_type abs_tol=1e-12, float_type rel_tol=1e-12, int derivs=2, bool adapt=true, bool extrapolate=true) const;
    178 
     249             float_type abs_tol=1e-12, float_type rel_tol=1e-12, int derivs=2, bool adapt=true, bool extrapolate=true)
     250                const throw(c2_exception);
     251
     252        /// \brief create a c2_piecewise_function_p from c2_connector_function_p segments which
     253        /// is a representation of the parent function to the specified accuracy, but maybe much cheaper to evaluate
     254        ///
     255        /// This method has three modes, depending on the \a derivs flag.
     256        ///
     257        /// If \a derivs is 2,
     258        /// it computes a c2_piecewise_function_p representation of its parent function, which may be a much faster
     259        /// function to use in codes if the parent function is expensive.  If \a xvals and \a yvals are non-null,
     260        /// it will also fill them in with the function values at each grid point the adaptive algorithm chooses.
     261        ///
     262        /// If \a derivs is 1, this does not create the connectors,
     263        /// and returns an null pointer, but will fill in the \a xvals and \a yvals
     264        /// vectors with values of the function at points such that the linear interpolation error between the points
     265        /// is bounded by the tolerance values given.  Because it uses derivative information from the function to manage the
     266        /// error control, it is almost completely free of issues with missing periods of oscillatory functions,
     267        /// even with no information provided in the sampling grid.
     268        /// This is typically useful for sampling a function for plotting.
     269        ///
     270        /// If \a derivs is 0, this does something very like what it does if \a derivs = 1, but without derivatives. 
     271        /// Instead, to compute the intermediate value of the function for error control, it just uses
     272        /// 3-point parabolic interpolation.  This is useful amost exclusively for converting a non-c2_function,
     273        /// with no derivatives, but wrapped in a c2_classic_function wrapper, into a table of values to seed an interpolating_function_p.
     274        /// Note, however, that without derivatives, this is very susceptible to missing periods of oscillatory
     275        /// functions, so it is important to set a sampling grid which isn't too much coarser than the typical oscillations.
     276        ///
     277        /// \note the \a sampling_grid of the returned function matches the \a sampling_grid of its parent.
     278        /// \see \ref sample_function_for_plotting "Adaptive Sampling Examples"
     279    /// \param xmin lower bound of the domain for sampling
     280        /// \param xmax upper bound of the domain for sampling
     281    /// \param abs_tol the absolute error bound for each segment
     282    /// \param rel_tol the fractional error bound for each segment.
     283        /// \param derivs if 0 or 1, return a useless function, but fill in the \a xvals and \a yvals vectors (if non-null).
     284        /// Also, if 0 or 1, tolerances refer to linear interpolation, not high-order interpolation.
     285        /// If 2, return a full piecewise collection of c2_connector_function_p segments.  See discussion above.
     286        /// \param [in,out] xvals vector of abscissas at which the function was actually sampled (if non-null)
     287        /// \param [in,out] yvals vector of function values corresponding to \a xvals (if non-null)
     288        /// \return a new, sampled representation, if \a derivs is 2.  A null pointer if \a derivs is 0 or 1.
     289        c2_piecewise_function_p<float_type> *adaptively_sample(float_type xmin, float_type xmax,
     290                 float_type abs_tol=1e-12, float_type rel_tol=1e-12,
     291                 int derivs=2, std::vector<float_type> *xvals=0, std::vector<float_type> *yvals=0) const throw(c2_exception);
     292       
    179293        /// \brief return the lower bound of the domain for this function as set by set_domain()
    180294        inline float_type xmin() const { return fXMin; }
     
    186300        /// \brief this is a counter owned by the function but which can be used to monitor efficiency of algorithms.
    187301        ///
    188         /// It is not maintained automatically in general! 
    189         /// The adaptive integrator and root finder do clear it at the start and update it for performance checking.
     302        /// It is not maintained automatically in general!  The root finder, integrator, and sampler do increment it.
    190303        /// \return number of evaluations logged since last reset.
    191         volatile int get_evaluations() const { return evaluations; }
     304        volatile size_t get_evaluations() const { return evaluations; }
    192305        /// \brief reset the counter
    193306        void reset_evaluations()  const { evaluations=0; } // evaluations are 'invisible' to constant
     
    200313        /// \param message an informative string to include in an exception if this throws c2_exception
    201314        /// \return true if in decreasing order, false if increasing
    202         bool check_monotonicity(const std::vector<float_type> &data, const char message[]) throw(c2_exception);
     315        bool check_monotonicity(const std::vector<float_type> &data, const char message[]) const throw(c2_exception);
    203316       
    204317        /// \brief establish a grid of 'interesting' points on the function.
     
    212325        virtual void set_sampling_grid(const std::vector<float_type> &grid) throw(c2_exception);
    213326       
     327        /// \brief get the sampling grid, which may be a null pointer
     328        /// \return pointer to the sampling grid
     329        std::vector<float_type> *get_sampling_grid_pointer() const { return sampling_grid; }
     330       
    214331    /// \brief return the grid of 'interesting' points along this function which lie in the region requested
    215332        ///
     
    217334        /// \param xmin the lower bound for which the function is to be sampled
    218335        /// \param xmax the upper bound for which the function is to be sampled
    219         /// \return a new vector containing the samplng grid.
    220         virtual std::vector<float_type> &get_sampling_grid(float_type xmin, float_type xmax) const ;
     336        /// \param [in,out] grid filled vector containing the samplng grid.
     337        virtual void get_sampling_grid(float_type xmin, float_type xmax, std::vector<float_type> &grid) const ;
    221338       
    222339        /// \brief clean up endpoints on a grid of points
    223         ///
    224340        /// \param[in,out] result the sampling grid with excessively closely space endpoints removed.
    225341        /// The grid is modified in place.
    226342        void preen_sampling_grid(std::vector<float_type> *result) const;               
    227343        /// \brief refine a grid by splitting each interval into more intervals
    228         /// \param grid the grid to refine
     344        /// \param [in,out] grid the grid to refine in place
    229345        /// \param refinement the number of new steps for each old step
    230         /// \return a new sampling grid with more points.
    231         std::vector<float_type> & refine_sampling_grid(const std::vector<float_type> &grid, size_t refinement) const;           
     346        void refine_sampling_grid(std::vector<float_type> &grid, size_t refinement) const;             
    232347       
    233348        /// \brief create a new c2_function from this one which is normalized on the interval
     
    236351        /// \param norm the desired integral for the function over the region
    237352        /// \return a new c2_function with the desired \a norm.
    238         c2_function<float_type> &normalized_function(float_type xmin, float_type xmax, float_type norm=1.0);
     353        c2_function<float_type> &normalized_function(float_type xmin, float_type xmax, float_type norm=1.0) const throw(c2_exception);
    239354        /// \brief create a new c2_function from this one which is square-normalized on the interval
    240355    /// \param xmin lower bound of the domain for integration
     
    242357        /// \param norm the desired integral for the function over the region
    243358        /// \return a new c2_function with the desired \a norm.
    244         c2_function<float_type> &square_normalized_function(float_type xmin, float_type xmax, float_type norm=1.0);
     359        c2_function<float_type> &square_normalized_function(float_type xmin, float_type xmax, float_type norm=1.0) const throw(c2_exception);
    245360        /// \brief create a new c2_function from this one which is square-normalized with the provided \a weight on the interval
    246361    /// \param xmin lower bound of the domain for integration
     
    249364        /// \param norm the desired integral for the function over the region
    250365        /// \return a new c2_function with the desired \a norm.
    251         c2_function<float_type> &square_normalized_function(float_type xmin, float_type xmax, const c2_function<float_type> &weight, float_type norm=1.0);
    252 
    253         /// \brief factory function to create a c2_sum from an regular algebraic expression.
    254         /// \note
    255         /// be very wary of ownership issues if this is used in a complex expression.
    256         c2_sum<float_type> &operator + (const c2_function<float_type> &rhs)  { return *new c2_sum<float_type>(*this, rhs); }
    257         /// \brief factory function to create a c2_diff from an regular algebraic expression.
    258         /// \note
    259         /// be very wary of ownership issues if this is used in a complex expression.
    260         c2_diff<float_type> &operator - (const c2_function<float_type> &rhs)  { return *new c2_diff<float_type>(*this, rhs); }
    261         /// \brief factory function to create a c2_product from an regular algebraic expression.
    262         /// \note
    263         /// be very wary of ownership issues if this is used in a complex expression.
    264         c2_product<float_type> &operator * (const c2_function<float_type> &rhs)  { return *new c2_product<float_type>(*this, rhs); }
    265         /// \brief factory function to create a c2_ratio from an regular algebraic expression.
    266         /// \note
    267         /// be very wary of ownership issues if this is used in a complex expression.
    268         c2_ratio<float_type> &operator / (const c2_function<float_type> &rhs)  { return *new c2_ratio<float_type>(*this, rhs); }
    269        
    270 
    271        
    272         std::vector<float_type> *sampling_grid;
    273         bool no_overwrite_grid;
    274            
     366        c2_function<float_type> &square_normalized_function(
     367                float_type xmin, float_type xmax, const c2_function<float_type> &weight, float_type norm=1.0)
     368                const throw(c2_exception);
     369
     370        /// \brief factory function to create a c2_sum_p from a regular algebraic expression.
     371        /// \param rhs the right-hand term of the sum
     372        /// \return a new c2_function
     373        c2_sum_p<float_type> &operator + (const c2_function<float_type> &rhs)  const
     374                { return *new c2_sum_p<float_type>(*this, rhs); }
     375        /// \brief factory function to create a c2_diff_p from a regular algebraic expression.
     376        /// \param rhs the right-hand term of the difference
     377        /// \return a new c2_function
     378        c2_diff_p<float_type> &operator - (const c2_function<float_type> &rhs)  const
     379                { return *new c2_diff_p<float_type>(*this, rhs); }
     380        /// \brief factory function to create a c2_product_p from a regular algebraic expression.
     381        /// \param rhs the right-hand term of the product
     382        /// \return a new c2_function
     383        c2_product_p<float_type> &operator * (const c2_function<float_type> &rhs) const
     384                { return *new c2_product_p<float_type>(*this, rhs); }
     385        /// \brief factory function to create a c2_ratio_p from a regular algebraic expression.
     386        /// \param rhs the right-hand term of the ratio (the denominator)
     387        /// \return a new c2_function
     388        c2_ratio_p<float_type> &operator / (const c2_function<float_type> &rhs)  const
     389                { return *new c2_ratio_p<float_type>(*this, rhs); }
     390    /// \brief compose this function outside another.
     391    /// \param inner the inner function
     392    /// \return the composed function
     393        /// \anchor compose_operator
     394        c2_composed_function_p<float_type> & operator ()(const c2_function<float_type> &inner) const
     395                { return *new c2_composed_function_p<float_type>((*this), inner); }
     396
     397        /// \brief Find out where a calculation ran into trouble, if it got a nan.
     398        /// If the most recent computation did not return a nan, this is undefined.
     399        /// \return \a x value of point at which something went wrong, if integrator (or otherwise) returned a nan.
     400        float_type get_trouble_point() const { return bad_x_point; }
     401       
     402        /// \brief increment our reference count.  Destruction is only legal if the count is zero.
     403        void claim_ownership() const { owner_count++; }
     404        /// \brief decrement our reference count. Do not destroy at zero.
     405        /// \return final owner count, to check whether object should disappear.
     406        size_t release_ownership_for_return() const throw(c2_exception) {
     407                if(!owner_count) {
     408                        std::ostringstream outstr;
     409                        outstr << "attempt to release ownership of an unowned function in class ";
     410                        outstr << typeid(*this).name() << std::endl;
     411                        throw c2_exception(outstr.str().c_str());
     412                }
     413                owner_count--;
     414                return owner_count;
     415        }
     416        /// \brief decrement our reference count. If the count reaches zero, destroy ourself.
     417        void release_ownership() const throw(c2_exception) {
     418                if(!release_ownership_for_return()) delete this;
     419        }
     420        /// \brief get the reference count, mostly for debugging
     421        /// \return the count
     422        size_t count_owners() const { return owner_count; }
     423
    275424protected:
    276425        c2_function(const c2_function<float_type>  &src) : sampling_grid(0),
    277426                no_overwrite_grid(false),
    278         fXMin(src.fXMin), fXMax(src.fXMax), rootInitialized(false)
     427        fXMin(src.fXMin), fXMax(src.fXMax), root_info(0), owner_count(0)
    279428        {} // copy constructor only copies domain, and is only for internal use
    280429        c2_function() :
    281430                        sampling_grid(0), no_overwrite_grid(0),
    282431        fXMin(-std::numeric_limits<float_type>::max()),
    283         fXMax(std::numeric_limits<float_type>::max()),
    284         rootInitialized(false)
     432        fXMax(std::numeric_limits<float_type>::max()), root_info(0), owner_count(0)
    285433                {} // prevent accidental naked construction (impossible any since this has pure virtual methods)
    286434       
     
    293441                }
    294442       
     443        std::vector<float_type> * sampling_grid;
     444        bool no_overwrite_grid;
     445       
    295446        float_type fXMin, fXMax;
    296         mutable int evaluations;
    297        
     447        mutable size_t evaluations;
     448        /// \brief this point may be used to record where a calculation ran into trouble
     449        mutable float_type bad_x_point;
     450public:
     451        /// \brief fill in a c2_fblock<float_type>... a shortcut for the integrator & sampler
     452        /// \param [in,out] fb the block to fill in with information
     453        inline void fill_fblock(c2_fblock<float_type> &fb) const throw(c2_exception)
     454        {
     455                fb.y=value_with_derivatives(fb.x, &fb.yp, &fb.ypp);
     456                fb.ypbad=c2_isnan(fb.yp) || !c2_isfinite(fb.yp);
     457                fb.yppbad=c2_isnan(fb.ypp) || !c2_isfinite(fb.ypp);
     458                increment_evaluations();
     459        }
     460
    298461private:
    299         /// \brief structure used for recursion in adaptive integrator. 
    300         ///
    301         /// Contains all the information for the function at one point.
    302         struct c2_integrate_fblock {    float_type x, y, yp, ypp; };
    303         /// \brief structure used to pass information recursively.
     462        /// \brief the data element for the internal recursion stack for the sampler and integrator
     463        struct recur_item {
     464                c2_fblock<float_type> f1; size_t depth;
     465                float_type previous_estimate, abs_tol, step_sum;
     466                bool done;
     467                size_t f0index, f2index;
     468        };
     469       
     470
     471        /// \brief structure used to pass information recursively in integrator.
    304472        ///
    305473        /// the \a abs_tol is scaled by a factor of two at each division. 
    306474        /// Everything else is just passed down.
    307         struct c2_integrate_recur { struct c2_integrate_fblock *f0, *f1, *f2;
    308                 float_type abs_tol, rel_tol, *lr, eps_scale, extrap_coef, extrap2;
    309                 int depth, derivs;
    310                 bool adapt, extrapolate;
     475        struct c2_integrate_recur {
     476                c2_fblock<float_type> *f0, *f1;
     477                float_type abs_tol, rel_tol, eps_scale, extrap_coef, extrap2, dx_tolerance, abs_tol_min;
     478                std::vector< recur_item > *rb_stack;
     479                int  derivs;
     480                bool adapt, extrapolate, inited;
     481        };
     482
     483        /// \brief structure used to pass information recursively in sampler.
     484        ///
     485        struct c2_sample_recur {
     486                c2_fblock<float_type> *f0, *f1;
     487                float_type abs_tol, rel_tol, dx_tolerance, abs_tol_min;
     488                int derivs;
     489                c2_piecewise_function_p<float_type> *out;
     490                std::vector<float_type> *xvals, *yvals;
     491                std::vector< recur_item > *rb_stack;
     492                bool inited;
     493        };
     494
     495        /// \brief structure used to hold root bracketing information
     496        ///
     497        struct c2_root_info {
     498                c2_fblock<float_type> lower, upper;
     499                bool inited;
    311500        };
    312501       
     
    316505    /// to allow very efficient recursion.
    317506    /// \param rb a pointer to the recur struct.
    318         float_type integrate_step(struct c2_integrate_recur &rb) const;
     507        float_type integrate_step(struct c2_integrate_recur &rb) const throw(c2_exception);
    319508   
    320     /// these carry a memory of the last root bracketing,
     509    /// \brief Carry out the recursive subdivision for sampling.
     510    ///
     511    /// This passes information recursively through the \a recur block pointer
     512    /// to allow very efficient recursion.
     513    /// \param rb a pointer to the recur struct.
     514        void sample_step(struct c2_sample_recur &rb) const throw(c2_exception);
     515
     516    /// this carry a memory of the last root bracketing,
    321517    /// to avoid the necessity of evaluating the function on the brackets every time
    322518    /// if the brackets have not been changed.
    323     mutable float_type lastRootLowerX, lastRootUpperX, lastRootLowerY, lastRootUpperY;
    324     mutable int rootInitialized;
    325        
    326 };
    327 
     519        /// it is declared as a pointer, since many c2_functions may never need one allocated
     520    mutable struct  c2_root_info *root_info;
     521       
     522        mutable size_t owner_count;
     523};
     524
     525/// \brief a container into which any conventional c-style function can be dropped,
     526/// to create a degenerate c2_function without derivatives.
     527/// Mostly useful for sampling into interpolating functions.
     528/// construct a reference to this with c2_classic_function()
     529/// \ingroup containers
     530/// The factory function c2_factory::classic_function() creates *new c2_classic_function_p()
     531template <typename float_type=double> class c2_classic_function_p : public c2_function<float_type> {
     532public:
     533        /// \brief construct the container
     534        /// \param c_func a pointer to a conventional c-style function
     535        c2_classic_function_p(const float_type (*c_func)(float_type)) : c2_function<float_type>(), func(c_func)  {}
     536
     537        /// \copydoc c2_function::value_with_derivatives
     538        /// Uses the internal function pointer set by set_function().
     539        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     540        {
     541                if(!func) throw c2_exception("c2_classic_function called with null function");
     542                if(yprime) *yprime=0;
     543                if(yprime2) *yprime2=0;
     544                return func(x);
     545        }
     546        ~c2_classic_function_p() { }
     547       
     548protected:
     549        /// \brief pointer to our function
     550        const float_type (*func)(float_type);
     551};
     552
     553/// \brief create a container for a c2_function which handles the reference counting.
     554/// \ingroup containers
     555/// It is useful as a smart container to hold a c2_function and keep the reference count correct. 
     556/// The recommended way for a class to store a c2_function which is handed in from the outside
     557/// is for it to have a c2_ptr member into which the passed-in function is stored.
     558/// This way, when the class instance is deleted, it will automatically dereference any function
     559/// which it was handed.
     560///
     561/// This class contains a copy constructor and operator=, to make it fairly easy to make
     562/// a std::vector of these objects, and have it work as expected.
     563template <typename float_type> class c2_const_ptr {
     564public:
     565        /// \brief construct the container with no function
     566        c2_const_ptr() : func(0)  {}
     567        /// \brief construct the container with a pre-defined function
     568        /// \param f the function to store
     569        c2_const_ptr(const c2_function<float_type> &f) : func(0)
     570                { set_function(&f); }
     571        /// \brief copy constructor
     572        /// \param src the container to copy
     573        c2_const_ptr(const c2_const_ptr<float_type> &src) : func(0)
     574                { set_function(src.get_ptr()); }
     575        /// \brief fill the container with a new function, or clear it with a null pointer
     576        /// \param f the function to store, releasing any previously held function
     577        void set_function(const c2_function<float_type> *f)
     578        {
     579                if(func) func->release_ownership();
     580                func=f;
     581                if(func) func->claim_ownership();
     582        }
     583       
     584        /// \brief fill the container from another container
     585        /// \param f the container to copy
     586        void operator =(const c2_const_ptr<float_type> &f)
     587                { set_function(f.get_ptr()); }
     588        /// \brief fill the container with a function
     589        /// \param f the function
     590        void operator =(const c2_function<float_type> &f)
     591                { set_function(&f); }
     592        /// \brief release the function without destroying it, so it can be returned from a function
     593        ///
     594        /// This is usually the very last line of a function before the return statement, so that
     595        /// any exceptions that happen during execution of the function will cause proper cleanup.
     596        /// Once the function has been released from its container this way, it is an orhpaned object
     597        /// until the caller claims it, so it could get lost if an exception happens.
     598        void release_for_return() throw(c2_exception)
     599                {       
     600                        if(func) func->release_ownership_for_return();
     601                        func=0;
     602                }
     603        /// \brief clear the function
     604        ///
     605        /// Any attempt to use this c2_plugin_function_p throws an exception if the saved function is cleared.
     606        void unset_function(void) { set_function(0);  }
     607        /// \brief destructor
     608        ~c2_const_ptr() { set_function(0); }
     609       
     610        /// \brief get a reference to our owned function
     611        inline const c2_function<float_type> &get() const throw(c2_exception)
     612        {
     613                if(!func) throw c2_exception("c2_ptr accessed uninitialized");
     614                return *func;
     615        }
     616        /// \brief get an unchecked pointer to our owned function
     617        inline const c2_function<float_type> *get_ptr() const { return func; }
     618        /// \brief get a checked pointer to our owned function
     619        inline const c2_function<float_type> *operator -> () const
     620                { return &get(); }
     621        /// \brief check if we have a valid function
     622        bool valid() const { return func != 0; }
     623       
     624        /// \brief type coercion operator which lets us use a pointer as if it were a const c2_function
     625        operator const c2_function<float_type>& () const { return this->get(); }
     626       
     627        /// \brief convenience operator to make us look like a function
     628        /// \param x the value at which to evaluate the contained function
     629        /// \return the evaluated function
     630        /// \note If you using this repeatedly, do const c2_function<float_type> &func=ptr;
     631        /// and use func(x).  Calling this operator wastes some time, since it checks the validity of the
     632        /// pointer every time.
     633        float_type operator()(float_type x) const throw(c2_exception) { return get()(x); }
     634        /// \brief convenience operator to make us look like a function
     635        /// \param x the value at which to evaluate the contained function
     636        /// \param yprime the derivative
     637        /// \param yprime2 the second derivative
     638        /// \return the evaluated function
     639        /// \note If you using this repeatedly, do const c2_function<float_type> &func=ptr;
     640        /// and use func(x).  Calling this operator wastes some time, since it checks the validity of the
     641        /// pointer every time.
     642        float_type operator()(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     643                { return get().value_with_derivatives(x, yprime, yprime2); }
     644        /// \brief factory function to create a c2_sum_p from a regular algebraic expression.
     645        /// \param rhs the right-hand term of the sum
     646        /// \return a new c2_function
     647        c2_sum_p<float_type> &operator + (const c2_function<float_type> &rhs)  const throw(c2_exception)
     648                { return *new c2_sum_p<float_type>(get(), rhs); }
     649        /// \brief factory function to create a c2_diff_p from a regular algebraic expression.
     650        /// \param rhs the right-hand term of the difference
     651        /// \return a new c2_function
     652        c2_diff_p<float_type> &operator - (const c2_function<float_type> &rhs)  const throw(c2_exception)
     653                { return *new c2_diff_p<float_type>(get(), rhs); }
     654        /// \brief factory function to create a c2_product_p from a regular algebraic expression.
     655        /// \param rhs the right-hand term of the product
     656        /// \return a new c2_function
     657        c2_product_p<float_type> &operator * (const c2_function<float_type> &rhs) const throw(c2_exception)
     658                { return *new c2_product_p<float_type>(get(), rhs); }
     659        /// \brief factory function to create a c2_ratio_p from a regular algebraic expression.
     660        /// \param rhs the right-hand term of the ratio (the denominator)
     661        /// \return a new c2_function
     662        c2_ratio_p<float_type> &operator / (const c2_function<float_type> &rhs)  const throw(c2_exception)
     663                { return *new c2_ratio_p<float_type>(get(), rhs); }
     664    /// \brief compose this function outside another.
     665    /// \param inner the inner function
     666    /// \return the composed function
     667        c2_composed_function_p<float_type> & operator ()(const c2_function<float_type> &inner) const throw(c2_exception)
     668                { return *new c2_composed_function_p<float_type>(get(), inner); }
     669       
     670protected:
     671        const c2_function<float_type> * func;
     672};
     673
     674/// \brief create a container for a c2_function which handles the reference counting.
     675/// \ingroup containers
     676///
     677/// \see  c2_const_ptr and \ref memory_management "Use of c2_ptr for memory management"
     678
     679template <typename float_type> class c2_ptr : public c2_const_ptr<float_type >
     680{
     681public:
     682        /// \brief construct the container with no function
     683        c2_ptr() : c2_const_ptr<float_type>()  {}
     684        /// \brief construct the container with a pre-defined function
     685        /// \param f the function to store
     686        c2_ptr(c2_function<float_type> &f) :
     687                c2_const_ptr<float_type>() { set_function(&f); }
     688        /// \brief copy constructor
     689        /// \param src the container to copy
     690        c2_ptr(const c2_ptr<float_type> &src) :
     691                c2_const_ptr<float_type>() { set_function(src.get_ptr()); }
     692        /// \brief get a checked pointer to our owned function
     693        inline c2_function<float_type> &get() const throw(c2_exception)
     694                { return *const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get()); }
     695        /// \brief get an unchecked pointer to our owned function
     696        inline c2_function<float_type> *get_ptr() const
     697                { return const_cast<c2_function<float_type>*>(this->func); }
     698        /// \brief get a checked pointer to our owned function
     699        inline c2_function<float_type> *operator -> () const
     700                { return &get(); }
     701        /// \brief fill the container from another container
     702        /// \param f the container to copy
     703        void operator =(const c2_ptr<float_type> &f)
     704                { set_function(f.get_ptr()); }
     705        /// \brief fill the container with a function
     706        /// \param f the function
     707        void operator =(c2_function<float_type> &f)
     708                { set_function(&f); }
     709private:
     710        /// \brief hidden non-const-safe version of operator=
     711        void operator =(const c2_const_ptr<float_type> &f) { }
     712        /// \brief hidden non-const-safe version of operator=
     713        void operator =(const c2_function<float_type> &f) { }
     714};
     715
     716/// \brief create a non-generic container for a c2_function which handles the reference counting.
     717/// \ingroup containers
     718///
     719/// \see  c2_const_ptr and \ref memory_management "Use of c2_ptr for memory management"
     720///
     721/// \note Overuse of this class will generate massive bloat.  Use c2_ptr and c2_const_ptr if you don't _really_ need specific pointer types.
     722/// \see  \ref memory_management "Use of c2_ptr for memory management"
     723/*
     724template <typename float_type, template <typename> class c2_class > class c2_typed_ptr : public c2_const_ptr<float_type> {
     725public:
     726        /// \brief construct the container with no function
     727        c2_typed_ptr() : c2_ptr<float_type>()  {}
     728        /// \brief construct the container with a pre-defined function
     729        /// \param f the function to store
     730        c2_typed_ptr(c2_class<float_type> &f)
     731                : c2_const_ptr<float_type>() { this->set_function(&f); }
     732        /// \brief copy constructor
     733        /// \param src the container to copy
     734        c2_typed_ptr(const c2_typed_ptr<float_type, c2_class> &src)
     735                : c2_const_ptr<float_type>() { this->set_function(src.get_ptr()); }
     736       
     737        /// \brief get a reference to our owned function
     738        inline c2_class<float_type> &get() const throw(c2_exception)
     739                {
     740                        return *static_cast<c2_class<float_type> *>(const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get()));
     741                }
     742        /// \brief get a checked pointer to our owned function
     743        inline c2_class<float_type> *operator -> () const
     744                { return &get(); }
     745        /// \brief get an unchecked pointer to our owned function
     746        inline c2_class<float_type> *get_ptr() const
     747                { return static_cast<c2_class<float_type> *>(const_cast<c2_function<float_type>*>(this->func)); }
     748        /// \brief type coercion operator which lets us use a pointer as if it were a c2_function
     749        operator c2_class<float_type>&() const { return get(); }
     750        /// \brief fill the container from another container
     751        /// \param f the container to copy
     752        void operator =(const c2_typed_ptr<float_type, c2_class> &f)
     753                { set_function(f.get_ptr()); }
     754        /// \brief fill the container with a function
     755        /// \param f the function
     756        void operator =(c2_class<float_type> &f)
     757                { set_function(&f); }
     758private:
     759        /// \brief hidden downcasting version of operator=
     760        void operator =(const c2_const_ptr<float_type> &f) { }
     761        /// \brief hidden downcasting version of operator=. Use an explicit dynamic_cast<c2_class<float_type>&>(f) if you need to try this.
     762        void operator =(const c2_function<float_type> &f) { }
     763};
     764*/
    328765/// \brief a container into which any other c2_function can be dropped, to allow expressions
    329766/// with replacable components. 
    330 ///
     767/// \ingroup containers
    331768///It is useful for plugging different InterpolatingFunctions into a c2_function expression.
    332769///It saves a lot of effort in other places with casting away const declarations.
     
    334771/// It is also useful as a wrapper for a function if it is necessary to have a copy of a function
    335772/// which has a different domain or sampling grid than the parent function.  This can be
    336 /// be used, for example, to patch badly-behaved functions with c2_piecewise_function by
     773/// be used, for example, to patch badly-behaved functions with c2_piecewise_function_p by
    337774/// taking the parent function, creating two plugins of it with domains on each side of the
    338775/// nasty bit, and then inserting a nice function in the hole.
    339 template <typename float_type=double> class c2_plugin_function : public c2_function<float_type> {
     776///
     777/// This can also be used as a fancier c2_ptr which allows direct evaluation
     778/// instead of having to dereference the container first.
     779///
     780/// The factory function c2_factory::plugin_function() creates *new c2_plugin_function_p()
     781template <typename float_type=double> class c2_plugin_function_p :
     782        public c2_function<float_type> {
    340783public:
    341784        /// \brief construct the container with no function
    342         c2_plugin_function() : c2_function<float_type>(), func(0), owns(false)  {}
     785        c2_plugin_function_p() : c2_function<float_type>(), func()  {}
    343786        /// \brief construct the container with a pre-defined function
    344         c2_plugin_function(const c2_function<float_type> &f) : c2_function<float_type>(), func(0), owns(false) { set_function(f); }
    345         /// \brief fill the container with a new function
    346         void set_function(const c2_function<float_type> &f)
    347                 {
    348                         if(owns && func) delete func;
    349                         func=&f; set_domain(f.xmin(), f.xmax());
    350                         set_sampling_grid_pointer(*f.sampling_grid);
    351                         owns=false;
     787        c2_plugin_function_p(c2_function<float_type> &f) :
     788                c2_function<float_type>(),func(f)  { }
     789        /// \brief fill the container with a new function, or clear it with a null pointer
     790        /// and copy our domain
     791        void set_function(c2_function<float_type> *f)
     792                {
     793                        func.set_function(f);
     794                        if(f) set_domain(f->xmin(), f->xmax());
    352795                }
    353796        /// \copydoc c2_function::value_with_derivatives
     
    355798        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    356799                {
    357                         if(!func) throw c2_exception("c2_plugin_function<float_type> called uninitialized");
    358                         return this->func->value_with_derivatives(x, yprime, yprime2);
     800                        if(!func.valid()) throw c2_exception("c2_plugin_function_p called uninitialized");
     801                        return func->value_with_derivatives(x, yprime, yprime2);
    359802                }
    360         /// \brief clear the function
    361         ///
    362         /// Any attempt to use this c2_plugin_function throws an exception if the saved function is cleared.
    363         void unset_function(void) { if(owns && func) delete func; func=0; owns=false; }
    364803        /// \brief destructor
    365         ~c2_plugin_function() { if(owns && func) delete func; }
    366         /// \brief tell us we should delete the function at destruction.  NOT sticky when function is reset
    367         void set_ownership() { this->owns=true; }
    368        
     804        ~c2_plugin_function_p() { }
     805       
     806        /// \brief clear our function
     807        void unset_function() { func.unset_function(); }
     808       
     809        virtual void get_sampling_grid(float_type xmin, float_type xmax, std::vector<float_type> &grid) const
     810        {       
     811                if(!func.valid()) throw c2_exception("c2_plugin_function_p called uninitialized");
     812                if(this->sampling_grid) c2_function<float_type>::get_sampling_grid(xmin, xmax, grid);
     813                else  func->get_sampling_grid(xmin, xmax, grid);
     814        }
    369815protected:
    370         const c2_function<float_type> *func;
    371         bool owns;
    372        
     816        c2_ptr<float_type> func;
     817};
     818
     819/// \brief a c2_plugin_function_p which promises not to fiddle with the plugged function.
     820/// \ingroup containers
     821///
     822/// The factory function c2_factory::const_plugin_function() creates *new c2_const_plugin_function_p()
     823template <typename float_type=double> class c2_const_plugin_function_p : public c2_plugin_function_p<float_type> {
     824public:
     825        /// \brief construct the container with no function
     826        c2_const_plugin_function_p() : c2_plugin_function_p<float_type>()  {}
     827        /// \brief construct the container with a pre-defined function
     828        c2_const_plugin_function_p(const c2_function<float_type> &f) :
     829                c2_plugin_function_p<float_type>()  { set_function(&f); }
     830        /// \brief fill the container with a new function, or clear it with a null pointer
     831        void set_function(const c2_function<float_type> *f)
     832                { c2_plugin_function_p<float_type>::set_function(const_cast<c2_function<float_type>*>(f)); }
     833        /// \brief destructor
     834        ~c2_const_plugin_function_p() { }
     835       
     836        /// \brief get a const reference to our owned function, for direct access
     837        const c2_function<float_type> &get() const throw(c2_exception)
     838                { return this->func.get(); }
    373839};
    374840
    375841/// \brief Provides support for c2_function objects which are constructed from two other c2_function
    376842/// objects. 
    377 ///
    378 /// It provides a very primitive ownership concept, so that the creator can tag a function
    379 /// as being owned by this function, so that when this function is deleted, the owned function will be deleted, too.
    380 /// This allows a piece of code to create various c2_function objects, combine them with binary operators,
    381 /// appropriately mark wich ones have no other possible owners, and return the final function with
    382 /// reasonable faith that everything will get cleaned up when the final function is deleted.  Note that
    383 /// none of this marking is automatic, to keep this class very lightweight.
     843/// \ingroup abstract_classes
    384844template <typename float_type=double> class c2_binary_function : public c2_function<float_type> {
    385845public:
    386        
    387        
    388846        ///  \brief function to manage the binary operation, used by c2_binary_function::value_with_derivatives()
    389847    ///
    390     /// Normally not used alone, but can be used to combine functions in other contexts.
    391         /// See interpolating_function::binary_operator() for an example.
    392         /// \param left the function on the left of the binary operator or outside the composition
    393         /// \param right the function to the right of the operator or inside the composition
    394     /// \param[in] x the point at which to evaluate the function
    395     /// \param[out] yprime the first derivative (if pointer is non-null)
    396     /// \param[out] yprime2 the second derivative (if pointer is non-null)
    397     /// \return the value of the function
    398         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    399                                            float_type x, float_type *yprime, float_type *yprime2) const =0;
    400848       
    401849        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw (c2_exception)
    402850    {
    403                 return this->combine(this->Left, this->Right, x, yprime, yprime2);
     851                if(stub) throw c2_exception("attempt to evaluate a c2_binary_function stub");
     852                return this->combine(*Left.get_ptr(), *Right.get_ptr(), x, yprime, yprime2);
    404853    }
    405854
    406         /// \brief allow c2_binary_function to remember ownership of contained functions for automatic cleanup
     855        /// \brief destructor releases ownership of member functions
    407856        ///
    408         /// upon destruction, this will cause disposal of the left member function
    409         void set_left_ownership(void) { leftown=true; }
    410         /// \brief allow c2_binary_function to remember ownership of contained functions for automatic cleanup
    411         ///
    412         /// upon destruction, this will cause disposal of the right member function
    413         void set_right_ownership(void) { rightown=true; }
    414         /// \brief allow c2_binary_function to remember ownership of contained functions for automatic cleanup
    415         ///
    416         /// upon destruction, this will cause disposal of both member functions
    417         void set_ownership(void) { leftown=rightown=true; }
    418         /// \brief destructor executes disposal of member functions if flagged
    419         ///
    420         /// depends on judicious use of set_ownership(), set_right_ownership(), or set_left_ownership()
    421         virtual ~c2_binary_function() {
    422                 if(leftown) delete &Left;
    423                 if(rightown) delete &Right;
    424         }
    425                
     857        virtual ~c2_binary_function() { }
     858
    426859protected:
    427860        /// \brief construct the binary function
     861        /// \param combiner pointer to the function which actualy knows how to execute the binary
    428862        /// \param left the c2_function to be used in the left side of the binary relation
    429863        /// \param right the c2_function to be used in the right side of the binary relation
    430         c2_binary_function( const c2_function<float_type> &left,  const c2_function<float_type> &right) :
    431         c2_function<float_type>(),
    432         Left(left), Right(right), leftown(false), rightown(false)
     864        c2_binary_function(
     865                        float_type (*combiner)(const c2_function<float_type> &left, const c2_function<float_type> &right,
     866                                   float_type x, float_type *yprime, float_type *yprime2),                                             
     867                        const c2_function<float_type> &left,  const c2_function<float_type> &right) :
     868                        c2_function<float_type>(), combine(combiner), Left(left), Right(right), stub(false)
    433869        {
    434                         set_domain(
    435                                            (left.xmin() > right.xmin()) ? left.xmin() : right.xmin(),
    436                                            (left.xmax() < right.xmax()) ? left.xmax() : right.xmax()
    437                                            );
     870                set_domain(
     871                                   (left.xmin() > right.xmin()) ? left.xmin() : right.xmin(),
     872                                   (left.xmax() < right.xmax()) ? left.xmax() : right.xmax()
     873                                   );
    438874        }
    439875       
    440876        /// \brief construct a 'stub' c2_binary_function, which provides access to the combine() function
    441877        /// \note Do not evaluate a 'stub' ever.  It is only used so that combine() can be called
    442     c2_binary_function() : c2_function<float_type>(),
    443                 Left(*((c2_function<float_type> *)0)), Right(*((c2_function<float_type> *)0)) {}
    444        
    445         const c2_function<float_type> &Left,  &Right;
    446         bool leftown, rightown;
    447                
     878    c2_binary_function(
     879           float_type (*combiner)(const c2_function<float_type> &left, const c2_function<float_type> &right,
     880                                                          float_type x, float_type *yprime, float_type *yprime2)
     881                ) : c2_function<float_type>(), combine(combiner), Left(), Right(), stub(true) { }
     882       
     883public:
     884        float_type (* const combine)(const c2_function<float_type> &left, const c2_function<float_type> &right,
     885                                                                 float_type x, float_type *yprime, float_type *yprime2);
     886       
     887protected:     
     888        const c2_const_ptr<float_type> Left,  Right;
     889        /// \brief if true, we don't own any functions, we are just a source of a combining function.
     890        bool stub;
     891       
    448892};
    449893
    450894/// \brief Create a very lightweight method to return a scalar multiple of another function.
    451 ///
    452 template <typename float_type=double> class c2_scaled_function : public c2_plugin_function<float_type> {
     895/// \ingroup containers \ingroup arithmetic_functions \ingroup parametric_functions
     896///
     897/// The factory function c2_factory::scaled_function() creates *new c2_scaled_function_p
     898template <typename float_type=double> class c2_scaled_function_p : public c2_function<float_type> {
    453899public:
    454900        /// \brief construct the function with its scale factor.
     
    456902        /// \param outer the function to be scaled
    457903        /// \param scale the multiplicative scale factor
    458         c2_scaled_function(const c2_function<float_type> &outer, float_type scale) :
    459                 c2_plugin_function<float_type>(outer), yscale(scale) { }
     904        c2_scaled_function_p(const c2_function<float_type> &outer, float_type scale) :
     905                c2_function<float_type>(), func(outer), yscale(scale) { }
    460906       
    461907        /// \brief set a new scale factor
     
    475921
    476922protected:
    477     c2_scaled_function<float_type>() {} // hide default constructor, since its use is almost always an error.
     923    c2_scaled_function_p<float_type>() : func() {} // hide default constructor, since its use is almost always an error.
     924        /// \brief the scaling factor for the function
     925        const c2_const_ptr<float_type> func;
    478926        float_type yscale;
    479927};
    480928
    481929/// \brief A container into which any other c2_function can be dropped.
    482 ///
     930/// \ingroup containers
    483931/// It allows a function to be pre-evaluated at a point, and used at multiple places in an expression
    484932/// efficiently. If it is re-evaluated at the previous point, it returns the remembered values;
    485933/// otherwise, it re-evauates the function at the new point.
    486934///
    487 template <typename float_type=double> class c2_cached_function : public c2_plugin_function<float_type> {
     935/// The factory function c2_factory::cached_function() creates *new c2_cached_function_p
     936template <typename float_type=double> class c2_cached_function_p : public c2_function<float_type> {
    488937public:
    489938        /// \brief construct the container
    490939        ///
    491940        /// \param f the function to be cached
    492         c2_cached_function(const c2_function<float_type> &f) : c2_plugin_function<float_type>(f), init(false)  {}
     941        c2_cached_function_p(const c2_function<float_type> &f) : c2_function<float_type>(),
     942                func(f), init(false)  {}
    493943        /// \copydoc c2_function::value_with_derivatives
    494944        ///
     
    508958
    509959protected:
    510     c2_cached_function() {} // hide default constructor, since its use is almost always an error.
     960    c2_cached_function_p() : func() {} // hide default constructor, since its use is almost always an error.
     961        const c2_const_ptr<float_type> func;
    511962        mutable bool init;
    512963        mutable float_type x0, y, yp, ypp;
     
    515966
    516967/// \brief Provides function composition (nesting)
    517 ///
     968/// \ingroup arithmetic_functions
    518969/// This allows evaluation of \a f(g(x)) where \a f and \a g are c2_function objects.
    519970///
    520 /// \note See c2_binary_function for discussion of ownership.
    521 template <typename float_type=double> class  c2_composed_function : public c2_binary_function<float_type> {
     971/// This should always be constructed using \ref compose_operator "c2_function::operator()"
     972template <typename float_type=double> class  c2_composed_function_p : public c2_binary_function<float_type> {
    522973public:
    523974       
     
    526977        /// \param outer the outer function
    527978        /// \param inner the inner function
    528         c2_composed_function(const c2_function<float_type> &outer, const c2_function<float_type> &inner) : c2_binary_function<float_type>(outer, inner) {}
     979        c2_composed_function_p(const c2_function<float_type> &outer, const c2_function<float_type> &inner) :
     980                c2_binary_function<float_type>(combine, outer, inner) { this->set_domain(inner.xmin(), inner.xmax()); }
    529981        /// \brief Create a stub just for the combiner to avoid statics.
    530         c2_composed_function() : c2_binary_function<float_type>() {} ;
    531 
    532         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    533                                                   float_type x, float_type *yprime, float_type *yprime2) const
     982        c2_composed_function_p() : c2_binary_function<float_type>(combine) {}
     983
     984        /// \brief execute math necessary to do composition
     985        static float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
     986                                                  float_type x, float_type *yprime, float_type *yprime2) throw(c2_exception)
    534987    {
    535                 float_type y0, yp0, ypp0, y1, yp1, ypp1;
    536                 float_type *yp0p, *ypp0p, *yp1p, *ypp1p;
     988                float_type y0, y1;
    537989                if(yprime || yprime2) {
    538                         yp0p=&yp0; ypp0p=&ypp0; yp1p=&yp1; ypp1p=&ypp1;
     990                        float_type yp0, ypp0, yp1, ypp1;
     991                        y0=right.value_with_derivatives(x, &yp0, &ypp0);
     992                        y1=left.value_with_derivatives(y0, &yp1, &ypp1);
     993                        if(yprime) *yprime=yp1*yp0;
     994                        if(yprime2) *yprime2=ypp0*yp1+yp0*yp0*ypp1;
    539995                } else {
    540                         yp0p=ypp0p=yp1p=ypp1p=0;
     996                        y0=right(x);
     997                        y1=left(y0);
    541998                }
    542                
    543                 y0=right.value_with_derivatives(x, yp0p, ypp0p);
    544                 y1=left.value_with_derivatives(y0, yp1p, ypp1p);
    545                 if(yprime) *yprime=yp1*yp0;
    546                 if(yprime2) *yprime2=ypp0*yp1+yp0*yp0*ypp1;
    547999                return y1;
    5481000        }       
     
    5501002
    5511003/// \brief create a c2_function which is the sum of two other c2_function objects.
    552 ///
    553 /// \note See c2_binary_function for discussion of ownership.
    554 template <typename float_type=double> class c2_sum : public c2_binary_function<float_type> {
     1004/// \ingroup arithmetic_functions
     1005/// This should always be constructed using c2_function::operator+()
     1006template <typename float_type=double> class c2_sum_p : public c2_binary_function<float_type> {
    5551007public:
    5561008        /// \brief construct \a left + \a right
    557     /// \note See c2_binary_function for discussion of ownership.
     1009        /// \param left the left function
     1010        /// \param right the right function
     1011        c2_sum_p(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(combine, left, right) {}
     1012        /// \brief Create a stub just for the combiner to avoid statics.
     1013        c2_sum_p() : c2_binary_function<float_type>(combine) {} ; // create a stub just for the combiner to avoid statics
     1014
     1015        /// \brief execute math necessary to do addition
     1016        static float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
     1017                                                  float_type x, float_type *yprime, float_type *yprime2) throw(c2_exception)
     1018    {
     1019                float_type y0, y1;
     1020                if(yprime || yprime2) {
     1021                        float_type yp0, ypp0, yp1, ypp1;
     1022                        y0=left.value_with_derivatives(x, &yp0, &ypp0);
     1023                        y1=right.value_with_derivatives(x, &yp1, &ypp1);
     1024                        if(yprime) *yprime=yp0+yp1;
     1025                        if(yprime2) *yprime2=ypp0+ypp1;
     1026                } else {
     1027                        y0=left(x);
     1028                        y1=right(x);
     1029                }
     1030                return y0+y1;
     1031        }
     1032};
     1033
     1034
     1035/// \brief create a c2_function which is the difference of two other c2_functions.
     1036/// \ingroup arithmetic_functions
     1037/// This should always be constructed using c2_function::operator-()
     1038template <typename float_type=double> class c2_diff_p : public c2_binary_function<float_type> {
     1039public:
     1040        /// \brief construct \a left - \a right
    5581041        /// \param left the left function
    5591042        /// \param right the right function
    560         c2_sum(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(left, right) {}
     1043        c2_diff_p(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(combine, left, right) {}
    5611044        /// \brief Create a stub just for the combiner to avoid statics.
    562         c2_sum() : c2_binary_function<float_type>() {} ; // create a stub just for the combiner to avoid statics
    563 
    564         // function to do derivative arithmetic for sums
    565         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    566                                                   float_type x, float_type *yprime, float_type *yprime2) const
     1045        c2_diff_p() : c2_binary_function<float_type>(combine) {} ; // create a stub just for the combiner to avoid statics
     1046
     1047        /// \brief execute math necessary to do subtraction
     1048        static float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
     1049                                                          float_type x, float_type *yprime, float_type *yprime2) throw(c2_exception)
    5671050    {
    568                 float_type y0, yp0, ypp0, y1, yp1, ypp1;
    569                 float_type *yp0p, *ypp0p, *yp1p, *ypp1p;
     1051                float_type y0, y1;
    5701052                if(yprime || yprime2) {
    571                         yp0p=&yp0; ypp0p=& ypp0; yp1p=&yp1; ypp1p=&ypp1;
     1053                        float_type yp0, ypp0, yp1, ypp1;
     1054                        y0=left.value_with_derivatives(x, &yp0, &ypp0);
     1055                        y1=right.value_with_derivatives(x, &yp1, &ypp1);
     1056                        if(yprime) *yprime=yp0-yp1;
     1057                        if(yprime2) *yprime2=ypp0-ypp1;
    5721058                } else {
    573                         yp0p=ypp0p=yp1p=ypp1p=0;
     1059                        y0=left(x);
     1060                        y1=right(x);
    5741061                }
    575                 y0=left.value_with_derivatives(x, yp0p, ypp0p);
    576                 y1=right.value_with_derivatives(x, yp1p, ypp1p);
    577                 if(yprime) *yprime=yp0+yp1;
    578                 if(yprime2) *yprime2=ypp0+ypp1;
    579                 return y0+y1;
     1062                return y0-y1;
    5801063        }
    5811064};
    5821065
    5831066
    584 /// \brief create a c2_function which is the difference of two other c2_functions.
    585 ///
    586 /// \note See c2_binary_function for discussion of ownership.
    587 template <typename float_type=double> class c2_diff : public c2_binary_function<float_type> {
     1067/// \brief create a c2_function which is the product of two other c2_functions.
     1068/// \ingroup arithmetic_functions
     1069/// This should always be constructed using c2_function::operator*()
     1070template <typename float_type=double> class c2_product_p : public c2_binary_function<float_type> {
    5881071public:
    589         /// \brief construct \a left - \a right
    590     /// \note See c2_binary_function for discussion of ownership.
     1072        /// \brief construct \a left * \a right
    5911073        /// \param left the left function
    5921074        /// \param right the right function
    593         c2_diff(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(left, right) {}
     1075        c2_product_p(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(combine, left, right) {}
    5941076        /// \brief Create a stub just for the combiner to avoid statics.
    595         c2_diff() : c2_binary_function<float_type>() {} ; // create a stub just for the combiner to avoid statics
    596 
    597         // function to do derivative arithmetic for diffs
    598         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    599                                                           float_type x, float_type *yprime, float_type *yprime2) const
     1077        c2_product_p() : c2_binary_function<float_type>(combine) {} ; // create a stub just for the combiner to avoid statics
     1078
     1079        /// \brief execute math necessary to do multiplication
     1080        static float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
     1081                                                           float_type x, float_type *yprime, float_type *yprime2)  throw(c2_exception)
    6001082    {
    601                 float_type y0, yp0, ypp0, y1, yp1, ypp1;
    602                 float_type *yp0p, *ypp0p, *yp1p, *ypp1p;
     1083                float_type y0, y1;
    6031084                if(yprime || yprime2) {
    604                         yp0p=&yp0; ypp0p=&ypp0; yp1p=&yp1; ypp1p=&ypp1;
     1085                        float_type yp0, ypp0, yp1, ypp1;
     1086                        y0=left.value_with_derivatives(x, &yp0, &ypp0);
     1087                        y1=right.value_with_derivatives(x, &yp1, &ypp1);
     1088                        if(yprime) *yprime=y1*yp0+y0*yp1;
     1089                        if(yprime2) *yprime2=ypp0*y1+2.0*yp0*yp1+ypp1*y0;
    6051090                } else {
    606                         yp0p=ypp0p=yp1p=ypp1p=0;
     1091                        y0=left(x);
     1092                        y1=right(x);
    6071093                }
    608                 y0=left.value_with_derivatives(x, yp0p, ypp0p);
    609                 y1=right.value_with_derivatives(x, yp1p, ypp1p);
    610                 if(yprime) *yprime=yp0-yp1;
    611                 if(yprime2) *yprime2=ypp0-ypp1;
    612                 return y0-y1;
     1094                return y0*y1;
    6131095        }
    6141096};
    6151097
    6161098
    617 /// \brief create a c2_function which is the product of two other c2_functions.
    618 ///
    619 /// \note See c2_binary_function for discussion of ownership.
    620 template <typename float_type=double> class c2_product : public c2_binary_function<float_type> {
     1099/// \brief create a c2_function which is the ratio of two other c2_functions.
     1100/// \ingroup arithmetic_functions
     1101/// This should always be constructed using c2_function::operator/()
     1102template <typename float_type=double> class c2_ratio_p : public c2_binary_function<float_type> {
    6211103public:
    622         /// \brief construct \a left * \a right
    623     /// \note See c2_binary_function for discussion of ownership.
     1104        /// \brief construct \a left / \a right
    6241105        /// \param left the left function
    6251106        /// \param right the right function
    626         c2_product(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(left, right) {}
     1107        c2_ratio_p(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(combine, left, right) {}
    6271108        /// \brief Create a stub just for the combiner to avoid statics.
    628         c2_product() : c2_binary_function<float_type>() {} ; // create a stub just for the combiner to avoid statics
    629 
    630         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    631                                                            float_type x, float_type *yprime, float_type *yprime2) const
     1109        c2_ratio_p() : c2_binary_function<float_type>(combine) {} ; // create a stub just for the combiner to avoid statics
     1110       
     1111        /// \brief execute math necessary to do division
     1112        static float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
     1113                                                          float_type x, float_type *yprime, float_type *yprime2) throw(c2_exception)
    6321114    {
    633                 float_type y0, yp0, ypp0, y1, yp1, ypp1;
    634                 float_type *yp0p, *ypp0p, *yp1p, *ypp1p;
     1115                float_type y0, y1;
    6351116                if(yprime || yprime2) {
    636                         yp0p=&yp0; ypp0p=&ypp0; yp1p=&yp1; ypp1p=&ypp1;
     1117                        float_type yp0, ypp0, yp1, ypp1;
     1118                        y0=left.value_with_derivatives(x, &yp0, &ypp0);
     1119                        y1=right.value_with_derivatives(x, &yp1, &ypp1);
     1120                        if(yprime) *yprime=(yp0*y1-y0*yp1)/(y1*y1); // first deriv of ratio
     1121                        if(yprime2) *yprime2=(y1*y1*ypp0+y0*(2*yp1*yp1-y1*ypp1)-2*y1*yp0*yp1)/(y1*y1*y1);
    6371122                } else {
    638                         yp0p=ypp0p=yp1p=ypp1p=0;
     1123                        y0=left(x);
     1124                        y1=right(x);
    6391125                }
    640                 y0=left.value_with_derivatives(x, yp0p, ypp0p);
    641                 y1=right.value_with_derivatives(x, yp1p, ypp1p);
    642                 if(yprime) *yprime=y1*yp0+y0*yp1;
    643                 if(yprime2) *yprime2=ypp0*y1+2.0*yp0*yp1+ypp1*y0;
    644                 return y0*y1;
    645         }
    646 };
    647 
    648 
    649 /// \brief create a c2_function which is the ratio of two other c2_functions.
    650 ///
    651 /// \note See c2_binary_function for discussion of ownership.
    652 template <typename float_type=double> class c2_ratio : public c2_binary_function<float_type> {
    653 public:
    654         /// \brief construct \a left / \a right
    655     /// \note See c2_binary_function for discussion of ownership.
    656         /// \param left the left function
    657         /// \param right the right function
    658         c2_ratio(const c2_function<float_type> &left, const c2_function<float_type> &right) : c2_binary_function<float_type>(left, right) {}
    659         /// \brief Create a stub just for the combiner to avoid statics.
    660         c2_ratio() : c2_binary_function<float_type>() {} ; // create a stub just for the combiner to avoid statics
    661        
    662         virtual float_type combine(const c2_function<float_type> &left, const c2_function<float_type> &right,
    663                                                           float_type x, float_type *yprime, float_type *yprime2) const
    664     {
    665                 float_type y0, yp0, ypp0, y1, yp1, ypp1;
    666                 float_type *yp0p, *ypp0p, *yp1p, *ypp1p;
    667                 if(yprime || yprime2) {
    668                         yp0p=&yp0; ypp0p=&ypp0; yp1p=&yp1; ypp1p=&ypp1;
    669                 } else {
    670                         yp0p=ypp0p=yp1p=ypp1p=0;
    671                 }
    672                 y0=left.value_with_derivatives(x, yp0p, ypp0p);
    673                 y1=right.value_with_derivatives(x, yp1p, ypp1p);
    674                 if(yprime) *yprime=(yp0*y1-y0*yp1)/(y1*y1); // first deriv of ratio
    675                 if(yprime2) *yprime2=(y1*y1*ypp0+y0*(2*yp1*yp1-y1*ypp1)-2*y1*yp0*yp1)/(y1*y1*y1); // second deriv of ratio
    6761126                return y0/y1;
    6771127        }
     
    6791129};
    6801130
    681 /// \brief a c2_function which is constant : can do interpolating_function  f2=f1 + c2_constant(11.3)
    682 template <typename float_type> class c2_constant : public c2_function<float_type> {
    683 public:
    684         c2_constant(float_type x=0.0) : c2_function<float_type>(), value(x) {}
     1131/// \brief a c2_function which is constant
     1132/// \ingroup parametric_functions
     1133///
     1134/// The factory function c2_factory::constant() creates *new c2_constant_p()
     1135template <typename float_type> class c2_constant_p : public c2_function<float_type> {
     1136public:
     1137        c2_constant_p(float_type x) : c2_function<float_type>(), value(x) {}
    6851138        void reset(float_type val) { value=val; }
    6861139        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     
    6911144};
    6921145
     1146/// \brief a transformation of a coordinate, including an inverse
     1147/// \ingroup transforms
     1148template <typename float_type> class c2_transformation {
     1149public:
     1150        /// \brief initialize all our function pointers
     1151        /// \param transformed true if this function is not the identity
     1152        /// \param xin input X transform
     1153        /// \param xinp input X transform derivative
     1154        /// \param xinpp input X transform second derivative
     1155        /// \param xout output X transform, which MUST be the inverse of \a xin
     1156        c2_transformation(bool transformed,
     1157                   float_type (*xin)(float_type), float_type (*xinp)(float_type), float_type (*xinpp)(float_type), float_type (*xout)(float_type)
     1158           ) :
     1159                        fTransformed(transformed), fHasStaticTransforms(true),
     1160                        pIn(xin), pInPrime(xinp), pInDPrime(xinpp), pOut(xout) { }
     1161
     1162        /// \brief initialize all our function pointers so that only the (overridden) virtual functions can be called without an error
     1163        /// \param transformed true if this function is nonlinear
     1164        c2_transformation(bool transformed) :
     1165                        fTransformed(transformed), fHasStaticTransforms(false),
     1166                        pIn(report_error), pInPrime(report_error), pInDPrime(report_error), pOut(report_error) { }
     1167        /// \brief the destructor
     1168        virtual ~c2_transformation() { }
     1169        /// \brief flag to indicate if this transform is not the identity
     1170        const bool fTransformed;
     1171        /// \brief flag to indicate if the static function pointers can be used for efficiency
     1172        const bool fHasStaticTransforms;
     1173
     1174        /// \note the pointers to functions allow highly optimized access when static functions are available.
     1175        /// They are only used inside value_with_derivatives(), which is assumed to be the most critical routine.
     1176        /// \brief non-virtual pointer to input X transform
     1177        float_type (* const pIn)(float_type);
     1178        /// \brief non-virtual pointer to input X transform derivative
     1179        float_type (* const pInPrime)(float_type);
     1180        /// \brief non-virtual pointer to input X transform second derivative
     1181        float_type (* const pInDPrime)(float_type);
     1182        /// \brief non-virtual pointer to output X transform
     1183        float_type (* const pOut)(float_type);
     1184       
     1185        /// \brief virtual input X transform
     1186        virtual float_type fIn(float_type x) const { return pIn(x); }
     1187        /// \brief virtual input X transform derivative
     1188        virtual float_type fInPrime(float_type x) const { return pInPrime(x); }
     1189        /// \brief virtual input X transform second derivative
     1190        virtual float_type fInDPrime(float_type x) const { return pInDPrime(x); }
     1191        /// \brief virtual output X transform
     1192        virtual float_type fOut(float_type x) const { return pOut(x); }
     1193
     1194protected:
     1195        /// \brief utility function for unimplemented conversion
     1196        static float_type report_error(float_type x)  { throw c2_exception("use of improperly constructed axis transform"); return x; }
     1197        /// \brief utility function f(x)=x useful in axis transforms
     1198        static float_type ident(float_type x)  { return x; }
     1199        /// \brief utility function f(x)=1 useful in axis transforms
     1200        static float_type one(float_type)  { return 1; }
     1201        /// \brief utility function f(x)=0 useful in axis transforms
     1202        static float_type zero(float_type)  { return 0; }
     1203        /// \brief utility function f(x)=1/x useful in axis transforms
     1204        static float_type recip(float_type x)  { return 1.0/x; }
     1205        /// \brief utility function f(x)=-1/x**2 useful in axis transforms
     1206        static float_type recip_prime(float_type x)  { return -1/(x*x); }
     1207        /// \brief utility function f(x)=2/x**3 useful in axis transforms
     1208        static float_type recip_prime2(float_type x)  { return 2/(x*x*x); }
     1209
     1210};
     1211
     1212/// \brief the identity transform
     1213/// \ingroup transforms
     1214template <typename float_type> class c2_transformation_linear : public c2_transformation<float_type> {
     1215public:
     1216        /// \brief constructor
     1217        c2_transformation_linear() : c2_transformation<float_type>(false, this->ident, this->one, this->zero, this->ident) { }
     1218        /// \brief destructor
     1219        ~c2_transformation_linear() { }
     1220};
     1221/// \brief log axis transform
     1222/// \ingroup transforms
     1223template <typename float_type> class c2_transformation_log : public c2_transformation<float_type> {
     1224public:
     1225        /// \brief constructor
     1226        c2_transformation_log() : c2_transformation<float_type>(true, std::log, this->recip, this->recip_prime, std::exp) { }
     1227        /// \brief destructor
     1228        ~c2_transformation_log() { }
     1229};
     1230/// \brief reciprocal axis transform
     1231/// \ingroup transforms
     1232template <typename float_type> class c2_transformation_recip : public c2_transformation<float_type> {
     1233public:
     1234        /// \brief constructor
     1235        c2_transformation_recip() : c2_transformation<float_type>(true, this->recip, this->recip_prime, this->recip_prime2, this->recip) { }
     1236        /// \brief destructor
     1237        ~c2_transformation_recip() { }
     1238};
     1239
     1240/// \brief a transformation of a function in and out of a coordinate space, using 2 c2_transformations
     1241///
     1242/// This class is a container for two axis transforms, but also provides the critical evaluate()
     1243/// function which converts a result in internal coordinates (with derivatives) into the external representation
     1244/// \ingroup transforms
     1245template <typename float_type>
     1246        class c2_function_transformation {
     1247public:
     1248        /// \brief construct this from two c2_transformation instances
     1249        /// \param xx the X axis transform
     1250        /// \param yy the Y axis transform 
     1251        c2_function_transformation(
     1252                const c2_transformation<float_type> &xx, const c2_transformation<float_type> &yy) :
     1253                isIdentity(!(xx.fTransformed || yy.fTransformed)), X(xx), Y(yy) { }
     1254        /// \brief destructor
     1255        virtual ~c2_function_transformation() { delete &X; delete &Y; }
     1256        /// \brief evaluate the transformation from internal coordinates to external coordinates
     1257        /// \param xraw the value of \a x in external cordinates at which the transform is taking place
     1258        /// \param y the value of the function in internal coordinates
     1259        /// \param yp0 the derivative in internal coordinates
     1260        /// \param ypp0 the second derivative in internal coordinates
     1261        /// \param [out] yprime pointer to the derivative, or NULL, in external coordinates
     1262        /// \param [out] yprime2 pointer to the second derivative, or NULL, in external coordinates
     1263        /// \return the value of the function in external coordinates
     1264        virtual float_type evaluate(float_type xraw,
     1265                float_type y, float_type yp0, float_type ypp0,
     1266                float_type *yprime, float_type *yprime2) const;
     1267        /// \brief flag indicating of the transform is the identity, and can be skipped for efficiency
     1268        const bool isIdentity;
     1269        /// \brief the X axis transform
     1270        const c2_transformation<float_type> &X;
     1271        /// \brief the Y axis transform
     1272        const c2_transformation<float_type> &Y;
     1273};
     1274
     1275/// \brief a transformation of a function in and out of lin-lin space
     1276///
     1277/// \ingroup transforms
     1278template <typename float_type> class c2_lin_lin_function_transformation :
     1279        public c2_function_transformation<float_type> {
     1280public:
     1281        c2_lin_lin_function_transformation() :
     1282                c2_function_transformation<float_type>(
     1283                        *new c2_transformation_linear<float_type>,
     1284                        *new c2_transformation_linear<float_type>
     1285                ) { }
     1286        virtual ~c2_lin_lin_function_transformation() { }
     1287};
     1288
     1289/// \brief a transformation of a function in and out of log-log space
     1290///
     1291/// \ingroup transforms
     1292template <typename float_type> class c2_log_log_function_transformation :
     1293        public c2_function_transformation<float_type> {
     1294public:
     1295        c2_log_log_function_transformation() :
     1296                c2_function_transformation<float_type>(
     1297                        *new c2_transformation_log<float_type>,
     1298                        *new c2_transformation_log<float_type>
     1299                ) { }
     1300        virtual ~c2_log_log_function_transformation() { }
     1301};
     1302
     1303/// \brief a transformation of a function in and out of lin-log space
     1304///
     1305/// \ingroup transforms
     1306template <typename float_type> class c2_lin_log_function_transformation :
     1307        public c2_function_transformation<float_type> {
     1308public:
     1309        c2_lin_log_function_transformation() :
     1310                c2_function_transformation<float_type>(
     1311                        *new c2_transformation_linear<float_type>,
     1312                        *new c2_transformation_log<float_type>
     1313                ) { }
     1314        virtual ~c2_lin_log_function_transformation() { }
     1315};
     1316
     1317/// \brief a transformation of a function in and out of log-lin space
     1318///
     1319/// \ingroup transforms
     1320template <typename float_type> class c2_log_lin_function_transformation :
     1321        public c2_function_transformation<float_type> {
     1322public:
     1323        c2_log_lin_function_transformation() :
     1324                c2_function_transformation<float_type>(
     1325                        *new c2_transformation_log<float_type>,
     1326                        *new c2_transformation_linear<float_type>
     1327                ) { }
     1328        virtual ~c2_log_lin_function_transformation() { }
     1329};
     1330
     1331/// \brief a transformation of a function in and out of Arrhenuis (1/x vs. log(y)) space
     1332///
     1333/// \ingroup transforms
     1334template <typename float_type> class c2_arrhenius_function_transformation :
     1335        public c2_function_transformation<float_type> {
     1336public:
     1337        c2_arrhenius_function_transformation() :
     1338                c2_function_transformation<float_type>(
     1339                        *new c2_transformation_recip<float_type>,
     1340                        *new c2_transformation_log<float_type>
     1341                ) { }
     1342        virtual ~c2_arrhenius_function_transformation() { }
     1343};
     1344
    6931345/**
    6941346    \brief create a cubic spline interpolation of a set of (x,y) pairs
    695 
     1347        \ingroup interpolators
    6961348    This is one of the main reasons for c2_function objects to exist.
    6971349
     
    7071359    (vanishing second derivative), is created as: \n
    7081360    \code
     1361        c2_ptr<double> c2p;
     1362        c2_factory<double> c2;
    7091363    std::vector<double> xvals(10), yvals(10);
    7101364    // < fill in xvals and yvals >
    711     interpolating_function<double>  myfunc(xvals, yvals);
     1365    c2p myfunc=c2.interpolating_function().load(xvals, yvals,true,0,true,0);
    7121366    // and it can be evaluated at a point for its value only by:
    7131367    double y=myfunc(x);
     
    7161370    double y=myfunc(x,&yprime, &yprime2);
    7171371    \endcode
     1372       
     1373        The factory function c2_factory::interpolating_function() creates *new interpolating_function_p()
    7181374*/
    7191375
    720 template <typename float_type=double> class interpolating_function  : public c2_function<float_type> {
    721 public:
    722     /// \brief create the most general interpolating_function which defaults to linear-linear space
     1376template <typename float_type=double> class interpolating_function_p  : public c2_function<float_type> {
     1377public:
     1378    /// \brief an empty linear-linear cubic-spline interpolating_function_p
    7231379    ///
    7241380    /// lots to say here, but see Numerical Recipes for a discussion of cubic splines.
     1381        ///
     1382        interpolating_function_p() : c2_function<float_type>(),
     1383                fTransform(*new  c2_lin_lin_function_transformation<float_type>) { }
     1384
     1385    /// \brief an empty cubic-spline interpolating_function_p with a specific transform
     1386    ///
     1387        interpolating_function_p(const c2_function_transformation<float_type> &transform) : c2_function<float_type>(),
     1388                fTransform(transform) { }
     1389
     1390    /// \brief do the dirty work of constructing the spline from a function.
    7251391    /// \param x the list of abscissas.  Must be either strictly increasing or strictly decreasing.
    7261392        /// Strictly increasing is preferred, as less memory is used since a copy is not required for the sampling grid.
     
    7301396    /// \param upperSlopeNatural if true, set y''(last point)=0, otherwise compute it from \a upperSope
    7311397    /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
    732     /// \param inputXConversion a function (not a c2_function) which converts \a x into the internal space. \n
    733         /// If this is NULL, use linear space and ignore inputXConversionPrime, inputXConversionDPrime
    734     /// \param inputYConversion a function (not a c2_function) which converts \a y into the internal space. \n
    735         /// If this is NULL, use linear space and ignore inputYConversionPrime, inputYConversionDPrime, outputYConversion
    736     /// \param outputYConversion a function (not a c2_function) which converts \a y out of the internal space
    737     /// \param inputXConversionPrime the derivative of \a inputXConversion
    738     /// \param inputYConversionPrime the derivative of \a inputYConversion
    739     /// \param inputXConversionDPrime the second derivative of \a inputXConversion
    740     /// \param inputYConversionDPrime the second derivative of \a inputYConversion
    741     interpolating_function(const std::vector<float_type> &x, const std::vector<float_type> &f,
    742                                                   bool lowerSlopeNatural=true, float_type lowerSlope=0.0,
    743                                                   bool upperSlopeNatural=true, float_type upperSlope=0.0,
    744                                                   float_type (*inputXConversion)(float_type)=0,
    745                                                   float_type (*inputYConversion)(float_type)=0,
    746                                                   float_type (*outputYConversion)(float_type)=0,
    747                                                   float_type (*inputXConversionPrime)(float_type)=0,
    748                                                   float_type (*inputYConversionPrime)(float_type)=0,
    749                                                   float_type (*inputXConversionDPrime)(float_type)=0,
    750                                                   float_type (*inputYConversionDPrime)(float_type)=0
    751                                                    ) throw(c2_exception) : c2_function<float_type>()
    752         { init(x, f, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope,
    753                inputXConversion, inputYConversion, outputYConversion,
    754                inputXConversionPrime, inputYConversionPrime,
    755                inputXConversionDPrime, inputYConversionDPrime
    756                );
    757         }
    758        
    759     /// \brief copy constructor
    760     /// \param rhs interpolating_function  to copy from
    761         interpolating_function(const interpolating_function <float_type> &rhs) : c2_function<float_type>(rhs),
    762                 Xraw(rhs.Xraw), X(rhs.X), F(rhs.F), y2(rhs.y2),
    763                 fXin(rhs.fXin), fYin(rhs.fYin), fYout(rhs.fYout),
    764                 fXinPrime(rhs.fXinPrime), fYinPrime(rhs.fYinPrime),
    765                 fXinDPrime(rhs.fXinDPrime), fYinDPrime(rhs.fYinDPrime) ,
    766                 xInverted(rhs.xInverted), lastKLow(-1)
    767         {       set_sampling_grid_pointer(Xraw); }
    768        
    769         virtual ~interpolating_function() { } // just to suppress warnings about no virtual destructor
     1398        /// \param splined if true (default), use cubic spline, if false, use linear interpolation.
     1399        /// \return the same interpolating function, filled
     1400        interpolating_function_p<float_type> & load(const std::vector<float_type> &x, const std::vector<float_type> &f,
     1401                          bool lowerSlopeNatural, float_type lowerSlope,
     1402                          bool upperSlopeNatural, float_type upperSlope, bool splined=true
     1403        ) throw(c2_exception);
     1404
     1405    /// \brief do the dirty work of constructing the spline from a function.
     1406    /// \param data std::vector of std::pairs of x,y.  Will be sorted into x increasing order in place.
     1407    /// \param lowerSlopeNatural if true, set y''(first point)=0, otherwise compute it from \a lowerSope
     1408    /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
     1409    /// \param upperSlopeNatural if true, set y''(last point)=0, otherwise compute it from \a upperSope
     1410    /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
     1411        /// \param splined if true (default), use cubic spline, if false, use linear interpolation.
     1412        /// \return the same interpolating function, filled
     1413        interpolating_function_p<float_type> & load_pairs(
     1414                          std::vector<std::pair<float_type, float_type> > &data, 
     1415                          bool lowerSlopeNatural, float_type lowerSlope,
     1416                          bool upperSlopeNatural, float_type upperSlope, bool splined=true
     1417        ) throw(c2_exception);
     1418
     1419    /// \brief do the dirty work of constructing the spline from a function.
     1420    /// \param func a function without any requirement of valid derivatives to sample into an interpolating function.
     1421        /// Very probably a c2_classic_function.
     1422    /// \param xmin the lower bound of the region to sample
     1423    /// \param xmax the upper bound of the region to sample
     1424        /// \param abs_tol the maximum absolute error permitted when linearly interpolating the points.
     1425        /// the real error will be much smaller, since this uses cubic splines at the end.
     1426        /// \param rel_tol the maximum relative error permitted when linearly interpolating the points.
     1427        /// the real error will be much smaller, since this uses cubic splines at the end.
     1428    /// \param lowerSlopeNatural if true, set y'(first point) from 3-point parabola, otherwise compute it from \a lowerSope
     1429    /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
     1430    /// \param upperSlopeNatural if true, set y'(last point) from 3-point parabola, otherwise compute it from \a upperSope
     1431    /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
     1432        /// \return the same interpolating function, filled
     1433        /// \note If the interpolator being filled has a log vertical axis, put the desired relative error in
     1434        /// \a abs_tol, and 0 in \a rel_tol since the absolute error on the log of a function is the relative error
     1435        /// on the function itself.
     1436        interpolating_function_p<float_type> &  sample_function(const c2_function<float_type> &func,
     1437                          float_type xmin, float_type xmax, float_type abs_tol, float_type rel_tol,
     1438                          bool lowerSlopeNatural, float_type lowerSlope,
     1439                          bool upperSlopeNatural, float_type upperSlope
     1440                          ) throw(c2_exception);
     1441       
     1442
     1443        /// \brief initialize from a grid of points and a c2_function (un-normalized) to an
     1444        /// interpolator which, when evaluated with a uniform random variate on [0,1] returns random numbers
     1445        /// distributed as the input function.
     1446        /// \see  \ref random_subsec "Arbitrary random generation"
     1447        /// inverse_integrated_density starts with a probability density  std::vector, generates the integral,
     1448        /// and generates an interpolating_function_p  of the inverse function which, when evaluated using a uniform random on [0,1] returns values
     1449        /// with a density distribution equal to the input distribution
     1450        /// If the data are passed in reverse order (large X first), the integral is carried out from the big end.
     1451        /// \param bincenters the positions at which to sample the function \a binheights
     1452        /// \param binheights a function which describes the density of the random number distribution to be produced.
     1453        /// \return an initialized interpolator, which
     1454        /// if evaluated randomly with a uniform variate on [0,1] produces numbers
     1455        /// distributed according to \a binheights
     1456        interpolating_function_p<float_type> & load_random_generator_function(
     1457                const std::vector<float_type> &bincenters, const c2_function<float_type> &binheights)
     1458                throw(c2_exception);
     1459
     1460        /// \brief initialize from a grid of points and an std::vector of probability densities (un-normalized) to an
     1461        /// interpolator which, when evaluated with a uniform random variate on [0,1] returns random numbers
     1462        /// distributed as the input histogram.
     1463        /// \see  \ref random_subsec "Arbitrary random generation"
     1464        /// inverse_integrated_density starts with a probability density  std::vector, generates the integral,
     1465        /// and generates an interpolating_function_p  of the inverse function which, when evaluated using a uniform random on [0,1] returns values
     1466        /// with a density distribution equal to the input distribution
     1467        /// If the data are passed in reverse order (large X first), the integral is carried out from the big end.
     1468        /// \param bins if \a bins .size()==\a binheights .size(), the centers of the bins.  \n
     1469        /// if \a bins .size()==\a binheights .size()+1, the edges of the bins
     1470        /// \param binheights a vector which describes the density of the random number distribution to be produced.
     1471        /// Note density... the numbers in the bins are not counts, but counts/unit bin width.
     1472        /// \return an initialized interpolator, which
     1473        /// if evaluated randomly with a uniform variate on [0,1] produces numbers
     1474        /// distributed according to \a binheights
     1475        interpolating_function_p<float_type> & load_random_generator_bins(
     1476                const std::vector<float_type> &bins, const std::vector<float_type> &binheights)
     1477                throw(c2_exception);
     1478       
     1479        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception);
     1480       
     1481        /// \brief destructor
     1482        virtual ~interpolating_function_p() { delete &fTransform; }
     1483       
     1484        /// \brief create a new, empty interpolating function of this type (virtual constructor)
     1485        virtual interpolating_function_p<float_type> &clone() const throw(c2_exception)
     1486        {       return *new interpolating_function_p<float_type>(); }
    7701487       
    7711488    /// \brief retrieve copies of the x & y tables from which this was built
    7721489    ///
    7731490        /// This is often useful in the creation of new interpolating functions with transformed data.
    774         /// The vectorswill have their sizes set correctly on return.
     1491        /// The vectors will have their sizes set correctly on return.
    7751492        /// \param [in, out] xvals the abscissas
    7761493        /// \param [in, out] yvals the ordinates
     
    7931510        // preserving the X bounds and mapping functions of the host (left hand) function.
    7941511       
    795     /// \brief create a new interpolating_function  which is the \a source
     1512    /// \brief create a new interpolating_function_p  which is the \a source
    7961513    /// function applied to every point in the interpolating tables
    7971514    ///
    7981515    /// This carefully manages the derivative of the composed function at the two ends.
    7991516    /// \param source the function to apply
    800     /// \return a new interpolating_function  with the same mappings for x and y
    801         interpolating_function <float_type> & unary_operator(const c2_function<float_type> &source) const;
    802 
    803     /// \brief create a new interpolating_function  which is the parent interpolating_function 
     1517    /// \return a new interpolating_function_p  with the same mappings for x and y
     1518        interpolating_function_p <float_type> & unary_operator(const c2_function<float_type> &source) const;
     1519
     1520    /// \brief create a new interpolating_function_p  which is the parent interpolating_function_p 
    8041521    /// combined with \a rhs using \a combiner at every point in the interpolating tables
    8051522    ///
     
    8071524    /// \param rhs the function to apply
    8081525    /// \param combining_stub a function which defines which binary operation to use.
    809     /// \return a new interpolating_function  with the same mappings for x and y
    810         interpolating_function <float_type> & binary_operator(const c2_function<float_type> &rhs,
    811            c2_binary_function<float_type> *combining_stub
     1526    /// \return a new interpolating_function_p  with the same mappings for x and y
     1527        interpolating_function_p <float_type> & binary_operator(const c2_function<float_type> &rhs,
     1528           const c2_binary_function<float_type> *combining_stub
    8121529           ) const;
    813        
    814         // InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    815         // when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    816         // can be upcast back to a c2_function to produce unprocessed binaries.
    817 
    818         /// \brief produce a newly resampled interpolating_function  which is the specified sum.
     1530        /// \brief produce a newly resampled interpolating_function_p  which is the specified sum.
    8191531    /// \param rhs the function to add, pointwise
    820     /// \return a new interpolating_function
    821     /// \note
    822         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    823         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    824         /// can be upcast back to a c2_function to produce unprocessed binaries.
    825     interpolating_function <float_type> & operator + (const c2_function<float_type> &rhs) const {
    826                 return binary_operator(rhs, new c2_sum<float_type>()); }
    827         /// \brief produce a newly resampled interpolating_function  which is the specified difference.
     1532    /// \return a new interpolating_function_p
     1533    interpolating_function_p <float_type> & add_pointwise (const c2_function<float_type> &rhs) const {
     1534                return binary_operator(rhs, new c2_sum_p<float_type>()); }
     1535        /// \brief produce a newly resampled interpolating_function_p  which is the specified difference.
    8281536    /// \param rhs the function to subtract, pointwise
    829     /// \return a new interpolating_function
    830     /// \note
    831         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    832         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    833         /// can be upcast back to a c2_function to produce unprocessed binaries.
    834         interpolating_function <float_type> & operator - (const c2_function<float_type> &rhs) const {
    835                 return binary_operator(rhs, new c2_diff<float_type>()); }
    836         /// \brief produce a newly resampled interpolating_function  which is the specified product.
     1537    /// \return a new interpolating_function_p
     1538        interpolating_function_p <float_type> & subtract_pointwise (const c2_function<float_type> &rhs) const {
     1539                return binary_operator(rhs, new c2_diff_p<float_type>()); }
     1540        /// \brief produce a newly resampled interpolating_function_p  which is the specified product.
    8371541    /// \param rhs the function to multiply, pointwise
    838     /// \return a new interpolating_function
    839     /// \note
    840         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    841         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    842         /// can be upcast back to a c2_function to produce unprocessed binaries.
    843         interpolating_function <float_type> & operator * (const c2_function<float_type> &rhs) const {
    844                 return binary_operator(rhs, new c2_product<float_type>()); }
    845         /// \brief produce a newly resampled interpolating_function  which is the specified ratio.
     1542    /// \return a new interpolating_function_p
     1543        interpolating_function_p <float_type> & multiply_pointwise (const c2_function<float_type> &rhs) const {
     1544                return binary_operator(rhs, new c2_product_p<float_type>()); }
     1545        /// \brief produce a newly resampled interpolating_function_p  which is the specified ratio.
    8461546    /// \param rhs the function to divide, pointwise
    847     /// \return a new interpolating_function
    848     /// \note
    849         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    850         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    851         /// can be upcast back to a c2_function to produce unprocessed binaries.
    852         interpolating_function <float_type> & operator / (const c2_function<float_type> &rhs) const {
    853                 return binary_operator(rhs, new c2_ratio<float_type>()); }
    854         /// \brief produce a newly resampled interpolating_function  which is the specified sum.
    855     /// \param rhs a constant to add, pointwise
    856     /// \return a new interpolating_function
    857     /// \note
    858         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    859         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    860         /// can be upcast back to a c2_function to produce unprocessed binaries.
    861         interpolating_function <float_type> & operator + (float_type rhs) const { return (*this)+c2_constant<float_type>(rhs); }
    862         /// \brief produce a newly resampled interpolating_function  which is the specified difference.
    863     /// \param rhs a constant to subtract, pointwise
    864     /// \return a new interpolating_function
    865     /// \note
    866         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    867         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    868         /// can be upcast back to a c2_function to produce unprocessed binaries.
    869         interpolating_function <float_type> & operator - (float_type rhs) const { return (*this)-c2_constant<float_type>(rhs); }
    870         /// \brief produce a newly resampled interpolating_function  which is the specified product.
    871     /// \param rhs a constant to multiply, pointwise
    872     /// \return a new interpolating_function
    873     /// \note
    874         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    875         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    876         /// can be upcast back to a c2_function to produce unprocessed binaries.
    877         interpolating_function <float_type> & operator * (float_type rhs) const { return (*this)*c2_constant<float_type>(rhs); }
    878         /// \brief produce a newly resampled interpolating_function  which is the specified ratio.
    879     /// \param rhs a constant to divide, pointwise
    880     /// \return a new interpolating_function
    881     /// \note
    882         /// InterpolatingFunctions override the c2_function operators, since they explicitly re-generate the interpolation table
    883         /// when they are applied.  If this is not desired, these operators are not virtual, so the interpolating_function
    884         /// can be upcast back to a c2_function to produce unprocessed binaries.
    885         interpolating_function <float_type> & operator / (float_type rhs) const { return (*this)/c2_constant<float_type>(rhs); }
    886        
    887         virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception);
    888        
    889         /// \brief move value & derivatives into our internal coordinates (use splint to go the other way!)
    890     /// \note why?
    891         void localize_derivatives(float_type xraw, float_type y, float_type yprime, float_type yprime2, float_type *y0, float_type *yp0, float_type *ypp0) const;
    892        
    893 protected:
    894                
    895         interpolating_function() : c2_function<float_type>() { } // default constructor is never used, prevent accidents by protecting it.
    896    
    897     /// \brief do the dirty work of constructing the spline.  See interpolating_function  constructor for details.
    898         void init(const std::vector<float_type> &, const std::vector<float_type> &,
     1547    /// \return a new interpolating_function_p
     1548        interpolating_function_p <float_type> & divide_pointwise (const c2_function<float_type> &rhs) const {
     1549                return binary_operator(rhs, new c2_ratio_p<float_type>()); }
     1550    /// \brief copy data from another interpolating function.  This only makes sense if the source
     1551        /// function has the same transforms as the destination.
     1552    /// \param rhs interpolating_function_p  to copy from
     1553        void clone_data(const interpolating_function_p <float_type> &rhs) {
     1554                Xraw=rhs.Xraw; X=rhs.X; F=rhs.F; y2=rhs.y2;
     1555                set_sampling_grid_pointer(Xraw);
     1556        }
     1557
     1558        const c2_function_transformation<float_type> &fTransform;
     1559       
     1560protected:   
     1561    /// \brief create the spline coefficients
     1562        void spline(
    8991563                          bool lowerSlopeNatural, float_type lowerSlope,
    900                           bool upperSlopeNatural, float_type upperSlope,
    901                           float_type (*inputXConversion)(float_type)=0,
    902                           float_type (*inputXConversionPrime)(float_type)=0,
    903                           float_type (*inputXConversionDPrime)(float_type)=0,
    904                           float_type (*inputYConversion)(float_type)=0,
    905                           float_type (*inputYConversionPrime)(float_type)=0,
    906                           float_type (*inputYConversionDPrime)(float_type)=0,
    907                           float_type (*outputYConversion)(float_type)=0
    908                           ) throw(c2_exception) ;
     1564                          bool upperSlopeNatural, float_type upperSlope
     1565                          ) throw(c2_exception);
     1566
     1567        // This is for sorting the data. It must be static if it's going to be a class member.
     1568        static bool comp_pair(std::pair<float_type,float_type> const &i, std::pair<float_type,float_type> const &j) {return i.first<j.first;}
    9091569
    9101570    std::vector<float_type> Xraw, X, F, y2;
    911        
    912         float_type (*fXin)(float_type), (*fYin)(float_type), (*fYout)(float_type);
    913         float_type (*fXinPrime)(float_type), (*fYinPrime)(float_type);
    914         float_type (*fXinDPrime)(float_type), (*fYinDPrime)(float_type);
    915        
    916         int xInverted;
    917     mutable int lastKLow;
    918 };
    919 
    920 /// \brief An interpolatingFunction with X transformed into log space. 
    921 ///
     1571        c2_const_ptr<float_type> sampler_function;
     1572        bool xInverted;
     1573    mutable size_t lastKLow;
     1574};
     1575
     1576/// \brief A spline with X transformed into log space. 
     1577/// \ingroup interpolators
    9221578/// Most useful for functions looking like y=log(x) or any other function with a huge X dynamic range,
    9231579/// and a slowly varying Y.
    924 template <typename float_type=double> class log_lin_interpolating_function : public interpolating_function <float_type> {
    925 public:
    926     /// \brief Construct the function.
    927     /// \param x the list of abscissas.  Must be either strictly increasing or strictly decreasing.
    928         /// Strictly increasing is preferred, as less memory is used since a copy is not required for the sampling grid.
    929     /// \param f the list of function values.
    930     /// \param lowerSlopeNatural if true, set y''(first point)=0 in LogLin space, otherwise compute it from \a lowerSope
    931     /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
    932     /// \param upperSlopeNatural if true, set y''(last point)=0 in LogLin space, otherwise compute it from \a upperSope
    933     /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
    934     log_lin_interpolating_function(const std::vector<float_type> &x, const std::vector<float_type> &f,
    935                                                                 bool lowerSlopeNatural=true, float_type lowerSlope=0.0,
    936                                                                 bool upperSlopeNatural=true, float_type upperSlope=0.0);
    937 protected:
    938         log_lin_interpolating_function() {} // do not allow naked construction... it is usually an accident.
    939 };
    940 
    941 
    942 /// \brief An interpolatingFunction with Y transformed into log space. 
    943 ///
     1580///
     1581///     The factory function c2_factory::log_lin_interpolating_function() creates *new log_lin_interpolating_function_p()
     1582template <typename float_type=double> class log_lin_interpolating_function_p : public interpolating_function_p <float_type> {
     1583public:
     1584    /// \brief an empty log-linear cubic-spline interpolating_function_p
     1585    ///
     1586        log_lin_interpolating_function_p() : interpolating_function_p<float_type>(*new c2_log_lin_function_transformation<float_type>)
     1587                { }
     1588        /// \brief create a new, empty interpolating function of this type (virtual constructor)
     1589        virtual interpolating_function_p<float_type> &clone() const throw(c2_exception)
     1590                {       return *new log_lin_interpolating_function_p<float_type>(); }
     1591};
     1592
     1593
     1594/// \brief A spline with Y transformed into log space. 
     1595/// \ingroup interpolators
    9441596/// Most useful for functions looking like y=exp(x)
    945 template <typename float_type=double> class lin_log_interpolating_function : public interpolating_function <float_type> {
    946 public:
    947     /// \brief Construct the function.
    948     /// \param x the list of abscissas.  Must be either strictly increasing or strictly decreasing.
    949         /// Strictly increasing is preferred, as less memory is used since a copy is not required for the sampling grid.
    950     /// \param f the list of function values.
    951     /// \param lowerSlopeNatural if true, set y''(first point)=0 in LinLog space, otherwise compute it from \a lowerSope
    952     /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
    953     /// \param upperSlopeNatural if true, set y''(last point)=0 in LinLog space, otherwise compute it from \a upperSope
    954     /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
    955     lin_log_interpolating_function(const std::vector<float_type> &x, const std::vector<float_type> &f,
    956                                                                 bool lowerSlopeNatural=true, float_type lowerSlope=0.0,
    957                                                                 bool upperSlopeNatural=true, float_type upperSlope=0.0);
    958 protected:
    959         lin_log_interpolating_function() {} // do not allow naked construction... it is usually an accident.
    960 };
    961 
    962 
    963 /// \brief An interpolatingFunction with X and Y transformed into log space. 
    964 ///
     1597///
     1598///     The factory function c2_factory::lin_log_interpolating_function() creates *new lin_log_interpolating_function_p()
     1599template <typename float_type=double> class lin_log_interpolating_function_p : public interpolating_function_p <float_type> {
     1600public:
     1601    /// \brief an empty linear-log cubic-spline interpolating_function_p
     1602    ///
     1603        lin_log_interpolating_function_p() : interpolating_function_p<float_type>(*new c2_lin_log_function_transformation<float_type>)
     1604                { }
     1605        /// \brief create a new, empty interpolating function of this type (virtual constructor)
     1606        virtual interpolating_function_p<float_type> &clone() const throw(c2_exception)
     1607                {       return *new lin_log_interpolating_function_p<float_type>(); }
     1608};
     1609
     1610
     1611/// \brief A spline with X and Y transformed into log space. 
     1612/// \ingroup interpolators
    9651613/// Most useful for functions looking like y=x^n or any other function with a huge X and Y dynamic range.
    966 template <typename float_type=double> class log_log_interpolating_function : public interpolating_function <float_type> {
    967 public:
    968     /// \brief Construct the function.
    969     /// \param x the list of abscissas.  Must be either strictly increasing or strictly decreasing.
    970         /// Strictly increasing is preferred, as less memory is used since a copy is not required for the sampling grid.
    971     /// \param f the list of function values.
    972     /// \param lowerSlopeNatural if true, set y''(first point)=0 in LogLog space, otherwise compute it from \a lowerSope
    973     /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
    974     /// \param upperSlopeNatural if true, set y''(last point)=0 in LogLog space, otherwise compute it from \a upperSope
    975     /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
    976     log_log_interpolating_function(const std::vector<float_type> &x, const std::vector<float_type> &f,
    977                                                                 bool lowerSlopeNatural=true, float_type lowerSlope=0.0,
    978                                                                 bool upperSlopeNatural=true, float_type upperSlope=0.0);
    979 protected:
    980         log_log_interpolating_function() {} // do not allow naked construction... it is usually an accident.
    981 };
    982 
    983 
    984 /// \brief An interpolating_function  with X in reciprocal space and Y transformed in log space. 
    985 ///
     1614///
     1615///     The factory function c2_factory::log_log_interpolating_function() creates *new log_log_interpolating_function_p()
     1616template <typename float_type=double> class log_log_interpolating_function_p : public interpolating_function_p <float_type> {
     1617public:
     1618    /// \brief an empty log-log cubic-spline interpolating_function_p
     1619    ///
     1620        log_log_interpolating_function_p() : interpolating_function_p<float_type>(*new c2_log_log_function_transformation<float_type>)
     1621                { }
     1622        /// \brief create a new, empty interpolating function of this type (virtual constructor)
     1623        virtual interpolating_function_p<float_type> &clone() const throw(c2_exception)
     1624        {       return *new log_log_interpolating_function_p<float_type>(); }
     1625};
     1626
     1627
     1628/// \brief A spline with X in reciprocal space and Y transformed in log space. 
     1629/// \ingroup interpolators
    9861630/// Most useful for thermodynamic types of data where Y is roughly A*exp(-B/x).
    9871631/// Typical examples are reaction rate data, and thermistor calibration data.
    988 template <typename float_type=double> class arrhenius_interpolating_function : public interpolating_function <float_type> {
    989 public:
    990     /// \brief Construct the function.
    991     /// \param x the list of abscissas.  Must be either strictly increasing or strictly decreasing.
    992         /// Strictly increasing is preferred, as less memory is used since a copy is not required for the sampling grid.
    993     /// \param f the list of function values.
    994     /// \param lowerSlopeNatural if true, set y''(first point)=0 in Arrhenius space, otherwise compute it from \a lowerSope
    995     /// \param lowerSlope derivative of the function at the lower bound, used only if \a lowerSlopeNatural is false
    996     /// \param upperSlopeNatural if true, set y''(last point)=0 in Arrhenius space, otherwise compute it from \a upperSope
    997     /// \param upperSlope derivative of the function at the upper bound, used only if \a upperSlopeNatural is false
    998     arrhenius_interpolating_function(const std::vector<float_type> &x, const std::vector<float_type> &f,
    999                                                                 bool lowerSlopeNatural=true, float_type lowerSlope=0.0,
    1000                                                                 bool upperSlopeNatural=true, float_type upperSlope=0.0);
    1001 protected:
    1002         arrhenius_interpolating_function() {} // do not allow naked construction... it is usually an accident.
    1003 };
    1004 
    1005 /**
    1006  \brief create a linear-linear interpolating grid with both x & y set to
    1007  (xmin, xmin+dx, ... xmin + (count-1)*dx )
    1008 
    1009  very useful for transformaiton with other functions e.g.
    1010  \code
    1011  f=c2_sin<double>::sin(LinearInterpolatingGrid(-0.1,0.1, 65))
    1012  \endcode
    1013  creates a spline table of sin(x) slightly beyond the first period
    1014  \param xmin the starting point for the grid
    1015  \param dx the step size for the grid
    1016  \param count the number of points in the  grid
    1017  \return an identity interpolating_function  with the requested grid
    1018  */
    1019 template <typename float_type> interpolating_function <float_type> &linear_interpolating_grid(float_type xmin, float_type dx, int count) {
    1020         std::vector<float_type> x(count);
    1021         for(int i=0; i<count; i++) x[i]=xmin + i * dx;
    1022         return *new interpolating_function <float_type>(x,x);
    1023 }
    1024 
    1025 /**
    1026  \brief create a log-log interpolating grid with both x & y set to
    1027  (xmin, xmin*dx, ... xmin * dx^(count-1) )
    1028 
    1029  very useful for transformaiton with other functions e.g.
    1030  \code
    1031  f=c2_log<double>::log(LogLogInterpolatingGrid(2, 1.1, 65))
    1032  \endcode
    1033  creates a spline table of log(x)
    1034  \param xmin the starting point for the grid
    1035  \param dx the ratio between points
    1036  \param count the number of points in the  grid
    1037  \return an identity log_log_interpolating_function with the requested grid
    1038 */
    1039 template <typename float_type> log_log_interpolating_function <float_type> &log_log_interpolating_grid(float_type xmin, float_type dx, int count) {
    1040         std::vector<float_type> x(count);
    1041         x[0]=xmin;
    1042         for(int i=1; i<count; i++) x[i]=dx*x[i-1];
    1043         return *new log_log_interpolating_function<float_type>(x,x);
    1044 }
     1632///
     1633///     The factory function c2_factory::arrhenius_interpolating_function() creates *new arrhenius_interpolating_function_p()
     1634template <typename float_type=double> class arrhenius_interpolating_function_p : public interpolating_function_p <float_type> {
     1635public:
     1636    /// \brief an empty arrhenius cubic-spline interpolating_function_p
     1637    ///
     1638        arrhenius_interpolating_function_p() : interpolating_function_p<float_type>(*new c2_arrhenius_function_transformation<float_type>)
     1639                { }
     1640        /// \brief create a new, empty interpolating function of this type (virtual constructor)
     1641        virtual interpolating_function_p<float_type> &clone() const throw(c2_exception)
     1642        {       return *new arrhenius_interpolating_function_p<float_type>(); }
     1643};
    10451644
    10461645/// \brief compute sin(x) with its derivatives.
    1047 ///
    1048 /// Creates a singleton instance c2_sin::sin of itself for convenient access.
    1049 template <typename float_type=double> class c2_sin : public c2_function<float_type> {
    1050 public:
    1051         /// \brief constructor.  There is alread a singleton c2_sin::sin, which usually suffices.
    1052         c2_sin() {}
     1646/// \ingroup math_functions
     1647///
     1648/// The factory function c2_factory::sin() creates *new c2_sin_p
     1649template <typename float_type=double> class c2_sin_p : public c2_function<float_type> {
     1650public:
     1651        /// \brief constructor.
     1652        c2_sin_p() : c2_function<float_type>() {}
    10531653       
    10541654        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     
    10581658    /// \param xmin the lower bound for the grid
    10591659    /// \param xmax upper bound for the grid
    1060     /// \return a new sampling grid.
    1061         virtual std::vector<float_type> &get_sampling_grid(float_type xmin, float_type xmax);
    1062     /// \brief the static singleton
    1063         static const c2_sin sin;
    1064 };
     1660    /// \param [in, out] grid the sampling grid.
     1661        virtual void get_sampling_grid(float_type xmin, float_type xmax,  std::vector<float_type> &grid) const;
     1662};
     1663
    10651664/// \brief compute cos(x) with its derivatives.
    1066 ///
    1067 /// Creates a singleton instance c2_cos::cos of itself for convenient access.
    1068 template <typename float_type=double> class c2_cos : public c2_sin<float_type> {
    1069 public:
    1070         /// \brief constructor.  There is already a singleton c2_cos::cos, which usually suffices.
    1071         c2_cos() {}
     1665/// \ingroup math_functions
     1666///
     1667/// The factory function c2_factory::cos() creates *new c2_cos_p
     1668template <typename float_type=double> class c2_cos_p : public c2_sin_p<float_type> {
     1669public:
     1670        /// \brief constructor.
     1671        c2_cos_p() : c2_sin_p<float_type>() {}
    10721672       
    10731673        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    10741674        { float_type q=std::cos(x); if(yprime) *yprime=-std::sin(x); if(yprime2) *yprime2=-q; return q; }       
    1075     /// \brief the static singleton
    1076         static const c2_cos cos;
    1077 };
     1675};
     1676
    10781677/// \brief compute tan(x) with its derivatives.
    1079 ///
    1080 /// Creates a singleton instance c2_tan::tan of itself for convenient access.
    1081 template <typename float_type=double> class c2_tan : public c2_function<float_type> {
    1082 public:
    1083         /// \brief constructor.  There is already a singleton c2_tan::tan, which usually suffices.
    1084         c2_tan() {}
     1678/// \ingroup math_functions
     1679///
     1680/// The factory function c2_factory::tan() creates *new c2_tan_p
     1681template <typename float_type=double> class c2_tan_p : public c2_function<float_type> {
     1682public:
     1683        /// \brief constructor.
     1684        c2_tan_p() : c2_function<float_type>() {}
    10851685       
    10861686        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     
    10921692                return t;
    10931693        }       
    1094     /// \brief the static singleton
    1095         static const c2_tan tan;
    1096 };
     1694};
     1695
    10971696/// \brief compute log(x) with its derivatives.
    1098 ///
    1099 /// Creates a singleton instance c2_log::log of itself for convenient access.
    1100 template <typename float_type=double> class c2_log : public c2_function<float_type> {
    1101 public:
    1102         /// \brief constructor.  There is already a singleton c2_log::log, which usually suffices.
    1103         c2_log() {}
     1697/// \ingroup math_functions
     1698///
     1699/// The factory function c2_factory::log() creates *new c2_log_p
     1700template <typename float_type=double> class c2_log_p : public c2_function<float_type> {
     1701public:
     1702        /// \brief constructor.
     1703        c2_log_p() : c2_function<float_type>() {}
    11041704
    11051705        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    11061706        { if(yprime) *yprime=1.0/x; if(yprime2) *yprime2=-1.0/(x*x); return std::log(x); }     
    1107     /// \brief the static singleton
    1108         static const c2_log log;
    1109 };
     1707};
     1708
    11101709/// \brief compute exp(x) with its derivatives.
    1111 ///
    1112 /// Creates a singleton instance c2_exp::exp of itself for convenient access.
    1113 template <typename float_type=double>  class c2_exp : public c2_function<float_type> {
    1114 public:
    1115         /// \brief constructor.  There is already a singleton c2_exp::exp, which usually suffices.
    1116         c2_exp() {}
     1710/// \ingroup math_functions
     1711///
     1712/// The factory function c2_factory::exp() creates *new c2_exp_p
     1713template <typename float_type=double>  class c2_exp_p : public c2_function<float_type> {
     1714public:
     1715        /// \brief constructor.
     1716        c2_exp_p() : c2_function<float_type>() {}
    11171717
    11181718        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    11191719        { float_type q=std::exp(x); if(yprime) *yprime=q; if(yprime2) *yprime2=q; return q; }
    1120     /// \ brief the static singleton
    1121         static const c2_exp exp;
    1122 };
     1720};
     1721
    11231722/// \brief compute sqrt(x) with its derivatives.
    1124 ///
    1125 /// Creates a singleton instance c2_sqrt::sqrt of itself for convenient access.
    1126 template <typename float_type=double> class c2_sqrt : public c2_function<float_type> {
    1127 public:
    1128         /// \brief constructor.  There is already a singleton c2_sqrt::sqrt, which usually suffices.
    1129         c2_sqrt() {}
     1723/// \ingroup math_functions
     1724///
     1725/// The factory function c2_factory::sqrt() creates *new c2_sqrt_p()
     1726template <typename float_type=double> class c2_sqrt_p : public c2_function<float_type> {
     1727public:
     1728        /// \brief constructor.
     1729        c2_sqrt_p() : c2_function<float_type>() {}
    11301730       
    11311731        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    11321732        { float_type q=std::sqrt(x); if(yprime) *yprime=0.5/q; if(yprime2) *yprime2=-0.25/(x*q); return q; }
    1133     /// \brief the static singleton
    1134         static const c2_sqrt sqrt;
    1135 };
     1733};
     1734
    11361735/// \brief compute scale/x with its derivatives.
    1137 ///
    1138 /// Creates a singleton instance c2_recip:recip of itself for convenient access.
    1139 template <typename float_type=double> class c2_recip : public c2_function<float_type> {
    1140 public:
    1141         /// \brief constructor.  There is already a singleton c2_recip::recip, which usually suffices.
    1142         c2_recip(float_type scale) : rscale(scale) {}
     1736/// \ingroup parametric_functions
     1737///
     1738/// The factory function c2_factory::recip() creates *new c2_recip_p
     1739template <typename float_type=double> class c2_recip_p : public c2_function<float_type> {
     1740public:
     1741        /// \brief constructor.
     1742        c2_recip_p(float_type scale) : c2_function<float_type>(), rscale(scale) {}
    11431743       
    11441744        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
     
    11531753        /// \param scale the new numerator
    11541754        void reset(float_type scale) { rscale=scale; }
    1155     /// \brief the static singleton
    1156         static const c2_recip recip;
    11571755private:
    11581756        float_type rscale;
    11591757};
     1758
    11601759/// \brief compute x with its derivatives.
    1161 ///
    1162 /// Creates a singleton instance c2_identity::identity of itself for convenient access.
    1163 template <typename float_type=double> class c2_identity : public c2_function<float_type> {
    1164 public:
    1165         /// \brief constructor.  There is already a singleton c2_identity::identity, which usually suffices.
    1166         c2_identity() {}
     1760/// \ingroup math_functions
     1761///
     1762/// The factory function c2_factory::identity() creates *new c2_identity_p
     1763template <typename float_type=double> class c2_identity_p : public c2_function<float_type> {
     1764public:
     1765        /// \brief constructor.
     1766        c2_identity_p() : c2_function<float_type>() {}
    11671767       
    11681768        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    11691769        { if(yprime) *yprime=1.0; if(yprime2) *yprime2=0; return x; }
    1170     /// \brief the static singleton
    1171         static const c2_identity identity;
    11721770};
    11731771
    11741772/**
    11751773 \brief create a linear mapping of another function
    1176  
     1774 \ingroup parametric_functions
    11771775 for example, given a c2_function \a f
    11781776 \code
    1179  c2_linear<double> L(1.2, 2.0, 3.0);
    1180  c2_composed_function<double> &F=L(f);
     1777 c2_function<double> &F=c2_linear<double>(1.2, 2.0, 3.0)(f);
    11811778 \endcode
    11821779 produces a new c2_function F=2.0+3.0*(\a f - 1.2)
     1780 
     1781 The factory function c2_factory::linear() creates *new c2_linear_p
    11831782*/
    1184 template <typename float_type=double> class c2_linear : public c2_function<float_type> {
     1783template <typename float_type=double> class c2_linear_p : public c2_function<float_type> {
    11851784public:
    11861785    /// \brief Construct the operator f=y0 + slope * (x-x0)
     
    11881787    /// \param y0 the y-intercept i.e. f(x0)
    11891788    /// \param slope the slope of the mapping
    1190         c2_linear(float_type x0, float_type y0, float_type slope) : xint(x0), intercept(y0), m(slope) {}
     1789        c2_linear_p(float_type x0, float_type y0, float_type slope) :
     1790                c2_function<float_type>(), xint(x0), intercept(y0), m(slope) {}
    11911791    /// \brief Change the slope and intercepts after construction.
    11921792        /// \param x0 the x offset
     
    12001800                float_type xint, intercept, m;
    12011801protected:
    1202                 c2_linear() {} // do not allow naked construction... it is usually an accident.
     1802                c2_linear_p() {} // do not allow naked construction... it is usually an accident.
    12031803};
    12041804
    12051805/**
    12061806\brief create a quadratic mapping of another function
    1207  
     1807 \ingroup parametric_functions
    12081808 for example, given a c2_function \a f
    12091809 \code
    1210  c2_quadratic<double> Q(1.2, 2.0, 3.0, 4.0);
    1211  c2_composed_function<double> &F=Q(f);
     1810 c2_function<double> &F=c2_quadratic<double>(1.2, 2.0, 3.0, 4.0)(f);
    12121811 \endcode
    12131812 produces a new c2_function F=2.0 + 3.0*(f-1.2) + 4.0*(f-1.2)^2
     
    12151814 note that the parameters are overdetermined, but allows the flexibility of two different representations
    12161815
     1816 The factory function c2_factory::quadratic() creates *new c2_quadratic_p
    12171817 */
    1218 template <typename float_type=double> class c2_quadratic : public c2_function<float_type> {
     1818template <typename float_type=double> class c2_quadratic_p : public c2_function<float_type> {
    12191819public:
    12201820    /// \brief Construct the operator
     
    12231823    /// \param xcoef the scale on the (\a x - \a x0) term
    12241824    /// \param x2coef the scale on the (\a x - \a x0)^2 term
    1225         c2_quadratic(float_type x0, float_type y0, float_type xcoef, float_type x2coef) : intercept(y0), center(x0), a(x2coef), b(xcoef) {}
    1226     /// Modify the mapping after construction
     1825        c2_quadratic_p(float_type x0, float_type y0, float_type xcoef, float_type x2coef) :
     1826                c2_function<float_type>(), intercept(y0), center(x0), a(x2coef), b(xcoef) {}
     1827    /// \brief Modify the coefficients after construction
    12271828    /// \param x0 the new center around which the powers are computed
    12281829    /// \param y0 the new value of the function at \a x = \a x0
     
    12361837                float_type intercept, center, a, b;
    12371838protected:
    1238                 c2_quadratic() {} // do not allow naked construction... it is usually an accident.
     1839                c2_quadratic_p() {} // do not allow naked construction... it is usually an accident.
    12391840};
    12401841
    12411842/**
    12421843\brief create a power law mapping of another function
    1243  
     1844 \ingroup parametric_functions
    12441845 for example, given a c2_function \a f
    12451846 \code
    1246  c2_power_law<double> PLaw(1.2, 2.5);
    1247  c2_composed_function<double> &F=PLaw(f);
     1847 c2_power_law_p<double> PLaw(1.2, 2.5);
     1848 c2_composed_function_p<double> &F=PLaw(f);
    12481849 \endcode
    12491850 produces a new c2_function F=1.2 * f^2.5
    12501851 
     1852 The factory function c2_factory::power_law() creates *new c2_power_law_p
    12511853 */
    1252 template <typename float_type=double> class c2_power_law : public c2_function<float_type> {
     1854template <typename float_type=double> class c2_power_law_p : public c2_function<float_type> {
    12531855public:
    12541856    /// \brief Construct the operator
    12551857    /// \param scale the multipler
    12561858    /// \param power the exponent
    1257         c2_power_law(float_type scale, float_type power) : a(scale), b(power) {}
     1859        c2_power_law_p(float_type scale, float_type power) :
     1860                c2_function<float_type>(), a(scale), b(power) {}
    12581861    /// \brief Modify the mapping after construction
    12591862    /// \param scale the new multipler
     
    12661869                float_type a, b;
    12671870protected:
    1268                 c2_power_law() {} // do not allow naked construction... it is usually an accident.
     1871                c2_power_law_p() {} // do not allow naked construction... it is usually an accident.
    12691872};
    12701873
    12711874/**
    12721875\brief create the formal inverse function of another function
    1273  
     1876 \ingroup containers
    12741877 for example, given a c2_function \a f
    12751878 \code
     
    12821885 derivatives, too, unlike the case of a simple root-finding inverse.  This means
    12831886 it can be integrated (for example) quite efficiently.
    1284  
    1285  Note that it is a subclass of c2_scaled_function only to manage ownership of another c2_function.
    1286  */
    1287 template <typename float_type=double> class c2_inverse_function : public c2_plugin_function<float_type> {
     1887
     1888 \see \ref combined_inversion_hinting_sampling
     1889
     1890 The factory function c2_factory::inverse_function() creates *new c2_inverse_function_p
     1891*/
     1892template <typename float_type=double> class c2_inverse_function_p : public c2_function<float_type> {
    12881893public:
    12891894    /// \brief Construct the operator
    12901895    /// \param source the function to be inverted
    1291         c2_inverse_function(const c2_function<float_type> &source); 
     1896        c2_inverse_function_p(const c2_function<float_type> &source); 
    12921897    virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception);
    12931898   
     
    13011906    ///  It is used in value_with_derivatives() to guess where to start the root finder.
    13021907    /// \param x the abscissa for which an estimate is needed
    1303     virtual float_type get_start_hint(float_type x) const { return start_hint; }
    1304    
     1908    virtual float_type get_start_hint(float_type x) const
     1909                { return hinting_function.valid()? hinting_function(x) : start_hint; }
     1910
     1911        /// \brief set or unset the approximate function used to start the root finder
     1912        /// \anchor set_hinting_function_discussion
     1913        /// A hinting function is mostly useful if the evaluation of this inverse is
     1914        /// going to be carried out in very non-local order, so the root finder has to start over
     1915        /// for each step.  If most evaluations are going to be made in fairly localized clusters (scanning
     1916        /// through the function, for example), the default mechanism used (which just remembers the last point)
     1917        /// is almost certainly faster.
     1918        ///
     1919        /// Typically, the hinting function is likely to be set up by creating the inverse function,
     1920        /// and then adaptively sampling an interpolating function from it, and then using the result
     1921        /// to hint it.  Another way, if the parent function is already an interpolating function, is just to create
     1922        /// a version of the parent with the x & y coordinates reversed.
     1923        ///
     1924        /// \see \ref combined_inversion_hinting_sampling
     1925        ///
     1926        /// \param hint_func the function that is an approximate inverse of the parent of this inverse_function
     1927        void set_hinting_function(const c2_function<float_type> *hint_func)
     1928                { hinting_function.set_function(hint_func); }
     1929    /// \brief set the hinting function from a pointer.
     1930        ///
     1931        /// See \ref set_hinting_function_discussion "discussion"
     1932        /// \param hint_func the container holding the function
     1933        void set_hinting_function(const c2_const_ptr<float_type> hint_func)
     1934                { hinting_function=hint_func; }
     1935       
    13051936protected:
    1306     c2_inverse_function() {} // do not allow naked construction... it is usually an accident.
    1307     mutable float_type start_hint;
     1937        c2_inverse_function_p() {} // do not allow naked construction... it is usually an accident.
     1938        mutable float_type start_hint;
     1939        const c2_const_ptr<float_type> func;
     1940        c2_const_ptr<float_type> hinting_function;
    13081941};
    13091942
    13101943/**
    13111944  \brief
    1312     An interpolating_function  which is the cumulative integral of a histogram.
    1313 
     1945    An interpolating_function_p  which is the cumulative integral of a histogram.
     1946        \ingroup interpolators
    13141947    Note than binedges should be one element longer than binheights, since the lower & upper edges are specified.
    13151948    Note that this is a malformed spline, since the second derivatives are all zero, so it has less continuity.
     
    13181951*/
    13191952
    1320 template <typename float_type=double>  class accumulated_histogram : public interpolating_function <float_type> {
     1953template <typename float_type=double>  class accumulated_histogram : public interpolating_function_p <float_type> {
    13211954public:
    13221955    /// \brief Construct the integrated histogram
     
    13321965
    13331966/**
    1334   \brief Construct a function useful for generation of random numbers from the given distribution
    1335  
    1336   inverse_integrated_density<InterpolatingFunctionFlavor>() starts with a probability density c2_function, generates the integral,
    1337   and generates an interpolating_function  which, when evaluated using a uniform random on [0,1] returns values
    1338   with a density distribution equal to the input distribution
    1339   If the data are passed in reverse order (large X first), the integral is carried out from the big end.
     1967        \anchor inverse_integrated_density_bins
     1968        \brief construct from a grid of points and an std::vector of probability densities (un-normalized)
     1969        \see  \ref random_subsec "Arbitrary random generation"
     1970        \ingroup interpolators
     1971         inverse_integrated_density starts with a probability density  std::vector, generates the integral,
     1972         and generates an interpolating_function_p  of the inverse function which, when evaluated using a uniform random on [0,1] returns values
     1973         with a density distribution equal to the input distribution
     1974         If the data are passed in reverse order (large X first), the integral is carried out from the big end.
     1975         
     1976        \param bins if \a bins .size()==\a binheights .size(), the centers of the bins.  \n
     1977        if \a bins .size()==\a binheights .size()+1, the edges of the bins
     1978        \param binheights a vector which describes the density of the random number distribution to be produced.
     1979        Note density... the numbers in the bins are not counts, but counts/unit bin width.
     1980        \return an interpolating_function_p  of the type requested in the template which,
     1981        if evaluated randomly with a uniform variate on [0,1] produces numbers
     1982        distributed according to \a binheights
     1983*/
     1984
     1985template <typename float_type, typename Final>
     1986interpolating_function_p<float_type> & inverse_integrated_density_bins(
     1987                const std::vector<float_type> &bins, const std::vector<float_type> &binheights)
     1988                throw(c2_exception);
     1989
     1990/**
     1991\anchor inverse_integrated_density_function
     1992        \brief construct from a grid of points and a c2_function of probability densities (un-normalized)
     1993        \see  \ref random_subsec "Arbitrary random generation"
     1994        \ingroup interpolators
     1995 inverse_integrated_density starts with a probability density  std::vector, generates the integral,
     1996 and generates an interpolating_function_p  of the inverse function which, when evaluated using a uniform random on [0,1] returns values
     1997 with a density distribution equal to the input distribution
     1998 If the data are passed in reverse order (large X first), the integral is carried out from the big end.
    13401999 
    1341   \sa  template <typename Intermediate, typename Final> Final inverse_integrated_density(const std::vector, c2_function &)
    1342  
    1343   \param bincenters points at which to sample the c2_function \a binheights
    1344   \param binheights a c2_function which describes the random number distribution to be produced.
    1345   \return an interpolating_function  of the type requested in the template which,
    1346      if evaluated randomly with a uniform variate on [0,1) produces numbers
    1347      distributed according to \a binheights
    1348 */
    1349 
    1350 template <typename float_type, typename Final >
    1351         Final &inverse_integrated_density(const std::vector<float_type> &bincenters, c2_function<float_type> &binheights)
    1352 {       
    1353         std::vector<float_type> integral;
    1354        
    1355         // integrate from first to last bin in original order, leaving results in integral
    1356         // ask for relative error of 1e-6 on each bin, with absolute error set to 0 (since we don't know the data scale).
    1357         float_type sum=binheights.partial_integrals(bincenters, &integral, 0.0, 1e-6);
    1358         // the integral vector now has partial integrals... it must be accumulated by summing
    1359         integral.insert(integral.begin(), 0.0); // integral from start to start is 0
    1360         float_type scale=1.0/sum;
    1361         for(size_t i=1; i<integral.size(); i++) integral[i]=integral[i]*scale + integral[i-1];
    1362         integral.back()=1.0; // force exact value on boundary
    1363        
    1364         return  *new Final(integral, bincenters,
    1365                                            false, 1.0/(scale*binheights(bincenters.front() )),
    1366                                            false, 1.0/(scale*binheights(bincenters.back() ))
    1367                                            ); // use integral as x axis in inverse function
    1368 }
    1369 
    1370 /**
    1371  \brief Construct a function useful for generation of random numbers from the given distribution
    1372 
    1373  \code
    1374  template <typename Intermediate, typename Final>
    1375      Final & inverse_integrated_density(const std::vector &bincenters, const std::vector &binheights)
    1376  \endcode
    1377  is a variant of \code
    1378  template <typename Final>
    1379      Final & inverse_integrated_density(const std::vector &bincenters, c2_function &binheights)
    1380  \endcode
    1381  which takes two std::vectors and generates the intermediate interpolating_function  required for
    1382  inverse_integrated_density(), and then calls it.
    1383 
    1384  \param bincenters points at which \a binheights are defined
    1385  \param binheights an std::vector which describes the random number distribution to be produced.
    1386  \return an interpolating_function  of the type requested in the template which,
    1387  if evaluated randomly with a uniform variate on [0,1) produces numbers
    1388   distributed according to \a binheights
    1389 */
    1390 
    1391 template <typename float_type, typename Intermediate, typename Final> Final
    1392     &inverse_integrated_density(const std::vector<float_type> &bincenters, const std::vector<float_type> &binheights)
    1393 {       
    1394         std::vector<float_type> be(bincenters), bh(binheights);
    1395        
    1396         if(be[1] < be[0]) { // reverse data for interpolator if x axis passed in backwards
    1397                 std::reverse(be.begin(), be.end());
    1398                 std::reverse(bh.begin(), bh.end());
    1399         }
    1400        
    1401         Intermediate temp(be, bh); // create a temporary interpolating_function  to integrate
    1402         Final &result=inverse_integrated_density<Final>(bincenters, temp);
    1403        
    1404         return result;
    1405 }
     2000        \param bincenters the centers of the bins.
     2001        \param binheights a c2_function which describes the density of the random number distribution to be produced.
     2002        \return an interpolating_function_p  of the type requested in the template which,
     2003        if evaluated randomly with a uniform variate on [0,1] produces numbers
     2004        distributed according to \a binheights
     2005 */
     2006template <typename float_type, typename Final>
     2007interpolating_function_p<float_type>  & inverse_integrated_density_function(
     2008                const std::vector<float_type> &bincenters, const c2_function<float_type> &binheights)
     2009                throw(c2_exception);
    14062010
    14072011/// \brief create a c2_function which smoothly connects two other c2_functions.
    1408 ///
     2012/// \ingroup parametric_functions
    14092013/// This takes two points and generates a polynomial which matches two c2_function arguments
    14102014/// at those two points, with two derivatives at each point, and an arbitrary value at the center of the
     
    14142018/// of order 5.  If \a auto_center is false, the value \a y1 is used at the midpoint, resulting in a
    14152019/// polynomial of order 6.
    1416 template <typename float_type=double> class c2_connector_function : public c2_function<float_type> {
     2020///
     2021/// This is usually used in conjunction with c2_piecewise_function_p to assemble an apparently seamless
     2022/// function from a series of segments.
     2023/// \see \ref piecewise_applications_subsec "Sample Applications" and \ref c2_function::adaptively_sample() "Adaptive sampling"
     2024///
     2025/// The factory function c2_factory::connector_function() creates *new c2_connector_function_p
     2026template <typename float_type=double> class c2_connector_function_p : public c2_function<float_type> {
    14172027public:
    1418         /// \brief construct the container
    1419         /// \param f1 the function on the left side to be connected
     2028        /// \brief construct the container from two functions
     2029        /// \param x0 the point at which to match \a f1 and its derivatives
     2030        /// \param f0 the function on the left side to be connected
     2031        /// \param x2 the point at which to match \a f2 and its derivatives
    14202032        /// \param f2 the function on the right side to be connected
    1421         /// \param x0 the point at which to match \a f1 and its derivatives
    1422         /// \param x2 the point at which to match \a f2 and its derivatives
    14232033        /// \param auto_center if true, no midpoint value is specified.  If false, match the value \a y1 at the midpoint
    14242034        /// \param y1 the value to match at the midpoint, if \a auto_center is false
    1425         /// \return a c2_function with domain (\a x0,\a x2) which smoothly connects \a f1 and \a f2
    1426         c2_connector_function(const c2_function<float_type> &f1, const c2_function<float_type> &f2, float_type x0, float_type x2,
     2035        /// \return a c2_function with domain (\a x0,\a x2) which smoothly connects \a f0(x0) and \a f2(x2)
     2036        c2_connector_function_p(float_type x0, const c2_function<float_type> &f0, float_type x2, const c2_function<float_type> &f2,
    14272037                        bool auto_center, float_type y1);
     2038        /// \brief construct the container from numerical values
     2039        /// \param x0 the position of the left edge
     2040        /// \param y0 the function derivative on the left boundary
     2041        /// \param yp0 the function second derivative on the left boundary
     2042        /// \param ypp0 the function value on the left boundary
     2043        /// \param x2 the position of the right edge
     2044        /// \param y2 the function derivative on the right boundary
     2045        /// \param yp2 the function second derivative on the right boundary
     2046        /// \param ypp2 the function value on the right boundary
     2047        /// \param auto_center if true, no midpoint value is specified.  If false, match the value \a y1 at the midpoint
     2048        /// \param y1 the value to match at the midpoint, if \a auto_center is false
     2049        /// \return a c2_function with domain (\a x0,\a x2) which smoothly connects the points described
     2050        /// \anchor c2_connector_raw_init_docs
     2051        c2_connector_function_p(
     2052                float_type x0, float_type y0, float_type yp0, float_type ypp0,
     2053                float_type x2, float_type y2, float_type yp2, float_type ypp2,
     2054                bool auto_center, float_type y1);
     2055        /// \brief construct the container from c2_fblock<float_type> objects
     2056        /// \param fb0 the left edge
     2057        /// \param fb2 the right edge
     2058        /// \param auto_center if true, no midpoint value is specified.  If false, match the value \a y1 at the midpoint
     2059        /// \param y1 the value to match at the midpoint, if \a auto_center is false
     2060        /// \return a c2_function with domain (\a fb0.x,\a fb2.x) which smoothly connects \a fb0 and \a fb2
     2061        c2_connector_function_p(
     2062                const c2_fblock<float_type> &fb0,
     2063                const c2_fblock<float_type> &fb2,
     2064                bool auto_center, float_type y1);
     2065
    14282066        /// \brief destructor
    1429         virtual ~c2_connector_function();
     2067        virtual ~c2_connector_function_p();
    14302068        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw (c2_exception);
    14312069protected:
    1432         float_type fx1, fhinv, fdx, fy1, fa, fb, fc, fd, fe, ff;
    1433 };
    1434 
    1435 
     2070        /// \brief fill container numerically
     2071        void init(
     2072                const c2_fblock<float_type> &fb0,
     2073                const c2_fblock<float_type> &fb2,
     2074                bool auto_center, float_type y1);
     2075
     2076        float_type fhinv, fy1, fa, fb, fc, fd, fe, ff;
     2077};
    14362078
    14372079/// \brief create a c2_function which is a piecewise assembly of other c2_functions.
    1438 ///
     2080/// \ingroup containers
    14392081/// The functions must have increasing, non-overlapping domains.  Any empty space
    14402082/// between functions will be filled with a linear interpolation.
     2083///
     2084/// \note If you want a smooth connection, instead of the default linear interpolation,
     2085/// create a c2_connector_function_p to bridge the gap.  The linear interpolation is intended
     2086/// to be a barely intelligent bridge, and may never get used by anyone.
     2087///
    14412088/// \note The creation of the container results in the creation of an explicit sampling grid. 
    14422089/// If this is used with functions with a large domain, or which generate very dense sampling grids,
    14432090/// it could eat a lot of memory.  Do not abuse this by using functions which can generate gigantic grids.
    14442091///
    1445 /// See c2_plugin_function for a discussion of how this might be used.
    1446 template <typename float_type=double> class c2_piecewise_function : public c2_function<float_type> {
     2092/// \see \ref piecewise_applications_subsec "Sample Applications" \n
     2093/// c2_plugin_function_p page \n
     2094/// c2_connector_function_p page \n
     2095/// \ref c2_function::adaptively_sample() "Adaptive sampling"
     2096///
     2097/// The factory function c2_factory::piecewise_function() creates *new c2_piecewise_function_p
     2098template <typename float_type=double> class c2_piecewise_function_p : public c2_function<float_type> {
    14472099public:
    14482100        /// \brief construct the container
    1449         c2_piecewise_function();
     2101        c2_piecewise_function_p();
    14502102        /// \brief destructor
    1451         virtual ~c2_piecewise_function();
     2103        virtual ~c2_piecewise_function_p();
    14522104        virtual float_type value_with_derivatives(float_type x, float_type *yprime, float_type *yprime2) const throw (c2_exception);
    14532105        /// \brief append a new function to the sequence
     
    14572109        /// the final function.  If the domain exactly abuts the domain of the previous function, it
    14582110        /// will be directly attached.  If there is a gap, the gap will be filled in by linear interpolation.
    1459         /// If the function being appended is to be deleted automatically when this container is deleted, set the pass_ownership flag.
    14602111        /// \param func a c2_function with a defined domain to be appended to the collection
    1461         /// \param pass_ownership if set, \a func will be deleted when the container is destroyed
    1462         void append_function(c2_function<float_type> &func, bool pass_ownership) throw (c2_exception);
     2112        void append_function(const c2_function<float_type> &func) throw (c2_exception);
    14632113protected:
    1464         std::vector<c2_function<float_type> *> functions;
    1465         std::vector<bool> owns;
     2114        std::vector<c2_const_ptr<float_type> > functions;
    14662115        mutable int lastKLow;
    14672116};
  • trunk/examples/extended/electromagnetic/TestEm7/include/c2_function.icc

    r807 r1230  
     1//
     2// ********************************************************************
     3// * License and Disclaimer                                           *
     4// *                                                                  *
     5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
     6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
     7// * conditions of the Geant4 Software License,  included in the file *
     8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
     9// * include a list of copyright holders.                             *
     10// *                                                                  *
     11// * Neither the authors of this software system, nor their employing *
     12// * institutes,nor the agencies providing financial support for this *
     13// * work  make  any representation or  warranty, express or implied, *
     14// * regarding  this  software system or assume any liability for its *
     15// * use.  Please see the license in the file  LICENSE  and URL above *
     16// * for the full disclaimer and the limitation of liability.         *
     17// *                                                                  *
     18// * This  code  implementation is the result of  the  scientific and *
     19// * technical work of the GEANT4 collaboration.                      *
     20// * By using,  copying,  modifying or  distributing the software (or *
     21// * any work based  on the software)  you  agree  to acknowledge its *
     22// * use  in  resulting  scientific  publications,  and indicate your *
     23// * acceptance of all terms of the Geant4 Software license.          *
     24// ********************************************************************
     25//
     26//
    127/**
    228 *  \file
     
    733 *  \author Copyright 2005 __Vanderbilt University__. All rights reserved.
    834 *
    9  *      \version c2_function.cc,v 1.43 2007/11/12 20:22:54 marcus Exp
     35 *      \version c2_function.cc,v 1.169 2008/05/22 12:45:19 marcus Exp
    1036 */
    1137
     
    2248
    2349template <typename float_type> const std::string c2_function<float_type>::cvs_file_vers() const
    24 { return "c2_function.cc,v 1.43 2007/11/12 20:22:54 marcus Exp"; }
     50{ return "c2_function.cc,v 1.169 2008/05/22 12:45:19 marcus Exp"; }
    2551
    2652// find a pre-bracketed root of a c2_function, which is a MUCH easier job than general root finding
     
    3359        // find f(x)=value within the brackets, using the guarantees of smoothness associated with a c2_function
    3460        // can use local f(x)=a*x**2 + b*x + c and solve quadratic to find root, then iterate
    35         reset_evaluations();
    3661       
    3762        float_type yp, yp2; // we will make unused pointers point here, to save null checks later
     
    4772        float_type c, b;
    4873       
     74        if(!root_info) {
     75                root_info=new struct c2_root_info;
     76                root_info->inited=false;
     77        }
    4978        // this new logic is to keep track of where we were before, and lower the number of
    5079        // function evaluations if we are searching inside the same bracket as before.
    5180        // Since this root finder has, very often, the bracket of the entire domain of the function,
    5281        // this makes a big difference, especially to c2_inverse_function
    53         if(!rootInitialized || upper_bracket != lastRootUpperX || lower_bracket != lastRootLowerX) {
    54                 lastRootUpperY=value_with_derivatives(upper_bracket, final_yprime, final_yprime2);
    55                 increment_evaluations();
    56                 lastRootUpperX=upper_bracket;
    57        
    58                 lastRootLowerY=value_with_derivatives(lower_bracket, final_yprime, final_yprime2);
    59                 increment_evaluations();
    60                 lastRootLowerX=lower_bracket;
    61                 rootInitialized=true;
    62         }
    63        
    64         float_type clower=lastRootLowerY-value;
    65         float_type cupper=lastRootUpperY-value;
    66         if(clower*cupper >0) {
     82        if(!root_info->inited || upper_bracket != root_info->upper.x || lower_bracket != root_info->lower.x) {
     83                root_info->upper.x=upper_bracket;
     84                fill_fblock(root_info->upper);         
     85                root_info->lower.x=lower_bracket;
     86                fill_fblock(root_info->lower);
     87                root_info->inited=true;
     88        }
     89       
     90        float_type clower=root_info->lower.y-value;
     91        if(!clower) {
     92                *final_yprime=root_info->lower.yp;
     93                *final_yprime2=root_info->lower.ypp;
     94                return lower_bracket;
     95        }
     96       
     97        float_type cupper=root_info->upper.y-value;
     98        if(!cupper) {
     99                *final_yprime=root_info->upper.yp;
     100                *final_yprime2=root_info->upper.ypp;
     101                return upper_bracket;
     102        }
     103        const float_type lower_sign = (clower < 0) ? -1 : 1;
     104       
     105        if(lower_sign*cupper >0) {
    67106                // argh, no sign change in here!
    68107                if(error) { *error=1; return 0.0; }
     
    104143           }
    105144           c=value_with_derivatives(root, final_yprime, final_yprime2)-value; // compute initial values
     145           if(c2_isnan(c)) {
     146                   bad_x_point=root;
     147                   return c; // return the nan if a computation failed
     148           }
    106149           b=*final_yprime; // make a local copy for readability
    107150           increment_evaluations();
    108151
    109152           // now, close in bracket on whichever side this still brackets
    110            if(c*clower < 0.0) {
     153           if(c*lower_sign < 0.0) {
    111154                   cupper=c;
    112155                   upper_bracket=root;
     
    131174
    132175// the recursive part of the integrator is agressively designed to minimize copying of data... lots of pointers
    133 template <typename float_type> float_type c2_function<float_type>::integrate_step(c2_integrate_recur &rb) const
    134 {
    135         struct c2_integrate_fblock *fbl[3]={rb.f0, rb.f1, rb.f2};
    136         struct c2_integrate_fblock f1; // will hold new middle values
    137         float_type retvals[2]={0.0,0.0};
    138         float_type lr[2];
    139 
    140         // std::cout << "entering with " << rb.f0->x << " " << rb.f1->x << " " << rb.f2->x << std::endl;
    141        
    142         int depth=rb.depth; // save this from the recursion block
    143         float_type abs_tol=rb.abs_tol;  // this is the value we will pass down
    144         float_type *rblr=rb.lr; // save pointer to our parent's lr[2] array since it will get trampled in recursion
    145        
    146         if(!depth) {
     176template <typename float_type> float_type c2_function<float_type>::integrate_step(c2_integrate_recur &rb) const throw(c2_exception)
     177{
     178        std::vector< recur_item > &rb_stack=*rb.rb_stack; // heap-based stack of data for recursion
     179        rb_stack.clear();
     180
     181        recur_item top;
     182        top.depth=0; top.done=false; top.f0index=0; top.f2index=0; top.step_sum=0;
     183       
     184        // push storage for our initial elements
     185        rb_stack.push_back(top);
     186        rb_stack.back().f1=*rb.f0;
     187        rb_stack.back().done=true; // this element will never be evaluated further
     188       
     189        rb_stack.push_back(top);
     190        rb_stack.back().f1=*rb.f1;
     191        rb_stack.back().done=true; // this element will never be evaluated further
     192               
     193        if(!rb.inited) {
    147194                switch(rb.derivs) {
    148195                        case 0:
     
    157204               
    158205                rb.extrap2=1.0/(rb.extrap_coef-1.0);
    159         }
    160        
    161         for (int i=0; i<(depth==0?1:2); i++) { // handle left and right intervals, but only left one for depth=0
    162                 struct c2_integrate_fblock *f0=fbl[i], *f2=fbl[i+1];
    163                 f1.x=0.5*(f0->x + f2->x); // center of interval
    164                 float_type dx=f2->x - f0->x;
    165                 float_type dx2 = 0.5*dx;
    166                 float_type total;
    167                
    168                 f1.y=value_with_derivatives(f1.x, &(f1.yp), &(f1.ypp));
    169                 increment_evaluations();
    170                
     206                rb.dx_tolerance=10.0*std::numeric_limits<float_type>::epsilon();
     207                rb.abs_tol_min=10.0*std::numeric_limits<float_type>::min();
     208                rb.inited=true;
     209        }
     210       
     211        // now, push our first real element
     212        top.f0index=0; // left element is stack[0]
     213        top.f2index=1; // right element is stack[1]
     214        top.abs_tol=rb.abs_tol;
     215        rb_stack.push_back(top);
     216               
     217        while(rb_stack.size() > 2) {
     218                recur_item &back=rb_stack.back();
     219                if(back.done) {
     220                        float_type sum=back.step_sum;
     221                        rb_stack.pop_back();
     222                        rb_stack.back().step_sum+=sum; // bump our sum up to the parent
     223                        continue;
     224                }
     225                back.done=true;
     226               
     227                c2_fblock<float_type> &f0=rb_stack[back.f0index].f1, &f2=rb_stack[back.f2index].f1;
     228                c2_fblock<float_type> &f1=back.f1; // will hold new middle values
     229                size_t f1index=rb_stack.size()-1; // our current offset
     230                float_type abs_tol=back.abs_tol;
     231               
     232                f1.x=0.5*(f0.x + f2.x); // center of interval
     233                float_type dx2=0.5*(f2.x - f0.x);
     234
    171235                // check for underflow on step size, which prevents us from achieving specified accuracy.
    172                 if(std::abs(dx) < std::abs(f1.x)*rb.rel_tol) {
     236                if(std::abs(dx2) < std::abs(f1.x)*rb.dx_tolerance || std::abs(dx2) < rb.abs_tol_min) {
    173237                        std::ostringstream outstr;
    174                         outstr << "Step size underflow in adaptive_partial_integrals at depth=" << depth << ", x= " << f1.x;
     238                        outstr << "Step size underflow in adaptive_partial_integrals at depth=" << back.depth << ", x= " << f1.x;
    175239                        throw c2_exception(outstr.str().c_str());
    176240                }
    177241               
    178                 if(!depth) { // top level, total has not been initialized yet
    179                         switch(rb.derivs) { // create estimate of next lower order for first try
     242                fill_fblock(f1);
     243                if(c2_isnan(f1.y)) {
     244                        bad_x_point=f1.x;
     245                        return f1.y; // can't go any further if a nan has appeared
     246                }
     247               
     248                bool yptrouble=f0.ypbad || f2.ypbad || f1.ypbad;
     249                bool ypptrouble=f0.yppbad || f2.yppbad || f1.yppbad;
     250               
     251                // select the real derivative count based on whether we are at a point where derivatives exist
     252                int derivs = std::min(rb.derivs, (yptrouble||ypptrouble)?(yptrouble?0:1):2);
     253                               
     254                if(!back.depth) { // top level, total has not been initialized yet
     255                        switch(derivs) { // create estimate of next lower order for first try
    180256                                case 0:
    181                                         total=0.5*(f0->y+f2->y)*dx; break;
     257                                        back.previous_estimate=(f0.y+f2.y)*dx2; break;
    182258                                case 1:
    183                                         total=(f0->y+4.0*f1.y+f2->y)*dx/6.0; break;
     259                                        back.previous_estimate=(f0.y+4.0*f1.y+f2.y)*dx2/3.0; break;
    184260                                case 2:
    185                                         total=( (14*f0->y + 32*f1.y + 14*f2->y) +  dx * (f0->yp - f2->yp) ) * dx /60.; break;
     261                                        back.previous_estimate=( (14*f0.y + 32*f1.y + 14*f2.y) +  2*dx2 * (f0.yp - f2.yp) ) * dx2 /30.; break;
    186262                                default:
    187                                         total=0.0; // just to suppress missing default warnings
     263                                        back.previous_estimate=0.0; // just to suppress missing default warnings
    188264                        }
    189                 } else total=rblr[i]; // otherwise, get it from previous level
     265                }
    190266               
    191267                float_type left, right;
    192268               
    193                 switch(rb.derivs) {
     269                // pre-compute constants so all multiplies use a small dynamic range
     270                // constants for 0 derivative integrator
     271                static const float_type c0c1=5./12., c0c2=8./12., c0c3=-1./12.;
     272                // constants for 1 derivative integrator
     273                static const float_type c1c1=101./240., c1c2=128./240., c1c3=11./240.,
     274                        c1c4=13./240., c1c5=-40./240., c1c6=-3./240.;
     275                // constants for 2 derivative integrator
     276                static const float_type c2c1=169./40320., c2c2=1024./ 40320., c2c3=-41./40320.,
     277                        c2c4=2727./40320., c2c5=-5040./40320., c2c6=423./40320.,
     278                        c2c7=17007./40320., c2c8=24576./40320., c2c9=-1263./40320.;
     279               
     280                switch(derivs) {
    194281                        case 2:
    195282                                // use ninth-order estimates for each side, from full set of all values (!) (Thanks, Mathematica!)
    196                                 left=   ( ( (169*f0->ypp + 1024*f1.ypp -  41*f2->ypp)*dx2 +
    197                                                         (2727*f0->yp - 5040*f1.yp +  423*f2->yp) )*dx2 +
    198                                                   (17007*f0->y + 24576*f1.y -  1263*f2->y) )* (dx2/40320.0);
    199                                 right=  ( ( (169*f2->ypp + 1024*f1.ypp -  41*f0->ypp)*dx2 -
    200                                                         (2727*f2->yp - 5040*f1.yp +  423*f0->yp) )*dx2 +
    201                                                   (17007*f2->y + 24576*f1.y -  1263*f0->y) )* (dx2/40320.0);
    202                                 // std::cout << f0->x << " " << f1.x << " " << f2->x <<  std::endl ;
    203                                 // std::cout << f0->y << " " << f1.y << " " << f2->y << " " << left << " " << right << " " << total << std::endl ;
     283                                left=   ( ( (c2c1*f0.ypp + c2c2*f1.ypp +  c2c3*f2.ypp)*dx2 +
     284                                                        (c2c4*f0.yp + c2c5*f1.yp +  c2c6*f2.yp) )*dx2 +
     285                                                  (c2c7*f0.y + c2c8*f1.y +  c2c9*f2.y) )* dx2;
     286                                right=  ( ( (c2c1*f2.ypp + c2c2*f1.ypp +  c2c3*f0.ypp)*dx2 -
     287                                                        (c2c4*f2.yp + c2c5*f1.yp +  c2c6*f0.yp) )*dx2 +
     288                                                  (c2c7*f2.y + c2c8*f1.y +  c2c9*f0.y) )* dx2;
     289                                // std::cout << f0.x << " " << f1.x << " " << f2.x <<  std::endl ;
     290                                // std::cout << f0.y << " " << f1.y << " " << f2.y << " " << left << " " << right << " " << total << std::endl ;
    204291                                break;
    205292                        case 1:
    206                                 left=   ( (202*f0->y + 256*f1.y + 22*f2->y) + dx*(13*f0->yp - 40*f1.yp - 3*f2->yp) ) * dx /960.;
    207                                 right=  ( (202*f2->y + 256*f1.y + 22*f0->y) - dx*(13*f2->yp - 40*f1.yp - 3*f0->yp) ) * dx /960.;
     293                                left=   ( (c1c1*f0.y + c1c2*f1.y + c1c3*f2.y) + dx2*(c1c4*f0.yp + c1c5*f1.yp + c1c6*f2.yp) ) * dx2 ;
     294                                right=  ( (c1c1*f2.y + c1c2*f1.y + c1c3*f0.y) - dx2*(c1c4*f2.yp + c1c5*f1.yp + c1c6*f0.yp) ) * dx2 ;
    208295                                break;
    209296                        case 0:
    210                                 left=   (5*f0->y + 8*f1.y - f2->y)*dx/24.;
    211                                 right=  (5*f2->y + 8*f1.y - f0->y)*dx/24.;
     297                                left=   (c0c1*f0.y + c0c2*f1.y + c0c3*f2.y)*dx2;
     298                                right=  (c0c1*f2.y + c0c2*f1.y + c0c3*f0.y)*dx2;
    212299                                break;
    213300                        default:
     
    216303                }
    217304               
    218                 lr[0]= left; // left interval
    219                 lr[1]= right; // right interval
    220305                float_type lrsum=left+right;
    221306
    222                 float_type eps=std::abs(total-lrsum)*rb.eps_scale;
    223                 if(rb.extrapolate) eps*=rb.eps_scale;
    224                
    225                 if(!rb.adapt || eps < abs_tol ||  eps < std::abs(total)*rb.rel_tol) {
    226                         if(depth==0 || !rb.extrapolate) retvals[i]=lrsum;
    227                         else {
    228                                 retvals[i]=(rb.extrap_coef*lrsum - total)*rb.extrap2;   
    229                                 // std::cout << "extrapolating " << lrsum << " " << total << " " << retvals[i] << std::endl;
    230                                
    231                         }
     307                bool extrapolate=back.depth && rb.extrapolate && (derivs==rb.derivs); // only extrapolate if no trouble with derivs
     308                float_type eps=std::abs(back.previous_estimate-lrsum)*rb.eps_scale;
     309                if(extrapolate) eps*=rb.eps_scale;
     310               
     311                if(rb.adapt && eps > abs_tol &&  eps > std::abs(lrsum)*rb.rel_tol) {
     312                        // tolerance not met, subdivide & recur
     313                        if(abs_tol > rb.abs_tol_min) abs_tol=abs_tol*0.5; // each half has half the error budget
     314                        top.abs_tol=abs_tol;
     315                        top.depth=back.depth+1;
     316                       
     317                        // save the last things we need from back before a push happens, in case
     318                        // the push causes a reallocation and moves the whole stack.
     319                        size_t f0index=back.f0index, f2index=back.f2index;
     320                       
     321                        top.f0index=f1index; top.f2index=f2index; // insert pointers to right side data into our recursion block
     322                        top.previous_estimate=right;
     323                        rb_stack.push_back(top);
     324
     325                        top.f0index=f0index; top.f2index=f1index; // insert pointers to left side data into our recursion block
     326                        top.previous_estimate=left;
     327                        rb_stack.push_back(top);
     328
     329                } else if(extrapolate) {
     330                        // extrapolation only happens on leaf nodes, where the tolerance was met.
     331                        back.step_sum+=(rb.extrap_coef*lrsum - back.previous_estimate)*rb.extrap2;
    232332                } else {
    233                         rb.depth=depth+1; // increment depth counter
    234                         rb.lr=lr;  // point to our left-right values array for recursion
    235                         rb.abs_tol=abs_tol*0.5; // each half has half the error budget
    236                         rb.f0=f0; rb.f1=&f1; rb.f2=f2; // insert pointers to data into our recursion block
    237                         // std::cout << "recurring with " << f0->x << " " << f1.x << " " << f2->x <<  std::endl ;
    238                         retvals[i]=integrate_step(rb); // and recur
    239                 }
    240         }       
    241         return retvals[0]+retvals[1];
     333                        back.step_sum+=lrsum;
     334                }
     335        }
     336        return rb_stack.back().step_sum; // last element on the stack holds the sum
    242337}
    243338
    244339template <typename float_type> bool c2_function<float_type>::check_monotonicity(
    245         const std::vector<float_type> &data, const char message[]) throw(c2_exception)
     340        const std::vector<float_type> &data, const char message[]) const throw(c2_exception)
    246341{
    247342        size_t np=data.size();
     
    269364}
    270365
    271 template <typename float_type> std::vector<float_type> &c2_function<float_type>::get_sampling_grid(float_type xmin, float_type xmax) const
    272 {
    273         std::vector<float_type> *result=new std::vector<float_type>;
     366template <typename float_type> void c2_function<float_type>::
     367        get_sampling_grid(float_type xmin, float_type xmax, std::vector<float_type> &grid) const
     368{
     369        std::vector<float_type> *result=&grid;
     370        result->clear();
    274371       
    275372        if( !(sampling_grid) || !(sampling_grid->size()) || (xmax <= sampling_grid->front()) || (xmin >= sampling_grid->back()) ) {
     
    313410                std::copy(sg.begin()+firstindex, sg.begin()+lastindex+1, result->begin()+initsize);
    314411                result->back()=xmax;
    315                
     412
    316413                //  this is the unrefined sampling grid... now check for very close points on front & back and fix if needed.
    317414                preen_sampling_grid(result);
    318415        }
    319         return *result;
    320416}
    321417
     
    351447}
    352448
    353 template <typename float_type> std::vector<float_type> &c2_function<float_type>::
    354         refine_sampling_grid(const std::vector<float_type> &grid, size_t refinement) const
     449template <typename float_type> void c2_function<float_type>::
     450        refine_sampling_grid(std::vector<float_type> &grid, size_t refinement) const
    355451{
    356452        size_t np=grid.size();
     
    358454        float_type dxscale=1.0/refinement;
    359455       
    360         std::vector<float_type> *result=new std::vector<float_type>(count);
     456        std::vector<float_type> result(count);
    361457       
    362458        for(size_t i=0; i<(np-1); i++) {
    363459                float_type x=grid[i];
    364460                float_type dx=(grid[i+1]-x)*dxscale;
    365                 for(size_t j=0; j<refinement; j++, x+=dx) (*result)[i*refinement+j]=x;
    366         }
    367         (*result)[count-1]=grid.back();
    368         return *result;
     461                for(size_t j=0; j<refinement; j++, x+=dx) result[i*refinement+j]=x;
     462        }
     463        result.back()=grid.back();
     464        grid=result; // copy the expanded grid back to the input
    369465}
    370466
    371467template <typename float_type> float_type c2_function<float_type>::integral(float_type xmin, float_type xmax, std::vector<float_type> *partials,
    372          float_type abs_tol, float_type rel_tol, int derivs, bool adapt, bool extrapolate) const
    373 {
    374         std::vector<float_type> &grid=get_sampling_grid(xmin, xmax);
    375         float_type intg=partial_integrals(grid, partials, abs_tol, rel_tol, adapt, extrapolate);
    376         delete &grid;
     468         float_type abs_tol, float_type rel_tol, int derivs, bool adapt, bool extrapolate) const throw(c2_exception)
     469{
     470        if(xmin==xmax) {
     471                if(partials) partials->clear();
     472                return 0.0;
     473        }
     474        std::vector<float_type> grid;
     475        get_sampling_grid(xmin, xmax, grid);
     476        float_type intg=partial_integrals(grid, partials, abs_tol, rel_tol, derivs, adapt, extrapolate);
    377477        return intg;
    378478}
    379479
    380480template <typename float_type> c2_function<float_type> &c2_function<float_type>::normalized_function(float_type xmin, float_type xmax, float_type norm)
     481        const throw(c2_exception)
    381482{
    382483        float_type intg=integral(xmin, xmax);
    383         return *new c2_scaled_function<float_type>(*this, norm/intg);
    384 }
    385 
    386 template <typename float_type> c2_function<float_type> &c2_function<float_type>::square_normalized_function(float_type xmin, float_type xmax, float_type norm)
    387 {
    388         c2_quadratic<float_type> q(0., 0., 0., 1.);
    389         c2_composed_function<float_type> mesquared(q,*this);
    390        
    391         std::vector<float_type> grid(get_sampling_grid(xmin, xmax));           
    392         float_type intg=mesquared.partial_integrals(grid);
    393        
    394         return *new c2_scaled_function<float_type>(*this, std::sqrt(norm/intg));
     484        return *new c2_scaled_function_p<float_type>(*this, norm/intg);
     485}
     486
     487template <typename float_type> c2_function<float_type> &c2_function<float_type>::square_normalized_function(float_type xmin, float_type xmax, float_type norm)
     488        const throw(c2_exception)
     489{
     490        c2_ptr<float_type> mesquared((*new c2_quadratic_p<float_type>(0., 0., 0., 1.))(*this));
     491       
     492        std::vector<float_type> grid;
     493        get_sampling_grid(xmin, xmax, grid);           
     494        float_type intg=mesquared->partial_integrals(grid);
     495       
     496        return *new c2_scaled_function_p<float_type>(*this, std::sqrt(norm/intg));
    395497}
    396498
    397499template <typename float_type> c2_function<float_type> &c2_function<float_type>::square_normalized_function(
    398500                float_type xmin, float_type xmax, const c2_function<float_type> &weight, float_type norm)
    399 {
    400         c2_quadratic<float_type> q(0., 0., 0., 1.);
    401         c2_composed_function<float_type> mesquared(q,*this);
    402         c2_product<float_type> weighted(mesquared, weight);
    403 
    404         std::vector<float_type> grid(get_sampling_grid(xmin, xmax));   
    405         float_type intg=weighted.partial_integrals(grid);
    406 
    407         return *new c2_scaled_function<float_type>(*this, std::sqrt(norm/intg));
     501        const throw(c2_exception)
     502{
     503        c2_ptr<float_type> weighted((*new c2_quadratic_p<float_type>(0., 0., 0., 1.))(*this) * weight);
     504
     505        std::vector<float_type> grid;
     506        get_sampling_grid(xmin, xmax, grid);   
     507        float_type intg=weighted->partial_integrals(grid);
     508
     509        return *new c2_scaled_function_p<float_type>(*this, std::sqrt(norm/intg));
    408510}
    409511
    410512template <typename float_type> float_type c2_function<float_type>::partial_integrals(
    411513        std::vector<float_type> xgrid, std::vector<float_type> *partials,
    412         float_type abs_tol, float_type rel_tol, int derivs, bool adapt, bool extrapolate) const
     514        float_type abs_tol, float_type rel_tol, int derivs, bool adapt, bool extrapolate)
     515        const throw(c2_exception)
    413516{
    414517        int np=xgrid.size();
    415518       
    416         struct c2_integrate_fblock f0, f2;
     519        c2_fblock<float_type> f0, f2;
    417520        struct c2_integrate_recur rb;
    418521        rb.rel_tol=rel_tol;
     
    420523        rb.adapt=adapt;
    421524        rb.derivs=derivs;
    422        
    423         reset_evaluations(); // counter returns with total evaluations needed for this integral
     525        std::vector< recur_item > rb_stack;
     526        rb_stack.reserve(20); // enough for most operations
     527        rb.rb_stack=&rb_stack;
     528        rb.inited=false;
     529        float_type dx_inv=1.0/std::abs(xgrid.back()-xgrid.front());
    424530       
    425531        if(partials) partials->resize(np-1);
     
    428534       
    429535        f2.x=xgrid[0];
    430         f2.y=value_with_derivatives(f2.x, &f2.yp, &f2.ypp);
    431         increment_evaluations();
     536        fill_fblock(f2);
     537        if(c2_isnan(f2.y)) {
     538                bad_x_point=f2.x;
     539                return f2.y; // can't go any further if a nan has appeared
     540        }
    432541       
    433542        for(int i=0; i<np-1; i++) {
     
    435544               
    436545                f2.x=xgrid[i+1];
    437                 f2.y=value_with_derivatives(f2.x, &f2.yp, &f2.ypp);
    438                 increment_evaluations();
    439                
    440                 rb.depth=0;
    441                 rb.abs_tol=abs_tol;
    442                 rb.f0=&f0; rb.f1=&f2; rb.f2=&f2; // we are really only using the left half for the top level
    443                 rb.lr=0; // pointer is meaningless; will be filled in in recursion
     546                fill_fblock(f2);
     547                if(c2_isnan(f2.y)) {
     548                        bad_x_point=f2.x;
     549                        return f2.y; // can't go any further if a nan has appeared
     550                }
     551               
     552                rb.abs_tol=abs_tol*std::abs(f2.x-f0.x)*dx_inv; // distribute error tolerance over whole domain
     553                rb.f0=&f0; rb.f1=&f2;
    444554                float_type ps=integrate_step(rb);
    445555                sum+=ps;
    446556                if(partials) (*partials)[i]=ps;
     557                if(c2_isnan(ps)) break; // NaN stops integration
    447558        }
    448559        return sum;
    449560}
    450 
    451 // declare singleton functions for most common c2_function instances
    452 #define c2_singleton(X) template <typename float_type> const c2_##X<float_type> c2_##X<float_type>::X=c2_##X();
    453 c2_singleton(sin)
    454 c2_singleton(cos)
    455 c2_singleton(tan)
    456 c2_singleton(log)
    457 c2_singleton(exp)
    458 c2_singleton(sqrt)
    459 c2_singleton(identity)
    460 
    461 // reciprocal is actually parametric (a/x), but make singleton 1/x
    462 template <typename float_type> const c2_recip<float_type> c2_recip<float_type>::recip=c2_recip(1.0);
    463 
    464 #undef c2_singleton
    465561
    466562// generate a sampling grid at points separated by dx=5, which is intentionally
    467563// incommensurate with pi and 2*pi so grid errors are somewhat randomized
    468 template <typename float_type> std::vector<float_type> &c2_sin<float_type>::get_sampling_grid(float_type xmin, float_type xmax)
    469 {
    470         std::vector<float_type> *result=new std::vector<float_type>;
    471        
    472         for(; xmin < xmax; xmin+=5.0) result->push_back(xmin);
    473         result->push_back(xmax);
    474         this->preen_sampling_grid(result);
    475         return *result;
    476 }
    477 
    478 template <typename float_type> float_type Identity(float_type x) { return x; } // a useful function
    479 template <typename float_type> float_type f_one(float_type) { return 1.0; } // the first derivative of identity
    480 template <typename float_type> float_type f_zero(float_type) { return 0.0; } // the second derivative of identity
     564template <typename float_type> void c2_sin_p<float_type>::
     565        get_sampling_grid(float_type xmin, float_type xmax,  std::vector<float_type> &grid) const
     566{
     567        grid.clear();   
     568        for(; xmin < xmax; xmin+=5.0) grid.push_back(xmin);
     569        grid.push_back(xmax);
     570        this->preen_sampling_grid(&grid);
     571}
     572
     573template <typename float_type> float_type c2_function_transformation<float_type>::evaluate(
     574                float_type xraw,
     575                float_type y, float_type yp0, float_type ypp0,
     576                float_type *yprime, float_type *yprime2) const
     577{
     578        y=Y.fHasStaticTransforms ? Y.pOut(y) : Y.fOut(y);
     579               
     580        if(yprime || yprime2) {
     581
     582                float_type yp, yp2;
     583                if(X.fHasStaticTransforms && Y.fHasStaticTransforms) {
     584                        float_type fpi=1.0/Y.pInPrime(y);
     585                        float_type gp=X.pInPrime(xraw);
     586                        // from Mathematica Dt[InverseFunction[f][y[g[x]]], x]
     587                        yp=gp*yp0*fpi; // transformed derivative
     588                        yp2=(gp*gp*ypp0 + X.pInDPrime(xraw)*yp0  - Y.pInDPrime(y)*yp*yp )*fpi;
     589                } else {
     590                        float_type fpi=1.0/Y.fInPrime(y);
     591                        float_type gp=X.fInPrime(xraw);
     592                        // from Mathematica Dt[InverseFunction[f][y[g[x]]], x]
     593                        yp=gp*yp0*fpi; // transformed derivative
     594                        yp2=(gp*gp*ypp0 + X.fInDPrime(xraw)*yp0  - Y.fInDPrime(y)*yp*yp )*fpi;
     595                }
     596                if(yprime) *yprime=yp;
     597                if(yprime2) *yprime2=yp2;
     598        }       
     599        return y;
     600}
    481601
    482602//  The constructor
    483 template <typename float_type> void interpolating_function<float_type>::init(
     603template <typename float_type> interpolating_function_p<float_type> & interpolating_function_p<float_type>::load(
    484604                                                                const std::vector<float_type> &x, const std::vector<float_type> &f,
    485605                                                                bool lowerSlopeNatural, float_type lowerSlope,
    486606                                                                bool upperSlopeNatural, float_type upperSlope,
    487                                                                 float_type (*inputXConversion)(float_type),
    488                                                                 float_type (*inputXConversionPrime)(float_type),
    489                                                                 float_type (*inputXConversionDPrime)(float_type),
    490                                                                 float_type (*inputYConversion)(float_type),
    491                                                                 float_type (*inputYConversionPrime)(float_type),
    492                                                                 float_type (*inputYConversionDPrime)(float_type),
    493                                                                 float_type (*outputYConversion)(float_type)
    494                                         ) throw(c2_exception)
    495 {
     607                                                                bool splined
     608                ) throw(c2_exception)
     609{
     610        c2_ptr<float_type> keepme(*this);
    496611        X= x;
    497612        F= f;
     
    501616
    502617        set_domain(std::min(Xraw.front(), Xraw.back()),std::max(Xraw.front(), Xraw.back()));
    503        
    504         fXin=inputXConversion;
    505         fXinPrime=inputXConversionPrime;
    506         fXinDPrime=inputXConversionDPrime;
    507         fYin=inputYConversion;
    508         fYinPrime=inputYConversionPrime;
    509         fYinDPrime=inputYConversionDPrime;
    510         fYout=outputYConversion;
    511        
     618               
    512619        if(x.size() != f.size()) {
    513620                throw c2_exception("interpolating_function::init() -- x & y inputs are of different size");
     
    529636        }
    530637       
    531         if(fXin) { // check if X scale is nonlinear, and if so, do transform
    532                 if(!lowerSlopeNatural) lowerSlope /= fXinPrime(X[0]);
    533                 if(!upperSlopeNatural) upperSlope /= fXinPrime(X[np-1]);
    534                 for(size_t i=0; i<np; i++) X[i]=fXin(X[i]);
    535         } else {
    536                 fXin=Identity<float_type>;
    537                 fXinPrime=f_one<float_type>;
    538                 fXinDPrime=f_zero<float_type>;
    539         }
    540        
    541         if(inputYConversion) {  // check if Y scale is nonlinear, and if so, do transform
    542                 if(!lowerSlopeNatural) lowerSlope *= fYinPrime(F[0]);
    543                 if(!upperSlopeNatural) upperSlope *= fYinPrime(F[np-1]);
    544                 for(size_t i=0; i<np; i++) F[i]=inputYConversion(F[i]);
    545         } else {
    546                 fYin=Identity<float_type>;
    547                 fYinPrime=f_one<float_type>;
    548                 fYinDPrime=f_zero<float_type>;
    549                 fYout=Identity<float_type>;
     638        if(fTransform.X.fTransformed) { // check if X scale is nonlinear, and if so, do transform
     639                if(!lowerSlopeNatural) lowerSlope /= fTransform.X.fInPrime(X[0]);
     640                if(!upperSlopeNatural) upperSlope /= fTransform.X.fInPrime(X[np-1]);
     641                for(size_t i=0; i<np; i++) X[i]=fTransform.X.fIn(X[i]);
     642        }       
     643        if(fTransform.Y.fTransformed) {  // check if Y scale is nonlinear, and if so, do transform
     644                if(!lowerSlopeNatural) lowerSlope *= fTransform.Y.fInPrime(F[0]);
     645                if(!upperSlopeNatural) upperSlope *= fTransform.Y.fInPrime(F[np-1]);
     646                for(size_t i=0; i<np; i++) F[i]=fTransform.Y.fIn(F[i]);
    550647        }
    551648                 
     
    553650                "interpolating_function::init() non-monotonic transformed x input");
    554651       
    555         // construct spline tables here. 
     652        if(splined) spline(lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope);
     653        else y2.assign(np,0.0);
     654       
     655        lastKLow=0;
     656        keepme.release_for_return();
     657        return *this;
     658}
     659
     660/*
     661//  The constructor
     662template <typename float_type> interpolating_function_p<float_type> & interpolating_function_p<float_type>::load_pairs(
     663                                                                std::vector<std::pair<float_type, float_type> > &data,
     664                                                                bool lowerSlopeNatural, float_type lowerSlope,
     665                                                                bool upperSlopeNatural, float_type upperSlope,
     666                                                                bool splined
     667                ) throw(c2_exception)
     668{
     669        c2_ptr<float_type> keepme(*this);
     670       
     671        size_t np=data.size();
     672        if(np < 2) {
     673                throw c2_exception("interpolating_function::init() -- input < 2 elements ");
     674        }
     675       
     676        // sort into ascending order
     677        std::sort(data.begin(), data.end(), comp_pair);
     678       
     679        std::vector<float_type> xtmp, ytmp;
     680        xtmp.reserve(np);
     681        ytmp.reserve(np);
     682        for (size_t i=0; i<np; i++) {
     683                xtmp.push_back(data[i].first);
     684                ytmp.push_back(data[i].second);
     685        }
     686        this->load(xtmp, ytmp, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope, splined);
     687       
     688        keepme.release_for_return();
     689        return *this;
     690}
     691
     692template <typename float_type> interpolating_function_p<float_type> &
     693        interpolating_function_p<float_type>::load_random_generator_function(
     694        const std::vector<float_type> &bincenters, const c2_function<float_type> &binheights)
     695        throw(c2_exception)
     696{       
     697        c2_ptr<float_type> keepme(*this);
     698
     699        std::vector<float_type> integral;
     700        c2_const_ptr<float_type> keepit(binheights); // manage function... not really needed here, but always safe.
     701        // integrate from first to last bin in original order, leaving results in integral
     702        // ask for relative error of 1e-6 on each bin, with absolute error set to 0 (since we don't know the data scale).
     703        float_type sum=binheights.partial_integrals(bincenters, &integral, 0.0, 1e-6);
     704        // the integral vector now has partial integrals... it must be accumulated by summing
     705        integral.insert(integral.begin(), 0.0); // integral from start to start is 0
     706        float_type scale=1.0/sum;
     707        for(size_t i=1; i<integral.size(); i++) integral[i]=integral[i]*scale + integral[i-1];
     708        integral.back()=1.0; // force exact value on boundary
     709       
     710        this->load(integral, bincenters,
     711                                           false, 1.0/(scale*binheights(bincenters.front() )),
     712                                           false, 1.0/(scale*binheights(bincenters.back() ))
     713                                           ); // use integral as x axis in inverse function
     714        keepme.release_for_return();
     715        return *this;
     716}
     717
     718template <typename float_type> interpolating_function_p<float_type> &
     719        interpolating_function_p<float_type>::load_random_generator_bins(
     720        const std::vector<float_type> &bins, const std::vector<float_type> &binheights)
     721        throw(c2_exception)
     722{       
     723        c2_ptr<float_type> keepme(*this);
     724
     725        size_t np=binheights.size();
     726        std::vector<float_type> integral(np+1), bin_edges(np+1);
     727       
     728        // compute the integral based on estimates of the bin edges from the given bin centers...
     729        // except for bin 0 & final bin, the edge of a bin is halfway between then center of the
     730        // bin and the center of the previous/next bin.
     731        // This gives width[n] = (center[n+1]+center[n])/2 - (center[n]+center[n-1])/2 = (center[n+1]-center[n-1])/2
     732        // for the edges, assume a bin of width (center[1]-center[0]) or (center[np-1]-center[np-2])
     733        // be careful that absolute values are used in case data are reversed.
     734
     735        if(bins.size() == binheights.size()+1) {
     736                bin_edges=bins; // edges array was passed in
     737        } else if (bins.size() == binheights.size()) {
     738                bin_edges.front()=bins[0] - (bins[1]-bins[0])*0.5; // edge bin
     739                for(size_t i=1; i<np; i++) {
     740                        bin_edges[i]=(bins[i]+bins[i-1])*0.5;
     741                }
     742                bin_edges.back()=bins[np-1] + (bins[np-1]-bins[np-2])*0.5; // edge bin
     743        } else {
     744                throw c2_exception("inconsistent bin vectors passed to load_random_generator_bins");
     745        }
     746       
     747        float_type running_sum=0.0;
     748        for(size_t i=0; i<np; i++) {
     749                integral[i]=running_sum;
     750                if(!binheights[i]) throw c2_exception("empty bin passed to load_random_generator_bins");
     751                running_sum+=binheights[i]*std::abs(bin_edges[i+1]-bin_edges[i]);
     752        }
     753        float_type scale=1.0/running_sum;
     754        for(size_t i=0; i<np; i++) integral[i]*=scale;
     755        integral.back()=1.0; // force exactly correct value on boundary
     756        this->load(integral, bin_edges,
     757                  false, 1.0/(scale*binheights.front()),
     758                  false, 1.0/(scale*binheights.back())
     759                  ); // use integral as x axis in inverse function
     760        keepme.release_for_return();
     761        return *this;
     762}
     763*/
     764
     765//  The spline table generator
     766template <typename float_type> void interpolating_function_p<float_type>::spline(
     767         bool lowerSlopeNatural, float_type lowerSlope,
     768         bool upperSlopeNatural, float_type upperSlope
     769         ) throw(c2_exception)
     770{
     771// construct spline tables here. 
    556772        // this code is a re-translation of the pythonlabtools spline algorithm from pythonlabtools.sourceforge.net
    557        
     773        size_t np=X.size();
    558774        std::vector<float_type> u(np),  dy(np-1), dx(np-1), dxi(np-1), dx2i(np-2), siga(np-2), dydx(np-1);
    559775       
     
    596812        y2[np-1]=(un-qn*u[np-2])/(qn*y2[np-2]+1.0);
    597813        for (size_t k=np-1; k != 0; k--) y2[k-1]=y2[k-1]*y2[k]+u[k-1];
    598        
    599         lastKLow=-1; // flag  new X search required for next evaluation
     814}
     815
     816template <typename float_type> interpolating_function_p<float_type> &interpolating_function_p<float_type>::sample_function(
     817                        const c2_function<float_type> &func,
     818                        float_type xmin, float_type xmax, float_type abs_tol, float_type rel_tol,
     819                        bool lowerSlopeNatural, float_type lowerSlope,
     820                        bool upperSlopeNatural, float_type upperSlope
     821 ) throw(c2_exception)
     822{
     823        c2_ptr<float_type> keepme(*this);
     824       
     825        const c2_transformation<float_type> &XX=fTransform.X, &YY=fTransform.Y; // shortcuts
     826       
     827         // set up our params to look like the samplng function for now
     828         sampler_function=func;
     829         std::vector<float_type> grid;
     830         func.get_sampling_grid(xmin, xmax, grid);
     831         size_t gsize=grid.size();
     832         if(XX.fTransformed) for(size_t i=0; i<gsize; i++) grid[i]=XX.fIn(grid[i]);
     833         set_sampling_grid_pointer(grid);
     834         
     835        // float_type xmin1=fXin(xmin), xmax1=fXin(xmax); // bounds in transformed space
     836         // get a list of points needed in transformed space, directly into our tables
     837         this->adaptively_sample(grid.front(), grid.back(), 8*abs_tol, 8*rel_tol, 0, &X, &F);
     838         // clear the sampler function now, since otherwise our value_with_derivatives is broken
     839         sampler_function.unset_function();
     840         
     841         xInverted=check_monotonicity(X,
     842                  "interpolating_function::init() non-monotonic transformed x input");
     843         
     844         size_t np=X.size();
     845         
     846         // Xraw is useful in some of the arithmetic operations between interpolating functions
     847         if(!XX.fTransformed) Xraw=X;
     848         else {
     849                 Xraw.resize(np);
     850                 for (size_t i=1; i<np-1; i++) Xraw[i]=XX.fOut(X[i]);
     851                 Xraw.front()=xmin;
     852                 Xraw.back()=xmax;
     853         }
     854                 
     855         bool xraw_rev=check_monotonicity(Xraw,
     856                  "interpolating_function::init() non-monotonic raw x input");
     857                  // which way does raw X point?  sampling grid MUST be increasing
     858         
     859         if(!xraw_rev) { // we can use pointer to raw X values if they are in the right order
     860                 set_sampling_grid_pointer(Xraw);
     861                 // our intial grid of x values is certainly a good guess for 'interesting' points
     862         } else {
     863                 set_sampling_grid(Xraw); // make a copy of it, and assure it is in right order
     864         }
     865         
     866         if(XX.fTransformed) { // check if X scale is nonlinear, and if so, do transform
     867                 if(!lowerSlopeNatural) lowerSlope /= XX.fInPrime(xmin);
     868                 if(!upperSlopeNatural) upperSlope /= XX.fInPrime(xmax);
     869         }     
     870         if(YY.fTransformed) {  // check if Y scale is nonlinear, and if so, do transform
     871                 if(!lowerSlopeNatural) lowerSlope *= YY.fInPrime(func(xmin));
     872                 if(!upperSlopeNatural) upperSlope *= YY.fInPrime(func(xmax));
     873         }
     874         // note that each of ends has 3 points with two equal gaps, since they were obtained by bisection
     875         // so the step sizes are easy to get
     876         // the 'natural slope' option for sampled functions has a different meaning than
     877         // for normal splines.  In this case, the derivative is adjusted to make the
     878         // second derivative constant on the last two points at each end
     879         // which is consistent with the error sampling technique we used to get here
     880         if(lowerSlopeNatural) {
     881                 float_type hlower=X[1]-X[0];
     882                 lowerSlope=0.5*(-F[2]-3*F[0]+4*F[1])/hlower;
     883                 lowerSlopeNatural=false; // it's not the usual meaning of natural any more
     884         }
     885         if(upperSlopeNatural) {
     886                 float_type hupper=X[np-1]-X[np-2];
     887                 upperSlope=0.5*(F[np-3]+3*F[np-1]-4*F[np-2])/hupper;
     888                 upperSlopeNatural=false; // it's not the usual meaning of natural any more
     889         }
     890         this->set_domain(xmin, xmax);
     891         
     892         spline(lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope);
     893         lastKLow=0;
     894         keepme.release_for_return();
     895         return *this;
    600896}
    601897
    602898//  This function is the reason for this class to exist
    603899// it computes the interpolated function, and (if requested) its proper first and second derivatives including all coordinate transforms
    604 template <typename float_type> float_type interpolating_function<float_type>::value_with_derivatives(
     900template <typename float_type> float_type interpolating_function_p<float_type>::value_with_derivatives(
    605901                                float_type x, float_type *yprime, float_type *yprime2) const throw(c2_exception)
    606902{
     903        if(sampler_function.valid()) {
     904                // if this is non-null, we are sampling data for later, so just return raw function
     905                // however, transform it into our sampling space, first.
     906                if(yprime) *yprime=0;
     907                if(yprime2) *yprime2=0;
     908                sampler_function->increment_evaluations();
     909                return fTransform.Y.fIn(sampler_function(fTransform.X.fOut(x))); // derivatives are completely undefined
     910        }
     911                                       
    607912        if(x < this->xmin() || x > this->xmax()) {
    608913                std::ostringstream outstr;
     
    613918        float_type xraw=x;
    614919       
    615         // template here is impossible! if(fXin && fXin != (Identity<float_type>) )
    616         x=fXin(x); // save time by explicitly testing for identity function here
     920        if(fTransform.X.fTransformed) x=fTransform.X.fHasStaticTransforms?
     921                fTransform.X.pIn(x) : fTransform.X.fIn(x); // save time by explicitly testing for identity function here
    617922       
    618923        int klo=0, khi=X.size()-1;
     924
     925        if(khi < 0) throw c2_exception("Uninitialized interpolating function being evaluated");
     926       
     927        const float_type *XX=&X[lastKLow]; // make all fast checks short offsets from here
    619928       
    620929        if(!xInverted) { // select search depending on whether transformed X is increasing or decreasing
    621                 if(lastKLow >=0 && (X[lastKLow] <= x) && (X[lastKLow+1] >= x) ) { // already bracketed
     930                if((XX[0] <= x) && (XX[1] >= x) ) { // already bracketed
    622931                        klo=lastKLow;
    623                 } else if(lastKLow >=0 && (X[lastKLow+1] <= x) && (X[lastKLow+2] > x)) { // in next bracket to the right
     932                } else if((XX[1] <= x) && (XX[2] >= x)) { // in next bracket to the right
    624933                        klo=lastKLow+1;         
    625                 } else if(lastKLow > 0 && (X[lastKLow-1] <= x) && (X[lastKLow] > x)) { // in next bracket to the left
     934                } else if(lastKLow > 0 && (XX[-1] <= x) && (XX[0] >= x)) { // in next bracket to the left
    626935                        klo=lastKLow-1;         
    627936                } else { // not bracketed, not close, start over
     
    634943                }
    635944        } else {
    636                 if(lastKLow >=0 && (X[lastKLow] >= x) && (X[lastKLow+1] <= x) ) { // already bracketed
     945                if((XX[0] >= x) && (XX[1] <= x) ) { // already bracketed
    637946                        klo=lastKLow;
    638                 } else if(lastKLow >=0 && (X[lastKLow+1] >= x) && (X[lastKLow+2] < x)) { // in next bracket to the right
     947                } else if((XX[1] >= x) && (XX[2] <= x)) { // in next bracket to the right
    639948                        klo=lastKLow+1;         
    640                 } else if(lastKLow > 0 && (X[lastKLow-1] >= x) && (X[lastKLow] < x)) { // in next bracket to the left
     949                } else if(lastKLow > 0 && (XX[-1] >= x) && (XX[0] <= x)) { // in next bracket to the left
    641950                        klo=lastKLow-1;         
    642951                } else { // not bracketed, not close, start over
     
    659968        float_type ylo=F[klo], yhi=F[khi], y2lo=y2[klo], y2hi=y2[khi];
    660969        float_type y=a*ylo+b*yhi+((a*a*a-a)*y2lo+(b*b*b-b)*y2hi)*(h*h)/6.0;
    661        
    662         // template here is impossible! if(fYin && fYin != Identity)
    663         y=fYout(y); // save time by explicitly testing for identity function here
     970
     971        float_type yp0=0; // the derivative in interpolating table coordinates
     972        float_type ypp0=0; // second derivative
    664973       
    665974        if(yprime || yprime2) {
    666                 float_type fpi=1.0/fYinPrime(y);
    667                 float_type gp=fXinPrime(xraw);
    668                 float_type yp0=(yhi-ylo)/h+((3*b*b-1)*y2hi-(3*a*a-1)*y2lo)*h/6.0; // the derivative in interpolating table coordinates
    669                
    670                 // from Mathematica Dt[InverseFunction[f][y[g[x]]], x]
    671                 if(yprime) *yprime=gp*yp0*fpi; // the real derivative of the inverse transformed output
    672                 if(yprime2) {
    673                         float_type ypp0=b*y2hi+a*y2lo;
    674                         float_type fpp=fYinDPrime(y);
    675                         float_type gpp=fXinDPrime(xraw);
    676                         // also from Mathematica Dt[InverseFunction[f][y[g[x]]], {x,2}]
    677                         if(yprime2) *yprime2=(gp*gp*ypp0 + yp0*gpp - gp*gp*yp0*yp0*fpp*fpi*fpi)*fpi;
    678                 }
    679         }
    680        
    681         return y;
    682 }
    683 
    684 template <typename float_type> void interpolating_function<float_type>::set_lower_extrapolation(float_type bound)
     975                yp0=(yhi-ylo)/h+((3*b*b-1)*y2hi-(3*a*a-1)*y2lo)*h/6.0; // the derivative in interpolating table coordinates
     976                ypp0=b*y2hi+a*y2lo; // second derivative
     977        }
     978       
     979        if(fTransform.isIdentity) {
     980                if(yprime) *yprime=yp0;
     981                if(yprime2) *yprime2=ypp0;
     982                return y;       
     983        } else return fTransform.evaluate(xraw, y, yp0, ypp0, yprime, yprime2);
     984}
     985
     986template <typename float_type> void interpolating_function_p<float_type>::set_lower_extrapolation(float_type bound)
    685987{
    686988        int kl = 0 ;
    687989        int kh=kl+1;
    688         float_type xx=fXin(bound);
     990        float_type xx=fTransform.X.fIn(bound);
    689991        float_type h0=X[kh]-X[kl];
    690992        float_type h1=xx-X[kl];
     
    7021004}
    7031005
    704 template <typename float_type> void interpolating_function<float_type>::set_upper_extrapolation(float_type bound)
     1006template <typename float_type> void interpolating_function_p<float_type>::set_upper_extrapolation(float_type bound)
    7051007{
    7061008        int kl = X.size()-2 ;
    7071009        int kh=kl+1;
    708         float_type xx=fXin(bound);
     1010        float_type xx=fTransform.X.fIn(bound);
    7091011        float_type h0=X[kh]-X[kl];
    7101012        float_type h1=xx-X[kl];
     
    7211023}
    7221024
    723 // move derivatives into our internal coordinates (use splint to go the other way!)
    724 template <typename float_type> void interpolating_function<float_type>::localize_derivatives(
    725    float_type xraw, float_type y, float_type yp, float_type ypp, float_type *y0, float_type *yprime, float_type *yprime2) const
    726 {
    727         float_type fp=fYinPrime(y);
    728         float_type gp=fXinPrime(xraw);
    729         float_type fpp=fYinDPrime(y);
    730         float_type gpp=fXinDPrime(xraw);
    731        
    732         if(y0) *y0=fYin(y);
    733         if(yprime) *yprime=yp*fp/gp; // Mathematica Dt[f[y[InverseFunction[g][x]]], x]
    734         if(yprime2) *yprime2=( yp*yp*fpp - fp*yp*gpp/gp + fp*ypp )/(gp*gp) ; // Mathematica Dt[f[y[InverseFunction[g][x]]], {x,2}]
    735 }
    736 
    7371025// return a new interpolating_function which is the unary function of an existing interpolating_function
    7381026// can also be used to generate a resampling of another c2_function on a different grid
     
    7401028// and doing b=a.unary_operator(c) where c is a c2_function (probably another interpolating_function)
    7411029
    742 template <typename float_type> interpolating_function<float_type>&
    743         interpolating_function<float_type>::unary_operator(const c2_function<float_type> &source) const
     1030template <typename float_type> interpolating_function_p<float_type>&
     1031        interpolating_function_p<float_type>::unary_operator(const c2_function<float_type> &source) const
    7441032{
    7451033        size_t np=X.size();
    7461034        std::vector<float_type>yv(np);
    747         c2_composed_function<float_type> comp(source, *this);
     1035        c2_ptr<float_type> comp(source(*this));
    7481036        float_type yp0, yp1, ypp;
    7491037       
    750         for(size_t i=0; i<np; i++) {
    751                 yv[i]=source(fYout(F[i])); // copy pointwise the function of our data values
    752         }
    753                
    754         comp(Xraw.front(), &yp0, &ypp); // get derivative at front
    755         comp(Xraw.back(), &yp1, &ypp); // get derivative at back
    756        
    757         return  *new interpolating_function(Xraw, yv, false, yp0, false, yp1,
    758                                                                            fXin, fXinPrime, fXinDPrime,
    759                                                                            fYin, fYinPrime, fYinDPrime, fYout);
     1038        for(size_t i=1; i<np-1; i++) {
     1039                yv[i]=source(fTransform.Y.fOut(F[i])); // copy pointwise the function of our data values
     1040        }
     1041               
     1042        yv.front()=comp(Xraw.front(), &yp0, &ypp); // get derivative at front
     1043        yv.back()= comp(Xraw.back(), &yp1, &ypp); // get derivative at back
     1044       
     1045        interpolating_function_p &copy=clone();
     1046        copy.load(this->Xraw, yv, false, yp0, false, yp1);
     1047       
     1048        return copy;
    7601049}
    7611050
    7621051template <typename float_type> void
    763 interpolating_function<float_type>::get_data(std::vector<float_type> &xvals, std::vector<float_type> &yvals) const throw()
     1052interpolating_function_p<float_type>::get_data(std::vector<float_type> &xvals, std::vector<float_type> &yvals) const throw()
    7641053{
    7651054       
     
    7671056        yvals.resize(F.size());
    7681057       
    769         for(size_t i=0; i<F.size(); i++) yvals[i]=fYout(F[i]);
    770 }
    771 
    772 template <typename float_type> interpolating_function<float_type> &
    773         interpolating_function<float_type>::binary_operator(const c2_function<float_type> &rhs,
    774                 c2_binary_function<float_type> *combining_stub) const
     1058        for(size_t i=0; i<F.size(); i++) yvals[i]=fTransform.Y.fOut(F[i]);
     1059}
     1060
     1061template <typename float_type> interpolating_function_p<float_type> &
     1062        interpolating_function_p<float_type>::binary_operator(const c2_function<float_type> &rhs,
     1063                const c2_binary_function<float_type> *combining_stub) const
    7751064{       
    7761065        size_t np=X.size();     
    7771066        std::vector<float_type> yv(np);
    778         c2_constant<float_type> fval;
    779         c2_constant<float_type> yval;
     1067        c2_constant_p<float_type> fval(0);
    7801068        float_type yp0, yp1, ypp;
    7811069       
    782         for(size_t i=0; i<np; i++) {
    783                 fval.reset(fYout(F[i])); // update the constant function pointwise
    784                 yval.reset(rhs(Xraw[i]));
    785                 yv[i]=(*combining_stub).combine(fval, yval, Xraw[i], (float_type *)0, (float_type *)0); // compute rhs & combine without derivatives
    786         }
    787        
    788         (*combining_stub).combine(*this, rhs, Xraw.front(), &yp0, &ypp); // get derivative at front
    789         (*combining_stub).combine(*this, rhs, Xraw.back(),  &yp1, &ypp); // get derivative at back
    790 
    791         delete combining_stub;
    792        
    793         return  *new interpolating_function(Xraw, yv, false, yp0, false, yp1,
    794                                                                            fXin, fXinPrime, fXinDPrime,
    795                                                                            fYin, fYinPrime, fYinDPrime, fYout);
    796 }
    797 
    798 template <typename float_type>  float_type c2_f_logprime(float_type x) { return 1.0/x; } // the derivative of log(x)
    799 template <typename float_type>  float_type c2_f_logprime2(float_type x) { return -1.0/(x*x); } // the second derivative of log(x)
    800 
    801 template <typename float_type> log_lin_interpolating_function<float_type>::log_lin_interpolating_function(
    802                                                                                 const std::vector<float_type> &x, const std::vector<float_type> &f,
    803                                                                                 bool lowerSlopeNatural, float_type lowerSlope,
    804                                                                                 bool upperSlopeNatural, float_type upperSlope)
    805                                                                                 : interpolating_function<float_type>()
    806 {
    807         init(x, f, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope,
    808                  (float_type (*)(float_type)) (std::log), c2_f_logprime, c2_f_logprime2, 0, 0, 0, 0);
    809 }
    810 
    811 template <typename float_type> lin_log_interpolating_function<float_type>::lin_log_interpolating_function(
    812                                                                                 const std::vector<float_type> &x, const std::vector<float_type> &f,
    813                                                                                 bool lowerSlopeNatural, float_type lowerSlope,
    814                                                                                 bool upperSlopeNatural, float_type upperSlope)
    815                                                                                 : interpolating_function<float_type>()
    816 {
    817         init(x, f, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope,
    818                  0, 0, 0,
    819                  (float_type (*)(float_type)) (std::log), c2_f_logprime, c2_f_logprime2,
    820                  (float_type (*)(float_type)) (std::exp) );
    821 }
    822 
    823 template <typename float_type> log_log_interpolating_function<float_type>::log_log_interpolating_function(
    824                                                                                 const std::vector<float_type> &x, const std::vector<float_type> &f,
    825                                                                                 bool lowerSlopeNatural, float_type lowerSlope,
    826                                                                                 bool upperSlopeNatural, float_type upperSlope)
    827                                                                                 : interpolating_function<float_type>()
    828 {
    829         init(x, f, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope,
    830                  (float_type (*)(float_type)) (std::log), c2_f_logprime, c2_f_logprime2,
    831                  (float_type (*)(float_type)) (std::log), c2_f_logprime, c2_f_logprime2,
    832                  (float_type (*)(float_type)) (std::exp) );
    833 }
    834 
    835 template <typename float_type> float_type c2_f_recip(float_type x) { return 1.0/x; }
    836 template <typename float_type> float_type c2_f_recipprime(float_type x) { return -1.0/(x*x); } // the derivative of 1/x
    837 template <typename float_type> float_type c2_f_recipprime2(float_type x) { return 2.0/(x*x*x); } // the second derivative of 1/x
    838 
    839 template <typename float_type> arrhenius_interpolating_function<float_type>::arrhenius_interpolating_function(
    840                                                                                 const std::vector<float_type> &x, const std::vector<float_type> &f,
    841                                                                                 bool lowerSlopeNatural, float_type lowerSlope,
    842                                                                                 bool upperSlopeNatural, float_type upperSlope)
    843                                                                                 : interpolating_function<float_type>()
    844 {
    845         init(x, f, lowerSlopeNatural, lowerSlope, upperSlopeNatural, upperSlope,
    846                 c2_f_recip, c2_f_recipprime, c2_f_recipprime2,
    847                 (float_type (*)(float_type)) (std::log), c2_f_logprime, c2_f_logprime2,
    848                 (float_type (*)(float_type)) (std::exp) );
    849 }
    850 
    851 template <typename float_type> c2_inverse_function<float_type>::c2_inverse_function(const c2_function<float_type> &source)
    852         : c2_plugin_function<float_type>(source)
     1070        c2_const_ptr<float_type> stub(*combining_stub);  // manage ownership
     1071       
     1072        for(size_t i=1; i<np-1; i++) {
     1073                fval.reset(fTransform.Y.fOut(F[i])); // update the constant function pointwise
     1074                yv[i]=combining_stub->combine(fval, rhs, Xraw[i], (float_type *)0, (float_type *)0); // compute rhs & combine without derivatives
     1075        }
     1076       
     1077        yv.front()=combining_stub->combine(*this, rhs, Xraw.front(), &yp0, &ypp); // get derivative at front
     1078        yv.back()= combining_stub->combine(*this, rhs, Xraw.back(),  &yp1, &ypp); // get derivative at back
     1079       
     1080        interpolating_function_p &copy=clone();
     1081        copy.load(this->Xraw, yv, false, yp0, false, yp1);
     1082       
     1083        return copy;
     1084}
     1085
     1086template <typename float_type> c2_inverse_function_p<float_type>::c2_inverse_function_p(const c2_function<float_type> &source)
     1087        : c2_function<float_type>(), func(source)
    8531088{
    8541089        float_type l=source.xmin();
     
    8641099}
    8651100
    866 template <typename float_type> float_type c2_inverse_function<float_type>::value_with_derivatives(
     1101template <typename float_type> float_type c2_inverse_function_p<float_type>::value_with_derivatives(
    8671102                                        float_type x, float_type *yprime, float_type *yprime2
    8681103                        ) const throw(c2_exception)
     
    9271162                for(int i=0; i<=np; i++) cum[i]*=m;
    9281163        }
    929         if(inverse_function) interpolating_function<float_type>(cum, be); // use cum as x axis in inverse function
    930         else interpolating_function<float_type>(be, cum); // else use lower bin edge as x axis
     1164        if(inverse_function) interpolating_function_p<float_type>(cum, be); // use cum as x axis in inverse function
     1165        else interpolating_function_p<float_type>(be, cum); // else use lower bin edge as x axis
    9311166        std::fill(this->y2.begin(), this->y2.end(), 0.0); // clear second derivatives, to we are piecewise linear
    9321167}
    9331168
    934 template <typename float_type> c2_piecewise_function<float_type>::c2_piecewise_function()
     1169template <typename float_type> c2_piecewise_function_p<float_type>::c2_piecewise_function_p()
    9351170: c2_function<float_type>(), lastKLow(-1)
    9361171{
     
    9381173}
    9391174
    940 template <typename float_type> c2_piecewise_function<float_type>::~c2_piecewise_function()
    941 {
    942         size_t np=functions.size();
    943         for(size_t i=0; i<np; i++) if(owns[i]) delete functions[i];
    944 }
    945 
    946 template <typename float_type> float_type c2_piecewise_function<float_type>::value_with_derivatives(
     1175template <typename float_type> c2_piecewise_function_p<float_type>::~c2_piecewise_function_p()
     1176{
     1177}
     1178
     1179template <typename float_type> float_type c2_piecewise_function_p<float_type>::value_with_derivatives(
    9471180                  float_type x, float_type *yprime, float_type *yprime2
    9481181                  ) const throw(c2_exception)
     
    9741207}
    9751208
    976 template <typename float_type> void c2_piecewise_function<float_type>::append_function(
    977         c2_function<float_type> &func, bool pass_ownership) throw(c2_exception)
    978 {
     1209template <typename float_type> void c2_piecewise_function_p<float_type>::append_function(
     1210        const c2_function<float_type> &func) throw(c2_exception)
     1211{
     1212        c2_const_ptr<float_type> keepfunc(func);  //  manage function before we can throw any exceptions
    9791213        if(functions.size()) { // check whether there are any gaps to fill, etc.
    980                 c2_function<float_type> &tail=*(functions.back());
     1214                const c2_function<float_type> &tail=functions.back();
    9811215                float_type x0=tail.xmax();
    9821216                float_type x1=func.xmin();
     
    9851219                        float_type y0=tail(x0);
    9861220                        float_type y1=func(x1);
    987                         c2_function<float_type> *connector=new c2_linear<float_type>(x0, y0, (y1-y0)/(x1-x0));
    988                         connector->set_domain(x0,x1);
    989                         functions.push_back(connector);
    990                         owns.push_back(true);
     1221                        c2_function<float_type> &connector=*new c2_linear_p<float_type>(x0, y0, (y1-y0)/(x1-x0));
     1222                        connector.set_domain(x0,x1);
     1223                        functions.push_back(c2_const_ptr<float_type>(connector));
    9911224                        this->sampling_grid->push_back(x1);
    9921225                } else if(x0>x1) throw c2_exception("function domains not increasing in c2_piecewise_function");
    9931226        }
    994         functions.push_back(&func);
    995         owns.push_back(pass_ownership);
     1227        functions.push_back(keepfunc);
    9961228        // extend our domain to include all known functions
    9971229        this->set_domain(functions.front()->xmin(), functions.back()->xmax());
    9981230        // extend our sampling grid with the new function's grid, with the first point dropped to avoid duplicates
    999         std::vector<float_type> &newgrid=func.get_sampling_grid(func.xmin(), func.xmax());
     1231        std::vector<float_type> newgrid;
     1232        func.get_sampling_grid(func.xmin(), func.xmax(), newgrid);
    10001233        this->sampling_grid->insert(this->sampling_grid->end(), newgrid.begin()+1, newgrid.end());
    1001         delete &newgrid;
    1002 }
    1003 
    1004 template <typename float_type> c2_connector_function<float_type>::c2_connector_function(
    1005         const c2_function<float_type> &f1, const c2_function<float_type> &f2, float_type x0, float_type x2,
     1234}
     1235
     1236template <typename float_type> c2_connector_function_p<float_type>::c2_connector_function_p(
     1237        float_type x0, const c2_function<float_type> &f0, float_type x2, const c2_function<float_type> &f2,
    10061238        bool auto_center, float_type y1)
    1007 
    1008 : c2_function<float_type>()
    1009 {
    1010         float_type y0, yp0, ypp0, y2, yp2, ypp2;
    1011         fdx=(x2-x0)/2.0;
    1012         fhinv=1.0/fdx;
    1013         fx1=(x0+x2)/2.0;
    1014        
    1015         y0=f1.value_with_derivatives(x0, &yp0, &ypp0); // get left wall values from conventional computation
    1016         y2=f2.value_with_derivatives(x2, &yp2, &ypp2); // get right wall values from conventional computation
     1239        : c2_function<float_type>()
     1240{
     1241        c2_const_ptr<float_type> left(f0), right(f2); // make sure if these are unowned, they get deleted
     1242        c2_fblock<float_type> fb0, fb2;
     1243        fb0.x=x0;
     1244        f0.fill_fblock(fb0);
     1245        fb2.x=x2;
     1246        f2.fill_fblock(fb2);
     1247        init(fb0, fb2, auto_center, y1);
     1248}
     1249
     1250template <typename float_type> c2_connector_function_p<float_type>::c2_connector_function_p(
     1251        float_type x0, float_type y0, float_type yp0, float_type ypp0,
     1252        float_type x2, float_type y2, float_type yp2, float_type ypp2,
     1253        bool auto_center, float_type y1)
     1254        : c2_function<float_type>()
     1255{
     1256        c2_fblock<float_type> fb0, fb2;
     1257        fb0.x=x0; fb0.y=y0; fb0.yp=yp0; fb0.ypp=ypp0;
     1258        fb2.x=x2; fb2.y=y2; fb2.yp=yp2; fb2.ypp=ypp2;   
     1259        init(fb0, fb2, auto_center, y1);
     1260}
     1261
     1262template <typename float_type> c2_connector_function_p<float_type>::c2_connector_function_p(
     1263        const c2_fblock<float_type> &fb0,
     1264        const c2_fblock<float_type> &fb2,
     1265        bool auto_center, float_type y1)
     1266        : c2_function<float_type>()
     1267{
     1268        init(fb0, fb2, auto_center, y1);
     1269}
     1270
     1271template <typename float_type> void c2_connector_function_p<float_type>::init(
     1272        const c2_fblock<float_type> &fb0,
     1273        const c2_fblock<float_type> &fb2,
     1274        bool auto_center, float_type y1)
     1275{
     1276        float_type dx=(fb2.x-fb0.x)/2.0;
     1277        fhinv=1.0/dx;
    10171278
    10181279        // scale derivs to put function on [-1,1] since mma  solution is done this way
    1019         yp0*=fdx;
    1020         yp2*=fdx;
    1021         ypp0*=fdx*fdx;
    1022         ypp2*=fdx*fdx;
    1023        
    1024         float_type ff0=(8*(y0 + y2) + 5*(yp0 - yp2) + ypp0 + ypp2)/16.0;
     1280        float_type yp0=fb0.yp*dx;
     1281        float_type yp2=fb2.yp*dx;
     1282        float_type ypp0=fb0.ypp*dx*dx;
     1283        float_type ypp2=fb2.ypp*dx*dx;
     1284       
     1285        float_type ff0=(8*(fb0.y + fb2.y) + 5*(yp0 - yp2) + ypp0 + ypp2)*0.0625;
    10251286        if(auto_center) y1=ff0; // forces ff to be 0 if we are auto-centering
    10261287       
    1027         // y[x_] = y1 + x (a + b x) + (x-1) x (x+1) (c + d x + e x^2 + f x^3)
     1288        // y[x_] = y1 + x (a + b x) + x [(x-1) (x+1)] (c + d x) + x (x-1)^2 (x+1)^2 (e + f x)
     1289        // y' = a + 2 b x + d x [(x+1)(x-1)] + (c + d x)(3x^2-1) + f x [(x+1)(x-1)]^2 + (e + f x)[(x+1)(x-1)](5x^2-1) 
     1290        // y'' = 2 b + 6x(c + d x) + 2d(3x^2-1) + 4x(e + f x)(5x^2-3) + 2f(x^2-1)(5x^2-1)
    10281291        fy1=y1;
    1029         fa=-(y0 - y2)/2.;
    1030         fb=(y0 - 2*y1 + y2)/2.;
    1031         fc=(7*(y0 - y2 + yp0 + yp2) + ypp0 - ypp2)/16.;
    1032         fd=(32*y1 - 16*(y2 + y0) + 9*(yp2 - yp0) - ypp0 - ypp2)/16.;
    1033         fe=(3*(y2 - y0 - yp0 - yp2) - ypp0 + ypp2)/16.;
     1292        fa=(fb2.y - fb0.y)*0.5;
     1293        fb=(fb0.y + fb2.y)*0.5 - y1;
     1294        fc=(yp2+yp0-2.*fa)*0.25;
     1295        fd=(yp2-yp0-4.*fb)*0.25;
     1296        fe=(ypp2-ypp0-12.*fc)*0.0625;
    10341297        ff=(ff0 - y1);
    1035         // y'[x] = a + 2 b x + (3x^2 - 1)   (c + d x + e x^2 + f x^3) + (x-1) x (x+1) (d + 2 e x + 3 f x^2 )
    1036         // y''[x] = 2b + (x-1) x (x+1) (2 e + 6 f x) + 2 (3 x^2 -1) (d + 2 e x + 3 f x^2 ) + 6 x (c + d x + e x^2 + f x^3)
    1037         this->set_domain(x0,x2); // this is where the function is valid
    1038 }
    1039 
    1040 template <typename float_type> c2_connector_function<float_type>::~c2_connector_function()
    1041 {
    1042 }
    1043 
    1044 template <typename float_type> float_type c2_connector_function<float_type>::value_with_derivatives(
     1298        this->set_domain(fb0.x, fb2.x); // this is where the function is valid
     1299}
     1300
     1301template <typename float_type> c2_connector_function_p<float_type>::~c2_connector_function_p()
     1302{
     1303}
     1304
     1305template <typename float_type> float_type c2_connector_function_p<float_type>::value_with_derivatives(
    10451306        float_type x, float_type *yprime, float_type *yprime2
    10461307        ) const throw(c2_exception)
    10471308{
    1048                                                                                                                                                                                                        
    1049         float_type dx=(x-fx1)*fhinv;
    1050         float_type q1=fc + dx*(fd + dx*(fe + dx*ff));
    1051         float_type xp1=(dx-1)*(dx+1)*dx;
    1052        
    1053         float_type y= fy1 + dx*(fa+fb*dx) + xp1*q1;
     1309        float_type x0=this->xmin(), x2=this->xmax();
     1310        float_type dx=(x-(x0+x2)*0.5)*fhinv;
     1311        float_type q1=(x-x0)*(x-x2)*fhinv*fhinv; // exactly vanish all bits at both ends
     1312        float_type q2=dx*q1;
     1313       
     1314        float_type r1=fa+fb*dx;
     1315        float_type r2=fc+fd*dx;
     1316        float_type r3=fe+ff*dx;
     1317       
     1318        float_type y=fy1+dx*r1+q2*r2+q1*q2*r3;
     1319       
    10541320        if(yprime || yprime2) {
    1055                 float_type q2 =fd + dx*(2*fe + dx*3*ff);       
    1056                 float_type q3=2*fe+6*ff*dx;
    1057                 float_type xp2=(3*dx*dx-1);
    1058                 if(yprime) *yprime=(fa + 2*fb*dx + xp2*q1 + xp1*q2)*fhinv;
    1059                 if(yprime2) *yprime2=(2*fb+xp1*q3+2*xp2*q2+6*dx*q1)*fhinv*fhinv;
     1321                float_type q3=3*q1+2;
     1322                float_type q4=5*q1+4;
     1323                if(yprime) *yprime=(fa+2*fb*dx+fd*q2+r2*q3+ff*q1*q2+q1*q4*r3)*fhinv;
     1324                if(yprime2) *yprime2=2*(fb+fd*q3+3*dx*r2+ff*q1*q4+r3*(2*dx*(5*q1+2)))*fhinv*fhinv;
    10601325        }
    10611326        return y;
    10621327}
     1328
     1329// the recursive part of the sampler is agressively designed to minimize copying of data... lots of pointers
     1330template <typename float_type> void c2_function<float_type>::sample_step(c2_sample_recur &rb) const throw(c2_exception)
     1331{
     1332        std::vector< recur_item > &rb_stack=*rb.rb_stack; // heap-based stack of data for recursion
     1333        rb_stack.clear();
     1334       
     1335        recur_item top;
     1336        top.depth=0; top.done=false; top.f0index=0; top.f2index=0;
     1337       
     1338        // push storage for our initial elements
     1339        rb_stack.push_back(top);
     1340        rb_stack.back().f1=*rb.f0;
     1341        rb_stack.back().done=true;
     1342
     1343        rb_stack.push_back(top);
     1344        rb_stack.back().f1=*rb.f1;
     1345        rb_stack.back().done=true;
     1346       
     1347        if(!rb.inited) {
     1348                rb.dx_tolerance=10.0*std::numeric_limits<float_type>::epsilon();
     1349                rb.abs_tol_min=10.0*std::numeric_limits<float_type>::min();
     1350                rb.inited=true;
     1351        }
     1352
     1353        // now, push our first real element
     1354        top.f0index=0; // left element is stack[0]
     1355        top.f2index=1; // right element is stack[1]
     1356        rb_stack.push_back(top);
     1357
     1358        while(rb_stack.size() > 2) {
     1359                recur_item &back=rb_stack.back();
     1360                if(back.done) {
     1361                        rb_stack.pop_back();
     1362                        continue;
     1363                }
     1364                back.done=true;
     1365
     1366                c2_fblock<float_type> &f0=rb_stack[back.f0index].f1, &f2=rb_stack[back.f2index].f1;
     1367                c2_fblock<float_type> &f1=back.f1; // will hold new middle values
     1368                size_t f1index=rb_stack.size()-1; // our current offset
     1369
     1370                // std::cout << "processing: " << rb_stack.size() << " " <<
     1371                // (&back-&rb_stack.front())  << " " << back.depth << " " << f0.x << " " << f2.x << std::endl;
     1372
     1373                f1.x=0.5*(f0.x + f2.x); // center of interval
     1374                float_type dx2=0.5*(f2.x - f0.x);
     1375                       
     1376                // check for underflow on step size, which prevents us from achieving specified accuracy.
     1377                if(std::abs(dx2) < std::abs(f1.x)*rb.dx_tolerance || std::abs(dx2) < rb.abs_tol_min) {
     1378                        std::ostringstream outstr;
     1379                        outstr << "Step size underflow in adaptive_sampling at depth=" << back.depth << ", x= " << f1.x;
     1380                        throw c2_exception(outstr.str().c_str());
     1381                }
     1382               
     1383                fill_fblock(f1);
     1384               
     1385                if(c2_isnan(f1.y) || f1.ypbad || f1.yppbad) {
     1386                        // can't go any further if a nan has appeared
     1387                        bad_x_point=f1.x;
     1388                        throw c2_exception("NaN encountered while sampling function");
     1389                }
     1390
     1391                float_type eps;
     1392                if(rb.derivs==2) {
     1393                        // this is code from connector_function to compute the value at the midpoint
     1394                        // it is re-included here to avoid constructing a complete c2connector
     1395                        // just to find out if we are close enough
     1396                        float_type ff0=(8*(f0.y + f2.y) + 5*(f0.yp - f2.yp)*dx2 + (f0.ypp+f2.ypp)*dx2*dx2)*0.0625;
     1397                        // we are converging as at least x**5 and bisecting, so real error on final step is smaller
     1398                        eps=std::abs(ff0-f1.y)/32.0;   
     1399                } else {
     1400                        // there are two tolerances to meet... the shift in the estimate of the actual point,
     1401                        // and the difference between the current points and the extremum
     1402                        // build all the coefficients needed to construct the local parabola
     1403                        float_type ypcenter, ypp;
     1404                        if (rb.derivs==1) {
     1405                                // linear extrapolation error using exact derivs
     1406                                eps = (std::abs(f0.y+f0.yp*dx2-f1.y)+std::abs(f2.y-f2.yp*dx2-f1.y))*0.125;
     1407                                ypcenter=2*f1.yp*dx2; // first deriv scaled so this interval is on [-1,1]
     1408                                ypp=2*(f2.yp-f0.yp)*dx2*dx2; // second deriv estimate scaled so this interval is on [-1,1]
     1409                        } else {
     1410                                // linear interpolation error without derivs if we are at top level
     1411                                //  or 3-point parabolic interpolation estimates from previous level, if available
     1412                                ypcenter=(f2.y-f0.y)*0.5; // derivative estimate at center
     1413                                ypp=(f2.y+f0.y-2*f1.y); // second deriv estimate
     1414                                if(back.depth==0) eps=std::abs((f0.y+f2.y)*0.5 - f1.y)*2; // penalize first step
     1415                                else eps=std::abs(f1.y-back.previous_estimate)*0.25;
     1416                        }
     1417                        float_type ypleft=ypcenter-ypp; // derivative at left edge
     1418                        float_type ypright=ypcenter+ypp; // derivative at right edge
     1419                        float_type extremum_eps=0;
     1420                        if((ypleft*ypright) <=0) // y' changes sign if we have an extremum
     1421                        {
     1422                                // compute position and value of the extremum this way
     1423                                float_type xext=-ypcenter/ypp;
     1424                                float_type yext=f1.y + xext*ypcenter + 0.5*xext*xext*ypp;
     1425                                // and then find the the smallest offset of it from a point, looking in the left or right side
     1426                                if(xext <=0) extremum_eps=std::min(std::abs(f0.y-yext), std::abs(f1.y-yext));
     1427                                else extremum_eps=std::min(std::abs(f2.y-yext), std::abs(f1.y-yext));
     1428                        }
     1429                        eps=std::max(eps, extremum_eps); // if previous shot was really bad, keep trying
     1430                }
     1431               
     1432                if(eps < rb.abs_tol ||  eps < std::abs(f1.y)*rb.rel_tol) {
     1433                        if(rb.out) {
     1434                                // we've met the tolerance, and are building a function, append two connectors
     1435                                rb.out->append_function(
     1436                                        *new c2_connector_function_p<float_type>(f0, f1, true, 0.0)
     1437                                );
     1438                                rb.out->append_function(
     1439                                        *new c2_connector_function_p<float_type>(f1, f2, true, 0.0)
     1440                                );
     1441                        }
     1442                        if(rb.xvals && rb.yvals) {
     1443                                rb.xvals->push_back(f0.x);
     1444                                rb.xvals->push_back(f1.x);
     1445                                rb.yvals->push_back(f0.y);
     1446                                rb.yvals->push_back(f1.y);
     1447                                // the value at f2 will get pushed in the next segment... it is not forgotten
     1448                        }
     1449                } else {
     1450                        top.depth=back.depth+1; // increment depth counter
     1451
     1452                        // save the last things we need from back before a push happens, in case
     1453                        // the push causes a reallocation and moves the whole stack.
     1454                        size_t f0index=back.f0index, f2index=back.f2index;
     1455                        float_type left=0, right=0;
     1456                        if(rb.derivs==0) {
     1457                                // compute three-point parabolic interpolation estimate of right-hand and left-hand midpoint
     1458                                left=(6*f1.y + 3*f0.y - f2.y) * 0.125;
     1459                                right=(6*f1.y + 3*f2.y - f0.y) * 0.125;
     1460                        }
     1461                       
     1462                        top.f0index=f1index; top.f2index=f2index; // insert pointers to right side data into our recursion block                       
     1463                        top.previous_estimate=right;
     1464                        rb_stack.push_back(top);
     1465
     1466                        top.f0index=f0index; top.f2index=f1index; // insert pointers to left side data into our recursion block
     1467                        top.previous_estimate=left;
     1468                        rb_stack.push_back(top);
     1469                }
     1470        }
     1471}
     1472
     1473template <typename float_type>  c2_piecewise_function_p<float_type> *
     1474        c2_function<float_type>::adaptively_sample(
     1475                float_type xmin, float_type xmax,
     1476                float_type abs_tol, float_type rel_tol,
     1477                int derivs, std::vector<float_type> *xvals, std::vector<float_type> *yvals) const throw(c2_exception)
     1478{
     1479        c2_fblock<float_type> f0, f2;
     1480        c2_sample_recur rb;
     1481        std::vector< recur_item > rb_stack;
     1482        rb_stack.reserve(20); // enough for most operations
     1483        rb.rb_stack=&rb_stack;
     1484        rb.out=0;
     1485        if(derivs==2) rb.out=new c2_piecewise_function_p<float_type>();
     1486        c2_ptr<float_type> pieces(*rb.out); // manage this function, if any, so it deletes on an exception
     1487        rb.rel_tol=rel_tol;
     1488        rb.abs_tol=abs_tol;
     1489        rb.xvals=xvals;
     1490        rb.yvals=yvals;
     1491        rb.derivs=derivs;
     1492        rb.inited=false;
     1493       
     1494        if(xvals && yvals) {
     1495                xvals->clear();
     1496                yvals->clear();
     1497        }
     1498         
     1499        // create xgrid as a automatic-variable copy of the sampling grid so the exception handler correctly
     1500        // disposes of it.
     1501        std::vector<float_type> xgrid;
     1502        get_sampling_grid(xmin, xmax, xgrid);
     1503        int np=xgrid.size();     
     1504
     1505        f2.x=xgrid[0];
     1506        fill_fblock(f2);
     1507        if(c2_isnan(f2.y) || f2.ypbad || f2.yppbad) {
     1508                // can't go any further if a nan has appeared
     1509                bad_x_point=f2.x;
     1510                throw c2_exception("NaN encountered while sampling function");
     1511        }
     1512
     1513        for(int i=0; i<np-1; i++) {
     1514                f0=f2; // copy upper bound to lower before computing new upper bound
     1515
     1516                f2.x=xgrid[i+1];
     1517                fill_fblock(f2);
     1518                if(c2_isnan(f2.y) || f2.ypbad || f2.yppbad) {
     1519                        // can't go any further if a nan has appeared
     1520                        bad_x_point=f2.x;
     1521                        throw c2_exception("NaN encountered while sampling function");
     1522                }
     1523
     1524                rb.f0=&f0; rb.f1=&f2;
     1525                sample_step(rb);
     1526        }
     1527        if(xvals && yvals) { // push final point in vector
     1528                xvals->push_back(f2.x);
     1529                yvals->push_back(f2.y);
     1530        }
     1531       
     1532        if(rb.out) rb.out->set_sampling_grid(xgrid); // reflect old sampling grid, which still should be right
     1533        pieces.release_for_return(); // unmanage the piecewise_function so we can return it
     1534        return rb.out;
     1535}
     1536
     1537template <typename float_type, typename Final>
     1538 interpolating_function_p<float_type> & inverse_integrated_density_function(
     1539        const std::vector<float_type> &bincenters, const c2_function<float_type> &binheights)
     1540        throw(c2_exception)
     1541{       
     1542        return (new Final())->load_random_generator_function(bincenters, binheights);
     1543}
     1544
     1545template <typename float_type, typename Final>
     1546        interpolating_function_p<float_type> & inverse_integrated_density_bins(
     1547        const std::vector<float_type> &bins, const std::vector<float_type> &binheights)
     1548        throw(c2_exception)
     1549{       
     1550        return (new Final())->load_random_generator_bins(bins, binheights);
     1551}
Note: See TracChangeset for help on using the changeset viewer.