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

update to geant4.9.3

Location:
trunk/examples/extended/electromagnetic/TestEm7
Files:
47 edited

Legend:

Unmodified
Added
Removed
  • trunk/examples/extended/electromagnetic/TestEm7/GNUmakefile

    r807 r1230  
    1 # $Id: GNUmakefile,v 1.9 2007/06/22 12:44:42 maire Exp $
     1# $Id: GNUmakefile,v 1.11 2008/09/21 16:03:10 vnivanch Exp $
    22# --------------------------------------------------------------
    33# GNUmakefile for examples module.  Gabriele Cosmo, 06/04/98.
     
    1717#### G4ANALYSIS_USE := true
    1818
    19 ifdef G4ANALYSIS_USE
    20   CPPFLAGS += -DG4ANALYSIS_USE
    21 endif
    22 
    2319include $(G4INSTALL)/config/architecture.gmk
    24 
    25 ifdef G4ANALYSIS_USE
    26   # for the aida-config command see the README file
    27   CPPFLAGS += `aida-config --include`
    28   LOADLIBS += `aida-config --lib`
    29 endif
    3020
    3121include $(G4INSTALL)/config/binmake.gmk
     
    3626
    3727histclean:
    38         rm ${G4WORKDIR}/tmp/${G4SYSTEM}/${G4TARGET}/RunAction.o
     28        rm ${G4WORKDIR}/tmp/${G4SYSTEM}/${G4TARGET}/Histo.o
  • trunk/examples/extended/electromagnetic/TestEm7/TestEm7.cc

    r807 r1230  
    2525//
    2626// $Id: TestEm7.cc,v 1.8 2007/06/22 12:44:42 maire 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/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}
  • trunk/examples/extended/electromagnetic/TestEm7/ionC12.mac

    r807 r1230  
    1 # $Id: ionC12.mac,v 1.19 2007/11/07 19:41:32 vnivanch Exp $
     1# $Id: ionC12.mac,v 1.22 2008/10/24 15:36:24 maire Exp $
    22#
    33# Macro file for "TestEm7.cc"
     
    77/control/verbose 2
    88/run/verbose 2
    9 /tracking/verbose 1
     9/tracking/verbose 0
    1010#
    11 /testem/det/setMat Water
     11/testem/det/setMat G4_WATER
    1212/testem/det/setSizeX  20 cm
    1313/testem/det/setSizeYZ 20 cm
    1414#
    15 /testem/det/tallyMat Water
     15/testem/det/tallyMat G4_WATER
    1616/testem/det/tallySize 2. 2. 2. mm
    1717/testem/det/tallyPosition -9.9 0. 0. cm
     
    2020/testem/det/tallyPosition  5.  0. 0. cm
    2121#
    22 /testem/phys/addPhysics  standardNR     
    23 #/testem/phys/addPhysics  emstandard
    24 #/testem/phys/addPhysics  standard_opt2
     22#/testem/phys/addPhysics  standardNR   
     23/testem/phys/addPhysics  emstandard
     24#/testem/phys/addPhysics  emstandard_opt2
    2525#
    2626/run/initialize
     
    2929/gun/ion 6 12 6
    3030#/gun/ion 6 12 1
    31 /gun/energy 3.5 GeV
     31/gun/energy 2.4 GeV
    3232#
    3333# beam size
    34 /testem/gun/rndm 2 mm
     34#/testem/gun/rndm 2 mm
    3535#
    3636# step limit
    37 /testem/stepMax 1 mm
     37/testem/phys/setCuts 0.5 mm
     38#/testem/stepMax 0.1 mm
    3839#
    3940/testem/event/printModulo 1000
    4041#
     42/testem/histo/fileName c12
     43/testem/histo/fileType root
     44/testem/histo/setHisto 1 100 80 90
     45/testem/histo/setHisto 2 100 80 90
     46#
    4147/run/beamOn 1000
  • trunk/examples/extended/electromagnetic/TestEm7/proton.mac

    r807 r1230  
    1 # $Id: proton.mac,v 1.10 2007/07/28 16:39:31 vnivanch Exp $
     1# $Id: proton.mac,v 1.17 2008/10/24 15:36:24 maire Exp $
    22#
    33# Macro file for "TestEm7.cc"
     
    88/run/verbose 2
    99#
    10 /testem/det/setMat Water
     10/testem/det/setMat G4_WATER
    1111/testem/det/setSizeX  10 cm
    1212/testem/det/setSizeYZ 10 cm
     13/testem/det/tallyMat G4_WATER
    1314#
    14 /testem/phys/addPhysics  standard       #em physics
     15#/testem/phys/addPhysics  standard
     16/testem/phys/addPhysics  emstandard_opt3
    1517#
    1618/run/initialize
     
    2022#
    2123# step limit
    22 /testem/stepMax 0.5 mm
     24#/testem/phys/setCuts 0.5 mm
     25/testem/phys/setCuts 1 mm
     26#/testem/stepMax 0.5 mm
    2327#
    2428/testem/event/printModulo 1000
    2529#
     30/testem/histo/fileName p100opt3cut1
     31/testem/histo/fileType root
     32/testem/histo/setHisto 1 100 70 80
     33/testem/histo/setHisto 2 100 70 80
     34#
    2635/run/beamOn 10000
     36#
  • trunk/examples/extended/electromagnetic/TestEm7/snr.mac

    r807 r1230  
    1 # $Id: snr.mac,v 1.1 2007/12/19 19:21:41 vnivanch Exp $
     1# $Id: snr.mac,v 1.3 2008/05/08 11:20:50 vnivanch Exp $
    22#
    33# Macro file for "TestEm7.cc"
     
    1919/testem/det/tallyPosition  5.  0. 0. cm
    2020#
    21 /testem/phys/addPhysics  standardNR     # use screened nuclear recoil 
    22 ###/testem/phys/addPhysics  binary      # hadronic physics
     21#/testem/phys/addPhysics  emstandard
     22#/testem/phys/addPhysics  emstandard_opt2
     23#/testem/phys/addPhysics  emstandard_opt3 
     24/testem/phys/addPhysics  standardNR       
     25#/testem/phys/addPhysics  standardIG 
     26###/testem/phys/addPhysics  binary
    2327#
    2428/run/initialize
     
    4044/run/beamOn 1000
    4145#
    42 /testem/det/setMat G4_Cu
    43 /testem/det/update
    44 /gun/particle kaon+
    45 /gun/energy 100 MeV
    46 /run/beamOn 1000
  • trunk/examples/extended/electromagnetic/TestEm7/src/DetectorConstruction.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: DetectorConstruction.cc,v 1.8 2007/01/11 15:41:46 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: DetectorConstruction.cc,v 1.10 2008/04/21 13:13:30 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    4545
    4646#include "G4NistManager.hh"
    47 
    4847#include "G4UnitsTable.hh"
     48
     49#include "G4FieldManager.hh"
     50#include "G4TransportationManager.hh"
     51#include "G4RunManager.hh"
    4952
    5053//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    117120  Air->AddElement(N, fractionmass=0.7);
    118121  Air->AddElement(O, fractionmass=0.3);
     122
     123  density     = 1.e-5*g/cm3;
     124  pressure    = 2.e-2*bar;
     125  temperature = STP_Temperature;  // From PhysicalConstants.h .
     126  G4Material* vac = new G4Material( "TechVacuum", density, 1,
     127                           kStateGas, temperature, pressure );
     128  vac->AddMaterial( Air, 1. );
    119129
    120130  density     = universe_mean_density;    //from PhysicalConstants.h
     
    235245{
    236246  absorSizeX = value; worldSizeX = 1.2*absorSizeX;
     247  G4RunManager::GetRunManager()->GeometryHasBeenModified();
    237248}
    238249 
     
    243254  absorSizeYZ = value;
    244255  worldSizeYZ = 1.2*absorSizeYZ;
     256  G4RunManager::GetRunManager()->GeometryHasBeenModified();
    245257
    246258
     
    252264  G4Material* pttoMaterial =
    253265    G4NistManager::Instance()->FindOrBuildMaterial(materialChoice);
    254   if (pttoMaterial) absorMaterial = pttoMaterial;
    255 }
    256 
    257 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    258 
    259 #include "G4FieldManager.hh"
    260 #include "G4TransportationManager.hh"
     266  if (pttoMaterial) {
     267    absorMaterial = pttoMaterial;
     268    if(lAbsor) {
     269      lAbsor->SetMaterial(absorMaterial);
     270      G4RunManager::GetRunManager()->PhysicsHasBeenModified();
     271    }
     272  }
     273}
     274
     275//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    261276
    262277void DetectorConstruction::SetMagField(G4double fieldValue)
     
    285300{
    286301  tallySize = value;
     302  G4RunManager::GetRunManager()->GeometryHasBeenModified();
    287303
    288304
     
    294310  G4Material* pttoMaterial =
    295311    G4NistManager::Instance()->FindOrBuildMaterial(materialChoice);
    296   if (pttoMaterial) tallyMaterial = pttoMaterial;
     312  if (pttoMaterial) {
     313    tallyMaterial = pttoMaterial;
     314    if(lTally) {
     315      lTally->SetMaterial(tallyMaterial);
     316      G4RunManager::GetRunManager()->PhysicsHasBeenModified();
     317    }
     318  }
    297319}
    298320
     
    305327    tallyNumber++;
    306328  }
     329  G4RunManager::GetRunManager()->GeometryHasBeenModified();
    307330
    308331
    309332//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    310 
    311 #include "G4RunManager.hh"
    312333 
    313334void DetectorConstruction::UpdateGeometry()
    314335{
    315 G4RunManager::GetRunManager()->DefineWorldVolume(ConstructVolumes());
    316 }
    317 
    318 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     336  G4RunManager::GetRunManager()->PhysicsHasBeenModified();
     337  G4RunManager::GetRunManager()->DefineWorldVolume(ConstructVolumes());
     338}
     339
     340//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • trunk/examples/extended/electromagnetic/TestEm7/src/DetectorMessenger.cc

    r807 r1230  
    2525//
    2626// $Id: DetectorMessenger.cc,v 1.3 2006/06/29 16:58:13 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/src/EventAction.cc

    r807 r1230  
    2525//
    2626// $Id: EventAction.cc,v 1.4 2006/06/29 16:58:15 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/src/EventActionMessenger.cc

    r807 r1230  
    2525//
    2626// $Id: EventActionMessenger.cc,v 1.4 2006/06/29 16:58:17 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/src/G4ScreenedNuclearRecoil.cc

    r807 r1230  
    2525//
    2626//
    27 // $Id: G4ScreenedNuclearRecoil.cc,v 1.5 2008/01/14 12:11:39 vnivanch Exp $
    28 // GEANT4 tag $Name:  $
     27// G4ScreenedNuclearRecoil.cc,v 1.57 2008/05/07 11:51:26 marcus Exp
     28// GEANT4 tag
    2929//
    3030//
     
    8484#include "G4ScreenedNuclearRecoil.hh"
    8585
     86const char* G4ScreenedCoulombCrossSectionInfo::CVSFileVers() { return
     87        "G4ScreenedNuclearRecoil.cc,v 1.57 2008/05/07 11:51:26 marcus Exp GEANT4 tag ";
     88}
     89
    8690#include "G4ParticleTypes.hh"
    8791#include "G4ParticleTable.hh"
    8892#include "G4VParticleChange.hh"
    89 #include "G4ParticleChange.hh"
     93#include "G4ParticleChangeForLoss.hh"
    9094#include "G4DataVector.hh"
    9195#include "G4Track.hh"
     
    99103#include "G4IsotopeVector.hh"
    100104
     105#include "G4EmProcessSubType.hh"
     106
    101107#include "G4RangeTest.hh"
    102108#include "G4ParticleDefinition.hh"
     
    104110#include "G4ProcessManager.hh"
    105111#include "G4StableIsotopes.hh"
     112#include "G4LindhardPartition.hh"
    106113
    107114#include "Randomize.hh"
     
    112119#include <iomanip>
    113120
     121#include "c2_factory.hh"
     122static c2_factory<G4double> c2; // this makes a lot of notation shorter
     123typedef c2_ptr<G4double> c2p;
     124
    114125G4ScreenedCoulombCrossSection::~G4ScreenedCoulombCrossSection()
    115126{
    116         ScreeningMap::iterator tables=screeningData.begin();
    117         for (;tables != screeningData.end(); tables++) {
    118                 delete (*tables).second.EMphiData;
    119         }
    120127        screeningData.clear();
    121        
    122         std::map<G4int, c2_function<G4double> *>::iterator mfpit=MFPTables.begin();
    123         for (;mfpit != MFPTables.end(); mfpit++) {
    124                 delete (*mfpit).second;
    125         }
    126         MFPTables.clear();
    127        
     128        MFPTables.clear();     
    128129}
    129130
     
    248249                        element=elementVector[kel];
    249250                        G4int Z=(G4int)std::floor(element->GetZ()+0.5);
    250                         c2_function<G4double> &ifunc=*sigmaMap[Z];
     251                        const G4_c2_function &ifunc=sigmaMap[Z];
    251252                        if(!kel || ifunc.xmin() > emin) emin=ifunc.xmin();
    252253                        if(!kel || ifunc.xmax() < emax) emax=ifunc.xmax();                     
     
    268269                        element=elementVector[kel];
    269270                        G4int Z=(G4int)std::floor(element->GetZ()+0.5);
    270                         c2_function<G4double> &sigma=*sigmaMap[Z];
     271                        const G4_c2_function &sigma=sigmaMap[Z];
    271272                        G4double ndens = atomDensities[kel]; // compute atom fraction for this element in this material
    272273                                               
     
    281282                }
    282283                // and make a new interpolating function out of the sum
    283                 MFPTables[matidx] = static_cast<c2_function<G4double> *>(new log_log_interpolating_function<G4double>(
    284                                 evals, mfpvals));
     284                MFPTables[matidx] = c2.log_log_interpolating_function().load(evals, mfpvals,true,0,true,0);
    285285    }
    286        
    287 #ifdef DEBUG   
    288         for (G4int matidx=0; matidx < nMaterials; matidx++) {
    289                 const G4Material* material= (*materialTable)[matidx];
    290                 G4cout << "***** MFP (1MeV) ***** " << material->GetName() << "  " << (*MFPTables[matidx])(1.0) << G4endl;
    291         }
    292 #endif
    293        
    294286}
    295287
     
    304296        recoilCutoff(RecoilCutoff), physicsCutoff(PhysicsCutoff),
    305297        hardeningFraction(0.0), hardeningFactor(1.0),
    306         externalCrossSectionConstructor(0)
    307 {
     298        externalCrossSectionConstructor(0),
     299        NIELPartitionFunction(new G4LindhardRobinsonPartition)
     300{
     301                // for now, point to class instance of this. Doing it by creating a new one fails
     302                // to correctly update NIEL
     303                // not even this is needed... done in G4VProcess().
     304                // pParticleChange=&aParticleChange;
     305                processMaxEnergy=50000.0*MeV;
    308306                highEnergyLimit=100.0*MeV;
    309307                lowEnergyLimit=physicsCutoff;
     
    313311                AddStage(new G4ScreenedCoulombClassicalKinematics);
    314312                AddStage(new G4SingleScatter);
     313                SetProcessSubType(fCoulombScattering);
    315314}
    316315
    317316void G4ScreenedNuclearRecoil::ResetTables()
    318317{
    319         std::map<G4int, c2_function<G4double>*>::iterator xh=meanFreePathTables.begin();
    320         for(;xh != meanFreePathTables.end(); xh++) {
    321                 delete (*xh).second;
    322         }
    323         meanFreePathTables.clear();
    324318       
    325319        std::map<G4int, G4ScreenedCoulombCrossSection*>::iterator xt=crossSectionHandlers.begin();
     
    338332
    339333        collisionStages.clear();
     334}
     335
     336void G4ScreenedNuclearRecoil::SetNIELPartitionFunction(const G4VNIELPartition *part)
     337{
     338        if(NIELPartitionFunction) delete NIELPartitionFunction;
     339        NIELPartitionFunction=part;
     340}
     341
     342void G4ScreenedNuclearRecoil::DepositEnergy(G4int z1, G4double a1, const G4Material *material, G4double energy)
     343{
     344        if(!NIELPartitionFunction) {
     345                IonizingLoss+=energy;
     346        } else {
     347                G4double part=NIELPartitionFunction->PartitionNIEL(z1, a1, material, energy);
     348                IonizingLoss+=energy*(1-part);
     349                NIEL += energy*part;
     350        }
    340351}
    341352
     
    363374G4double G4ScreenedNuclearRecoil::GetMeanFreePath(const G4Track& track,
    364375                                                  G4double,
    365                                                   G4ForceCondition*)
     376                                                  G4ForceCondition* cond)
    366377{
    367378        const G4DynamicParticle* incoming = track.GetDynamicParticle();
     
    370381       
    371382        G4double meanFreePath;
    372        
    373         if (energy < lowEnergyLimit || energy < recoilCutoff) return 1.0*nanometer; /* stop slow particles! */
    374         else if (energy > highEnergyLimit*a1) energy=highEnergyLimit*a1; /* constant MFP at high energy */
     383        *cond=NotForced;
     384       
     385        if (energy < lowEnergyLimit || energy < recoilCutoff*a1) {
     386                *cond=Forced;
     387                return 1.0*nm; /* catch and stop slow particles to collect their NIEL! */
     388        } else if (energy > processMaxEnergy*a1) {
     389                return DBL_MAX; // infinite mean free path
     390        } else if (energy > highEnergyLimit*a1) energy=highEnergyLimit*a1; /* constant MFP at high energy */
    375391
    376392        G4double fz1=incoming->GetDefinition()->GetPDGCharge();
     
    390406        size_t materialIndex = materialCouple->GetMaterial()->GetIndex();
    391407
    392         c2_function<G4double> &mfp=*(*xs)[materialIndex];
     408        const G4_c2_function &mfp=*(*xs)[materialIndex];
    393409       
    394410        // make absolutely certain we don't get an out-of-range energy
     
    403419{
    404420        validCollision=1;
    405         aParticleChange.Initialize(aTrack);
     421        pParticleChange->Initialize(aTrack);
    406422        NIEL=0.0; // default is no NIEL deposited
     423        IonizingLoss=0.0;
    407424       
    408425        // do universal setup
     
    413430        G4double fz1=baseParticle->GetPDGCharge()/eplus;
    414431        G4int z1=(G4int)(fz1+0.5);
     432        G4double a1=baseParticle->GetPDGMass()/amu_c2;
    415433        G4double incidentEnergy = incidentParticle->GetKineticEnergy();
    416434               
     
    418436        const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
    419437       
    420         if(incidentEnergy < GetRecoilCutoff()) { // check energy sanity on entry
    421                 if(!baseParticle->GetProcessManager()->
    422                    GetAtRestProcessVector()->size())
    423                         aParticleChange.ProposeTrackStatus(fStopAndKill);
    424                 else
    425                         aParticleChange.ProposeTrackStatus(fStopButAlive);
    426 
    427                 AddToNIEL(incidentEnergy);
    428                 aParticleChange.ProposeEnergy(0.0);
     438        const G4Material* mat = couple->GetMaterial();
     439
     440        G4double P=0.0; // the impact parameter of this collision
     441
     442        if(incidentEnergy < GetRecoilCutoff()*a1) { // check energy sanity on entry
     443                DepositEnergy(z1, baseParticle->GetPDGMass()/amu_c2, mat, incidentEnergy);
     444                GetParticleChange().ProposeEnergy(0.0);
    429445                // stop the particle and bail out
    430446                validCollision=0;
    431         }       
    432        
    433         const G4Material* mat = couple->GetMaterial();
    434         G4double numberDensity=mat->GetTotNbOfAtomsPerVolume();
    435         G4double lattice=0.5/std::pow(numberDensity,1.0/3.0); // typical lattice half-spacing
    436         G4double length=GetCurrentInteractionLength();
    437         G4double sigopi=1.0/(CLHEP::pi*numberDensity*length);  // this is sigma0/pi
    438        
    439         // compute the impact parameter very early, so if is rejected as too far away, little effort is wasted
    440         // this is the TRIM method for determining an impact parameter based on the flight path
    441         // this gives a cumulative distribution of N(P)= 1-exp(-pi P^2 n l)
    442         // which says the probability of NOT hitting a disk of area sigma= pi P^2 =exp(-sigma N l)
    443         // which may be reasonable
    444         G4double P;
    445         if(sigopi < lattice*lattice) {
    446                 // normal long-flight approximation
    447                 P = std::sqrt(-std::log(G4UniformRand()) *sigopi);
    448447        } else {
    449                 // short-flight limit
    450                 P = std::sqrt(G4UniformRand())*lattice;
    451         }
    452                
    453         G4double fraction=GetHardeningFraction();
    454         if(fraction && G4UniformRand() < fraction) {
    455                 // pick out some events, and increase the central cross section
    456                 // by reducing the impact parameter
    457                 P /= std::sqrt(GetHardeningFactor());
    458         }
    459        
    460        
    461         // check if we are far enough away that the energy transfer must be below cutoff,
    462         // and leave everything alone if so, saving a lot of time.
    463         if(P*P > sigopi) {
    464                 if(GetVerboseLevel() > 1)
    465                         printf("ScreenedNuclear impact reject: length=%.3f P=%.4f limit=%.4f\n",
    466                                    length/angstrom, P/angstrom,std::sqrt(sigopi)/angstrom);
    467                 // no collision, don't follow up with anything
    468                 validCollision=0;
     448               
     449                G4double numberDensity=mat->GetTotNbOfAtomsPerVolume();
     450                G4double lattice=0.5/std::pow(numberDensity,1.0/3.0); // typical lattice half-spacing
     451                G4double length=GetCurrentInteractionLength();
     452                G4double sigopi=1.0/(CLHEP::pi*numberDensity*length);  // this is sigma0/pi
     453               
     454                // compute the impact parameter very early, so if is rejected as too far away, little effort is wasted
     455                // this is the TRIM method for determining an impact parameter based on the flight path
     456                // this gives a cumulative distribution of N(P)= 1-exp(-pi P^2 n l)
     457                // which says the probability of NOT hitting a disk of area sigma= pi P^2 =exp(-sigma N l)
     458                // which may be reasonable
     459                if(sigopi < lattice*lattice) {
     460                        // normal long-flight approximation
     461                        P = std::sqrt(-std::log(G4UniformRand()) *sigopi);
     462                } else {
     463                        // short-flight limit
     464                        P = std::sqrt(G4UniformRand())*lattice;
     465                }
     466                       
     467                G4double fraction=GetHardeningFraction();
     468                if(fraction && G4UniformRand() < fraction) {
     469                        // pick out some events, and increase the central cross section
     470                        // by reducing the impact parameter
     471                        P /= std::sqrt(GetHardeningFactor());
     472                }
     473               
     474               
     475                // check if we are far enough away that the energy transfer must be below cutoff,
     476                // and leave everything alone if so, saving a lot of time.
     477                if(P*P > sigopi) {
     478                        if(GetVerboseLevel() > 1)
     479                                printf("ScreenedNuclear impact reject: length=%.3f P=%.4f limit=%.4f\n",
     480                                           length/angstrom, P/angstrom,std::sqrt(sigopi)/angstrom);
     481                        // no collision, don't follow up with anything
     482                        validCollision=0;
     483                }
    469484        }
    470485       
    471486        // find out what we hit, and record it in our kinematics block.
     487        kinematics.targetMaterial=mat;
     488        kinematics.a1=a1;
     489       
    472490        if(validCollision) {
    473491                G4ScreenedCoulombCrossSection   *xsect=GetCrossSectionHandlers()[z1];
     
    477495                kinematics.recoilIon=recoilIon;
    478496                kinematics.impactParameter=P;
    479                 kinematics.a1=baseParticle->GetPDGMass()/amu_c2;
    480497                kinematics.a2=recoilIon->GetPDGMass()/amu_c2;
    481498        } else {
    482499                kinematics.recoilIon=0;
    483500                kinematics.impactParameter=0;
    484                 kinematics.a1=baseParticle->GetPDGMass()/amu_c2;
    485501                kinematics.a2=0;
    486502        }
     
    492508       
    493509        if(registerDepositedEnergy) {
    494           aParticleChange.ProposeLocalEnergyDeposit(NIEL);
    495           aParticleChange.ProposeNonIonizingEnergyDeposit(NIEL);
    496         }
     510                pParticleChange->ProposeLocalEnergyDeposit(IonizingLoss+NIEL);
     511                pParticleChange->ProposeNonIonizingEnergyDeposit(NIEL);
     512                //MHM G4cout << "depositing energy, total = " << IonizingLoss+NIEL << " NIEL = " << NIEL << G4endl;
     513        }
     514
    497515        return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep );
     516}
     517
     518G4ScreenedCoulombClassicalKinematics::G4ScreenedCoulombClassicalKinematics() :
     519// instantiate all the needed functions statically, so no allocation is done at run time
     520// we will be solving x^2 - x phi(x*au)/eps - beta^2 == 0.0
     521// or, for easier scaling, x'^2 - x' au phi(x')/eps - beta^2 au^2
     522// note that only the last of these gets deleted, since it owns the rest
     523phifunc(c2.const_plugin_function()),
     524xovereps(c2.linear(0., 0., 0.)), // will fill this in with the right slope at run time
     525diff(c2.quadratic(0., 0., 0., 1.)-xovereps*phifunc)
     526{
    498527}
    499528
     
    520549        }
    521550       
    522         c2_function<G4double> &phiData=*(screen->EMphiData);
    523         // instantiate all the needed functions statically, so no allocation is done at run time
    524551        // we will be solving x^2 - x phi(x*au)/eps - beta^2 == 0.0
    525552        // or, for easier scaling, x'^2 - x' au phi(x')/eps - beta^2 au^2
    526         static c2_plugin_function<G4double> phifunc;
    527         static c2_quadratic<G4double> xsq(0., 0., 0., 1.); //  x^2
    528         static c2_linear<G4double> xovereps(0., 0., 0.); // will fill this in with the right slope at run time
    529         static c2_function<G4double> &xphi=xovereps*phifunc;
    530         static c2_function<G4double> &diff=xsq-xphi;
    531        
    532553        xovereps.reset(0., 0.0, au/eps); // slope of x*au/eps term
    533         phifunc.set_function(phiData); // install interpolating table
    534        
     554        phifunc.set_function(&(screen->EMphiData.get())); // install interpolating table
    535555        G4double xx1, phip, phip2;
    536         G4int root_error;
    537        
    538         xx1=diff.find_root(phiData.xmin(), std::min(10*xx0*au,phiData.xmax()),
    539                                            std::min(xx0*au, phiData.xmax()), beta*beta*au*au, &root_error, &phip, &phip2)/au;
     556        G4int root_error;       
     557        xx1=diff->find_root(phifunc.xmin(), std::min(10*xx0*au,phifunc.xmax()),
     558                                           std::min(xx0*au, phifunc.xmax()), beta*beta*au*au, &root_error, &phip, &phip2)/au;
    540559       
    541560        if(root_error) {
    542561                G4cout << "Screened Coulomb Root Finder Error" << G4endl;
    543562                G4cout << "au " << au << " A " << A << " a1 " << a1 << " xx1 " << xx1 << " eps " << eps << " beta " << beta << G4endl;
    544                 G4cout << " xmin " << phiData.xmin() << " xmax " << std::min(10*xx0*au,phiData.xmax()) ;
    545                 G4cout << " f(xmin) " << phifunc(phiData.xmin()) <<  " f(xmax) " << phifunc(std::min(10*xx0*au,phiData.xmax())) ;
    546                 G4cout << " xstart " << std::min(xx0*au, phiData.xmax()) <<  " target " <<  beta*beta*au*au ;
     563                G4cout << " xmin " << phifunc.xmin() << " xmax " << std::min(10*xx0*au,phifunc.xmax()) ;
     564                G4cout << " f(xmin) " << phifunc(phifunc.xmin()) <<  " f(xmax) " << phifunc(std::min(10*xx0*au,phifunc.xmax())) ;
     565                G4cout << " xstart " << std::min(xx0*au, phifunc.xmax()) <<  " target " <<  beta*beta*au*au ;
    547566                G4cout << G4endl;
    548567                throw c2_exception("Failed root find");
    549568        }
    550569       
    551         phifunc.unset_function(); // throws an exception if used without setting again
    552                                                           // phiprime is scaled by one factor of au because phi is evaluated at (xx0*au),
     570        // phiprime is scaled by one factor of au because phi is evaluated at (xx0*au),
    553571        G4double phiprime=phip*au;
    554572       
     
    564582                G4double x, ff;
    565583                x=xx1/xvals[k];
    566                 ff=1.0/std::sqrt(1.0-phiData(x*au)/(x*eps)-beta*beta/(x*x));
     584                ff=1.0/std::sqrt(1.0-phifunc(x*au)/(x*eps)-beta*beta/(x*x));
    567585                alpha+=weights[k]*ff;
    568586        }
    569587       
     588        phifunc.unset_function(); // throws an exception if used without setting again
     589
    570590        G4double thetac1=CLHEP::pi*beta*alpha/xx1; // complement of CM scattering angle
    571591        G4double sintheta=std::sin(thetac1); //note sin(pi-theta)=sin(theta)
     
    626646        kin.eRecoil=eRecoil;
    627647       
    628         if(incidentEnergy-eRecoil < master->GetRecoilCutoff()) {
    629                 if(!baseParticle->GetProcessManager()->
    630                    GetAtRestProcessVector()->size())
    631                         aParticleChange.ProposeTrackStatus(fStopAndKill);
    632                 else
    633                         aParticleChange.ProposeTrackStatus(fStopButAlive);
     648        if(incidentEnergy-eRecoil < master->GetRecoilCutoff()*a1) {
    634649                aParticleChange.ProposeEnergy(0.0);
    635                 master->AddToNIEL(incidentEnergy-eRecoil);
     650                master->DepositEnergy(int(screen->z1), a1, kin.targetMaterial, incidentEnergy-eRecoil);
    636651        }
    637652       
    638         if(master->GetEnableRecoils() && eRecoil > master->GetRecoilCutoff()) {
     653        if(master->GetEnableRecoils() && eRecoil > master->GetRecoilCutoff() * kin.a2) {
    639654                kin.recoilIon=recoilIon;               
    640655        } else {
    641656                kin.recoilIon=0; // this flags no recoil to be generated
    642                 master->AddToNIEL(eRecoil) ;
     657                master->DepositEnergy(Z, A, kin.targetMaterial, eRecoil) ;
    643658        }       
    644659}
     
    706721#include <vector>
    707722
    708 static c2_function<G4double> &ZBLScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
     723G4_c2_function &ZBLScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
    709724{
    710725        static const size_t ncoef=4;
     
    729744       
    730745        *auval=au;
    731         return *static_cast<c2_function<G4double> *>(new lin_log_interpolating_function<G4double>(r, phi, false, phiprime0));
    732 }
    733 
    734 static c2_function<G4double> &MoliereScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
     746        return c2.lin_log_interpolating_function().load(r, phi, false, phiprime0,true,0);
     747}
     748
     749G4_c2_function &MoliereScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
    735750{       
    736751        static const size_t ncoef=3;
     
    755770       
    756771        *auval=au;
    757         return *static_cast<c2_function<G4double> *>(new lin_log_interpolating_function<G4double>(r, phi, false, phiprime0));
    758 }
    759 
    760 static c2_function<G4double> &LJScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
     772        return c2.lin_log_interpolating_function().load(r, phi, false, phiprime0,true,0);
     773}
     774
     775G4_c2_function &LJScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
    761776{       
    762777//from Loftager, Besenbacher, Jensen & Sorensen
     
    781796       
    782797        *auval=au;
    783         return *static_cast<c2_function<G4double> *>(new lin_log_interpolating_function<G4double>(r, phi, false, logphiprime0*phi[0]));
     798        return c2.lin_log_interpolating_function().load(r, phi, false, logphiprime0*phi[0],true,0);
     799}
     800
     801G4_c2_function &LJZBLScreening(G4int z1, G4int z2, size_t npoints, G4double rMax, G4double *auval)
     802{       
     803// hybrid of LJ and ZBL, uses LJ if x < 0.25*auniv, ZBL if x > 1.5*auniv, and
     804/// connector in between.  These numbers are selected so the switchover
     805// is very near the point where the functions naturally cross.
     806        G4double auzbl, aulj;
     807       
     808        c2p zbl=ZBLScreening(z1, z2, npoints, rMax, &auzbl);
     809        c2p lj=LJScreening(z1, z2, npoints, rMax, &aulj);
     810
     811        G4double au=(auzbl+aulj)*0.5;
     812        lj->set_domain(lj->xmin(), 0.25*au);
     813        zbl->set_domain(1.5*au,zbl->xmax());
     814       
     815        c2p conn=c2.connector_function(lj->xmax(), lj, zbl->xmin(), zbl, true,0);
     816        c2_piecewise_function_p<G4double> &pw=c2.piecewise_function();
     817        c2p keepit(pw);
     818        pw.append_function(lj);
     819        pw.append_function(conn);
     820        pw.append_function(zbl);
     821       
     822        *auval=au;
     823        keepit.release_for_return();
     824        return pw;
    784825}
    785826
     
    791832        AddScreeningFunction("lj", LJScreening);       
    792833        AddScreeningFunction("mol", MoliereScreening); 
     834        AddScreeningFunction("ljzbl", LJZBLScreening); 
    793835}
    794836
     
    855897                       
    856898                        G4double au;
    857                         c2_function<G4double> &screen=sfunc(z1, Z, 200, 50.0*angstrom, &au); // generate the screening data
    858 
     899                        G4_c2_ptr screen=sfunc(z1, Z, 200, 50.0*angstrom, &au); // generate the screening data
    859900                        G4ScreeningTables st;
    860                         st.EMphiData=&screen; // this is our phi table
     901       
     902                        st.EMphiData=screen; //save our phi table
    861903                        st.z1=z1; st.m1=a1; st.z2=Z; st.m2=a2; st.emin=recoilCutoff;
    862904                        st.au=au;
     
    869911                        //this rearranges to phi(x0)/(x0*eps) = 2*theta/pi - theta^2/pi^2
    870912                       
    871                         c2_linear<G4double> c2au(0.0, 0.0, au);
    872                         c2_composed_function<G4double> phiau(screen, c2au); // build phi(x*au) for dimensionless phi
    873                         c2_linear<G4double> c2eps(0.0, 0.0, 0.0); // will store an appropriate eps inside this in loop
    874                         c2_ratio<G4double> x0func(phiau, c2eps); // this will be phi(x)/(x*eps) when c2eps is correctly set
     913                        c2_linear_p<G4double> &c2eps=c2.linear(0.0, 0.0, 0.0); // will store an appropriate eps inside this in loop
     914                        G4_c2_ptr phiau=screen(c2.linear(0.0, 0.0, au));
     915                        G4_c2_ptr x0func(phiau/c2eps); // this will be phi(x)/(x*eps) when c2eps is correctly set
     916                        x0func->set_domain(1e-6*angstrom/au, 0.9999*screen->xmax()/au); // needed for inverse function
     917                        // use the c2_inverse_function interface for the root finder... it is more efficient for an ordered
     918                        // computation of values.
     919                        G4_c2_ptr x0_solution(c2.inverse_function(x0func));
    875920                       
    876921                        G4double m1c2=a1*amu_c2;
     
    897942                                G4double q=theta/pi;
    898943                                // G4cout << ee << " " << m1c2 << " " << gamma << " " << eps << " " << theta << " " << q << G4endl;
    899                                 G4double x0= x0func.find_root(1e-6*angstrom/au, 0.9999*screen.xmax()/au, 1.0, 2*q-q*q);
     944                                // old way using root finder
     945                                // G4double x0= x0func->find_root(1e-6*angstrom/au, 0.9999*screen.xmax()/au, 1.0, 2*q-q*q);
     946                                // new way using c2_inverse_function which caches useful information so should be a bit faster
     947                                // since we are scanning this in strict order.
     948                                G4double x0=0;
     949                                try {
     950                                        x0=x0_solution(2*q-q*q);
     951                                } catch(c2_exception e) {
     952                                        G4Exception(
     953                                                G4String("G4ScreenedNuclearRecoil: failure in inverse solution to generate MFP Tables: ")+e.what()
     954                                        );
     955                                }
    900956                                G4double betasquared=x0*x0 - x0*phiau(x0)/eps; 
    901957                                G4double sigma=pi*betasquared*au*au;
     
    903959                                data[idx]=sigma;
    904960                        }
    905                        
    906961                        screeningData[Z]=st;
    907                         sigmaMap[Z] = static_cast<c2_function<G4double> *>(new log_log_interpolating_function<G4double>(
    908                                 energies, data));
     962                        sigmaMap[Z] = c2.log_log_interpolating_function().load(energies, data, true,0,true,0);
    909963                }
    910964        }
  • trunk/examples/extended/electromagnetic/TestEm7/src/PhysListEmLivermore.cc

    r807 r1230  
    2626//
    2727// $Id: PhysListEmLivermore.cc,v 1.2 2006/12/11 20:13:53 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/src/PhysListEmPenelope.cc

    r807 r1230  
    2626//
    2727// $Id: PhysListEmPenelope.cc,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/src/PhysListEmStandard.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 //
    27 // $Id: PhysListEmStandard.cc,v 1.11 2008/01/14 12:11:39 vnivanch Exp $
    28 // GEANT4 tag $Name:  $
     26// $Id: PhysListEmStandard.cc,v 1.19 2008/11/20 20:34:50 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2928//
    3029//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    3938#include "G4PhotoElectricEffect.hh"
    4039
    41 #include "G4MultipleScattering.hh"
     40#include "G4eMultipleScattering.hh"
    4241#include "G4hMultipleScattering.hh"
    4342
     
    5150
    5251#include "G4hIonisation.hh"
     52#include "G4hBremsstrahlung.hh"
     53#include "G4hPairProduction.hh"
     54
    5355#include "G4ionIonisation.hh"
    5456
    5557#include "G4EmProcessOptions.hh"
     58#include "G4MscStepLimitType.hh"
    5659
    5760//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    8689    } else if (particleName == "e-") {
    8790      //electron
    88       pmanager->AddProcess(new G4MultipleScattering, -1, 1,1);
    89       pmanager->AddProcess(new G4eIonisation,        -1, 2,2);
    90       pmanager->AddProcess(new G4eBremsstrahlung,    -1, 3,3);
     91      pmanager->AddProcess(new G4eMultipleScattering, -1, 1, 1);
     92      pmanager->AddProcess(new G4eIonisation,         -1, 2, 2);
     93      pmanager->AddProcess(new G4eBremsstrahlung,     -1, 3, 3);
    9194           
    9295    } else if (particleName == "e+") {
    9396      //positron
    94       pmanager->AddProcess(new G4MultipleScattering, -1, 1,1);
    95       pmanager->AddProcess(new G4eIonisation,        -1, 2,2);
    96       pmanager->AddProcess(new G4eBremsstrahlung,    -1, 3,3);
    97       pmanager->AddProcess(new G4eplusAnnihilation,   0,-1,4);
     97      pmanager->AddProcess(new G4eMultipleScattering, -1, 1, 1);
     98      pmanager->AddProcess(new G4eIonisation,         -1, 2, 2);
     99      pmanager->AddProcess(new G4eBremsstrahlung,     -1, 3, 3);
     100      pmanager->AddProcess(new G4eplusAnnihilation,    0,-1, 4);
    98101     
    99102    } else if( particleName == "mu+" ||
    100103               particleName == "mu-"    ) {
    101104      //muon 
    102       pmanager->AddProcess(new G4hMultipleScattering,-1, 1,1);
    103       pmanager->AddProcess(new G4MuIonisation,       -1, 2,2);
    104       pmanager->AddProcess(new G4MuBremsstrahlung,   -1, 3,3);
    105       pmanager->AddProcess(new G4MuPairProduction,   -1, 4,4);       
     105      pmanager->AddProcess(new G4hMultipleScattering, -1, 1, 1);
     106      pmanager->AddProcess(new G4MuIonisation,        -1, 2, 2);
     107      pmanager->AddProcess(new G4MuBremsstrahlung,    -1, 3, 3);
     108      pmanager->AddProcess(new G4MuPairProduction,    -1, 4, 4);       
     109             
     110    } else if( particleName == "proton" ||
     111               particleName == "pi-" ||
     112               particleName == "pi+"    ) {
     113      //proton 
     114      pmanager->AddProcess(new G4hMultipleScattering, -1, 1, 1);
     115      pmanager->AddProcess(new G4hIonisation,         -1, 2, 2);
     116      pmanager->AddProcess(new G4hBremsstrahlung,     -1, 3, 3);
     117      pmanager->AddProcess(new G4hPairProduction,     -1, 4, 4);       
    106118     
    107     } else if( particleName == "alpha" || particleName == "GenericIon" ) {
    108       pmanager->AddProcess(new G4hMultipleScattering,-1, 1,1);
    109       pmanager->AddProcess(new G4ionIonisation,      -1, 2,2);
     119    } else if( particleName == "alpha" ||
     120               particleName == "He3" ||
     121               particleName == "GenericIon" ) {
     122      //Ions
     123      pmanager->AddProcess(new G4hMultipleScattering, -1, 1, 1);
     124      pmanager->AddProcess(new G4ionIonisation,       -1, 2, 2);   
    110125
    111126    } else if ((!particle->IsShortLived()) &&
     
    113128               (particle->GetParticleName() != "chargedgeantino")) {
    114129      //all others charged particles except geantino
    115       pmanager->AddProcess(new G4hMultipleScattering,-1,1,1);
    116       pmanager->AddProcess(new G4hIonisation,        -1,2,2);
     130      pmanager->AddProcess(new G4hMultipleScattering, -1, 1, 1);
     131      pmanager->AddProcess(new G4hIonisation,         -1, 2, 2);
    117132    }
    118133  }
    119   G4EmProcessOptions opt;
    120   opt.SetStepFunction(0.2, 10*um);
    121   //  opt.SetSkin(1.);
    122   opt.SetMinEnergy(0.1*keV);
    123   opt.SetMaxEnergy(100.*GeV);
    124   opt.SetDEDXBinning(360);
    125   opt.SetLambdaBinning(360);
    126   opt.SetLinearLossLimit(1.e-6);
    127134}
    128135
  • trunk/examples/extended/electromagnetic/TestEm7/src/PhysListEmStandardNR.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: PhysListEmStandardNR.cc,v 1.1 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: $
     26// $Id: PhysListEmStandardNR.cc,v 1.3 2008/05/09 08:30:59 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    5656#include "G4CoulombScattering.hh"
    5757
     58#include "G4DummyModel.hh"
     59
    5860//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    5961
     
    7476
    7577  G4ScreenedNuclearRecoil* nucr = new G4ScreenedNuclearRecoil();
     78  G4double energyLimit = 100.*MeV;
     79  nucr->SetMaxEnergyForScattering(energyLimit);
    7680
    7781  theParticleIterator->reset();
     
    109113             
    110114    } else if (particleName == "alpha" || particleName == "He3") {
     115      G4hMultipleScattering* msc = new G4hMultipleScattering();
     116      G4DummyModel* dm = new G4DummyModel();
     117      dm->SetLowEnergyLimit(0.0);
     118      dm->SetHighEnergyLimit(energyLimit);
     119      msc->AddEmModel(0, dm);
     120      pmanager->AddProcess(msc, -1, 1,1);
     121
    111122      G4ionIonisation* ion = new G4ionIonisation();
    112123      ion->ActivateNuclearStopping(false);
    113       pmanager->AddProcess(ion, -1, 1, 1);
     124      pmanager->AddProcess(ion, -1, 2, 2);
     125
    114126      pmanager->AddDiscreteProcess(nucr);     
    115127
    116128    } else if (particleName == "GenericIon" ) {
     129      G4hMultipleScattering* msc = new G4hMultipleScattering();
     130      G4DummyModel* dm = new G4DummyModel();
     131      dm->SetLowEnergyLimit(0.0);
     132      dm->SetHighEnergyLimit(energyLimit);
     133      msc->AddEmModel(0, dm);
     134      pmanager->AddProcess(msc, -1, 1,1);
     135
    117136      G4ionIonisation* ion = new G4ionIonisation();
    118137      ion->ActivateNuclearStopping(false);
    119138      ion->SetStepFunction(0.1, um);
    120       pmanager->AddProcess(ion, -1, 1, 1);
     139      pmanager->AddProcess(ion, -1, 2, 2);
     140
    121141      pmanager->AddDiscreteProcess(nucr);     
    122142
     
    124144               particleName == "deuteron" ||
    125145               particleName == "triton") {
     146      G4hMultipleScattering* msc = new G4hMultipleScattering();
     147      G4DummyModel* dm = new G4DummyModel();
     148      dm->SetLowEnergyLimit(0.0);
     149      dm->SetHighEnergyLimit(energyLimit);
     150      msc->AddEmModel(0, dm);
     151      pmanager->AddProcess(msc, -1, 1,1);
     152
    126153      G4hIonisation* hion = new G4hIonisation();
    127154      hion->SetFluctModel(new G4IonFluctuations());
    128155      hion->SetStepFunction(0.1, 10.*um);
    129156      hion->ActivateNuclearStopping(false);
    130       pmanager->AddProcess(hion, -1, 1,1);
     157      pmanager->AddProcess(hion, -1, 2, 2);
     158
    131159      pmanager->AddDiscreteProcess(nucr);     
    132160     
  • trunk/examples/extended/electromagnetic/TestEm7/src/PhysListEmStandardSS.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: PhysListEmStandardSS.cc,v 1.5 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: $
     26// $Id: PhysListEmStandardSS.cc,v 1.8 2008/11/16 19:17:39 maire Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    3838#include "G4PhotoElectricEffect.hh"
    3939
    40 #include "G4MultipleScattering.hh"
     40#include "G4CoulombScattering.hh"
    4141
    4242#include "G4eIonisation.hh"
     
    5050#include "G4hIonisation.hh"
    5151#include "G4ionIonisation.hh"
    52 #include "G4ionGasIonisation.hh"
    53 #include "G4IonFluctuations.hh"
    54 #include "G4CoulombScattering.hh"
     52
     53#include "G4EmProcessOptions.hh"
    5554
    5655//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    8584    } else if (particleName == "e-") {
    8685      //electron
    87       pmanager->AddProcess(new G4eIonisation,        -1, 1,1);
    88       pmanager->AddProcess(new G4eBremsstrahlung,    -1, 2,2);
    8986      pmanager->AddDiscreteProcess(new G4CoulombScattering);     
     87      pmanager->AddProcess(new G4eIonisation,        -1, 1, 1);
     88      pmanager->AddProcess(new G4eBremsstrahlung,    -1, 2, 2);
    9089           
    9190    } else if (particleName == "e+") {
    9291      //positron
    93       pmanager->AddProcess(new G4eIonisation,        -1, 1,1);
    94       pmanager->AddProcess(new G4eBremsstrahlung,    -1, 2,2);
    95       pmanager->AddProcess(new G4eplusAnnihilation,   0,-1,3);
    9692      pmanager->AddDiscreteProcess(new G4CoulombScattering);     
     93      pmanager->AddProcess(new G4eIonisation,        -1, 1, 1);
     94      pmanager->AddProcess(new G4eBremsstrahlung,    -1, 2, 2);
     95      pmanager->AddProcess(new G4eplusAnnihilation,   0,-1, 3);
    9796           
    9897    } else if (particleName == "mu+" ||
    9998               particleName == "mu-"    ) {
    100       //muon 
    101       pmanager->AddProcess(new G4MuIonisation,       -1, 1,1);
    102       pmanager->AddProcess(new G4MuBremsstrahlung,   -1, 2,2);
    103       pmanager->AddProcess(new G4MuPairProduction,   -1, 3,3);
    104       pmanager->AddDiscreteProcess(new G4CoulombScattering);     
     99      //muon
     100      pmanager->AddDiscreteProcess(new G4CoulombScattering);       
     101      pmanager->AddProcess(new G4MuIonisation,       -1, 1, 1);
     102      pmanager->AddProcess(new G4MuBremsstrahlung,   -1, 2, 2);
     103      pmanager->AddProcess(new G4MuPairProduction,   -1, 3, 3);
    105104             
    106     } else if (particleName == "alpha" || particleName == "He3") {
    107       G4ionIonisation* ion = new G4ionIonisation();
    108       ion->SetStepFunction(0.1, um);
    109       ion->ActivateNuclearStopping(false);
    110       pmanager->AddProcess(ion,  -1, 1,1);
    111       pmanager->AddDiscreteProcess(new G4CoulombScattering);     
    112 
    113     } else if (particleName == "GenericIon" ) {
    114       G4ionGasIonisation* ion = new G4ionGasIonisation();
    115       ion->ActivateNuclearStopping(false);
    116       ion->SetStepFunction(0.1, um);
    117       pmanager->AddProcess(ion,  -1, 1,1);
    118       G4CoulombScattering* cs = new G4CoulombScattering();
    119       cs->SetBuildTableFlag(false);
    120       pmanager->AddDiscreteProcess(cs);
    121      
     105    } else if (particleName == "alpha" ||
     106               particleName == "He3" ||
     107               particleName == "GenericIon") {
     108      pmanager->AddDiscreteProcess(new G4CoulombScattering);           
     109      pmanager->AddProcess(new G4ionIonisation,      -1, 1, 1);
     110     
    122111    } else if ((!particle->IsShortLived()) &&
    123112               (particle->GetPDGCharge() != 0.0) &&
    124113               (particle->GetParticleName() != "chargedgeantino")) {
    125114      //all others charged particles except geantino
    126       G4hIonisation* hion = new G4hIonisation();
    127       hion->SetStepFunction(0.1, 10.*um);
    128       hion->ActivateNuclearStopping(false);
    129       pmanager->AddProcess(hion,  -1,1,1);
    130115      pmanager->AddDiscreteProcess(new G4CoulombScattering);     
     116      pmanager->AddProcess(new G4hIonisation,        -1, 1, 1);
    131117    }
    132118  }
     119 
     120  // Em options
     121  //
     122  // Main options and setting parameters are shown here.
     123  // Several of them have default values.
     124  //
     125  G4EmProcessOptions emOptions;
     126 
     127  //physics tables
     128  //
     129  emOptions.SetMinEnergy(100*eV);       //default   
     130  emOptions.SetMaxEnergy(100*TeV);      //default 
     131  emOptions.SetDEDXBinning(12*20);      //default=12*7 
     132  emOptions.SetLambdaBinning(12*20);    //default=12*7
     133  emOptions.SetSplineFlag(true);        //default
     134     
     135  //energy loss
     136  //
     137  emOptions.SetStepFunction(0.2,50*um); //default=(0.2, 1*mm)   
     138  emOptions.SetLinearLossLimit(1.e-2);  //default
     139   
     140  //ionization
     141  //
     142  emOptions.SetSubCutoff(false);        //default   
    133143}
    134144
  • trunk/examples/extended/electromagnetic/TestEm7/src/PhysicsList.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: PhysicsList.cc,v 1.28 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: PhysicsList.cc,v 1.36 2008/11/21 12:53:13 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    3535#include "PhysListEmStandard.hh"
    3636#include "PhysListEmStandardSS.hh"
    37 #include "PhysListEmStandardIG.hh"
    3837#include "PhysListEmStandardNR.hh"
    3938#include "PhysListEmLivermore.hh"
     
    4241#include "G4EmStandardPhysics_option1.hh"
    4342#include "G4EmStandardPhysics_option2.hh"
     43#include "G4EmStandardPhysics_option3.hh"
     44
     45#include "G4DecayPhysics.hh"
    4446
    4547#include "G4HadronElasticPhysics.hh"
     
    5052#include "G4IonBinaryCascadePhysics.hh"
    5153
    52 #include "G4EmProcessOptions.hh"
    53 
    5454#include "G4LossTableManager.hh"
    5555#include "G4UnitsTable.hh"
     
    5757#include "G4ProcessManager.hh"
    5858#include "G4Decay.hh"
     59
     60#include "StepMax.hh"
     61
     62#include "G4IonFluctuations.hh"
     63#include "G4IonParametrisedLossModel.hh"
    5964
    6065//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    7984
    8085  // EM physics
    81   emPhysicsList = new PhysListEmStandard(emName = "standard");
    82 
     86  emPhysicsList = new G4EmStandardPhysics(1);
     87  emName = G4String("emstandard");
     88
     89  // Deacy physics and all particles
     90  decPhysicsList = new G4DecayPhysics();
    8391}
    8492
     
    8997  delete pMessenger;
    9098  delete emPhysicsList;
    91   for(size_t i=0; i<hadronPhys.size(); i++) delete hadronPhys[i];
    92 }
    93 
    94 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    95 
    96 // Bosons
    97 #include "G4ChargedGeantino.hh"
    98 #include "G4Geantino.hh"
    99 #include "G4Gamma.hh"
    100 
    101 // leptons
    102 #include "G4MuonPlus.hh"
    103 #include "G4MuonMinus.hh"
    104 #include "G4NeutrinoMu.hh"
    105 #include "G4AntiNeutrinoMu.hh"
    106 
    107 #include "G4Electron.hh"
    108 #include "G4Positron.hh"
    109 #include "G4NeutrinoE.hh"
    110 #include "G4AntiNeutrinoE.hh"
    111 
    112 // Hadrons
    113 #include "G4MesonConstructor.hh"
    114 #include "G4BaryonConstructor.hh"
    115 #include "G4IonConstructor.hh"
     99  delete decPhysicsList;
     100  for(size_t i=0; i<hadronPhys.size(); i++) {delete hadronPhys[i];}
     101}
    116102
    117103//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    119105void PhysicsList::ConstructParticle()
    120106{
    121 // pseudo-particles
    122   G4Geantino::GeantinoDefinition();
    123   G4ChargedGeantino::ChargedGeantinoDefinition();
    124  
    125 // gamma
    126   G4Gamma::GammaDefinition();
    127  
    128 // leptons
    129   G4Electron::ElectronDefinition();
    130   G4Positron::PositronDefinition();
    131   G4MuonPlus::MuonPlusDefinition();
    132   G4MuonMinus::MuonMinusDefinition();
    133 
    134   G4NeutrinoE::NeutrinoEDefinition();
    135   G4AntiNeutrinoE::AntiNeutrinoEDefinition();
    136   G4NeutrinoMu::NeutrinoMuDefinition();
    137   G4AntiNeutrinoMu::AntiNeutrinoMuDefinition(); 
    138 
    139 // mesons
    140   G4MesonConstructor mConstructor;
    141   mConstructor.ConstructParticle();
    142 
    143 // barions
    144   G4BaryonConstructor bConstructor;
    145   bConstructor.ConstructParticle();
    146 
    147 // ions
    148   G4IonConstructor iConstructor;
    149   iConstructor.ConstructParticle();
    150 }
    151 
    152 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     107  decPhysicsList->ConstructParticle();
     108}
     109
     110//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     111
    153112void PhysicsList::ConstructProcess()
    154113{
     
    160119  //
    161120  emPhysicsList->ConstructProcess();
     121  em_config.AddModels();
     122
     123  // decay physics list
     124  //
     125  decPhysicsList->ConstructProcess();
    162126 
    163127  // hadronic physics lists
    164   for(size_t i=0; i<hadronPhys.size(); i++) hadronPhys[i]->ConstructProcess();
    165  
    166   // decay process
    167   //
    168   G4Decay* fDecayProcess = new G4Decay();
    169 
    170   theParticleIterator->reset();
    171   while( (*theParticleIterator)() ){
    172     G4ParticleDefinition* particle = theParticleIterator->value();
    173     G4ProcessManager* pmanager = particle->GetProcessManager();
    174 
    175     if (fDecayProcess->IsApplicable(*particle) && !particle->IsShortLived()) {
    176 
    177       pmanager ->AddProcess(fDecayProcess);
    178 
    179       // set ordering for PostStepDoIt and AtRestDoIt
    180       pmanager ->SetProcessOrdering(fDecayProcess, idxPostStep);
    181       pmanager ->SetProcessOrdering(fDecayProcess, idxAtRest);
    182 
    183     }
     128  for(size_t i=0; i<hadronPhys.size(); i++) {
     129    hadronPhys[i]->ConstructProcess();
    184130  }
    185131 
    186132  // step limitation (as a full process)
    187133  // 
    188   AddStepMax();
    189  
    190   G4EmProcessOptions opt;
    191   opt.SetDEDXBinning(480);
     134  AddStepMax(); 
    192135}
    193136
     
    196139void PhysicsList::AddPhysicsList(const G4String& name)
    197140{
    198   if (verboseLevel>-1) {
     141  if (verboseLevel>1) {
    199142    G4cout << "PhysicsList::AddPhysicsList: <" << name << ">" << G4endl;
    200143  }
     
    202145  if (name == emName) return;
    203146
    204   if (name == "standard") {
     147  if (name == "standard_local") {
    205148
    206149    emName = name;
     
    212155    emName = name;
    213156    delete emPhysicsList;
    214     emPhysicsList = new G4EmStandardPhysics();
     157    emPhysicsList = new G4EmStandardPhysics(1);
    215158
    216159  } else if (name == "emstandard_opt1") {
     
    225168    delete emPhysicsList;
    226169    emPhysicsList = new G4EmStandardPhysics_option2();
     170   
     171  } else if (name == "emstandard_opt3") {
     172
     173    emName = name;
     174    delete emPhysicsList;
     175    emPhysicsList = new G4EmStandardPhysics_option3();   
    227176
    228177  } else if (name == "standardSS") {
     
    238187    emPhysicsList = new PhysListEmStandardNR(name);
    239188
    240   } else if (name == "standardIG") {
    241 
    242     emName = name;
    243     delete emPhysicsList;
    244     emPhysicsList = new PhysListEmStandardIG(name);
     189  } else if (name == "standardICRU73") {
     190
     191    emName = name;
     192    delete emPhysicsList;
     193    emPhysicsList = new PhysListEmStandard(name);
     194    em_config.SetExtraEmModel("GenericIon","ionIoni",
     195                              new G4IonParametrisedLossModel(),
     196                              "",0.0, 100.0*TeV,
     197                              new G4IonFluctuations());
     198    G4cout << "standardICRU73" << G4endl;
    245199
    246200  } else if (name == "livermore") {
     
    288242//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    289243
    290 #include "StepMax.hh"
    291 
    292244void PhysicsList::AddStepMax()
    293245{
     
    297249  theParticleIterator->reset();
    298250  while ((*theParticleIterator)()){
    299       G4ParticleDefinition* particle = theParticleIterator->value();
    300       G4ProcessManager* pmanager = particle->GetProcessManager();
    301 
    302       if (stepMaxProcess->IsApplicable(*particle) && pmanager)
    303         {
    304           pmanager ->AddDiscreteProcess(stepMaxProcess);
    305         }
     251    G4ParticleDefinition* particle = theParticleIterator->value();
     252    G4ProcessManager* pmanager = particle->GetProcessManager();
     253
     254    if (stepMaxProcess->IsApplicable(*particle) && pmanager)
     255      {
     256        pmanager ->AddDiscreteProcess(stepMaxProcess);
     257      }
    306258  }
    307259}
  • trunk/examples/extended/electromagnetic/TestEm7/src/PhysicsListMessenger.cc

    r807 r1230  
    2525//
    2626// $Id: PhysicsListMessenger.cc,v 1.3 2006/06/29 16:58:37 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/src/PrimaryGeneratorAction.cc

    r807 r1230  
    2525//
    2626// $Id: PrimaryGeneratorAction.cc,v 1.2 2006/06/29 16:58:39 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/src/PrimaryGeneratorMessenger.cc

    r807 r1230  
    2525//
    2626// $Id: PrimaryGeneratorMessenger.cc,v 1.3 2006/06/29 16:58:41 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/src/RunAction.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: RunAction.cc,v 1.21 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: RunAction.cc,v 1.24 2008/08/22 18:30:27 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    4242
    4343#include "Randomize.hh"
    44 
    45 #ifdef G4ANALYSIS_USE
    46 #include "AIDA/AIDA.h"
    47 #endif
     44#include "Histo.hh"
    4845
    4946//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    5148RunAction::RunAction(DetectorConstruction* det, PhysicsList* phys,
    5249                     PrimaryGeneratorAction* kin)
    53 :detector(det), physics(phys), kinematic(kin), af(0), tree(0)
     50:detector(det), physics(phys), kinematic(kin)
    5451{
    5552  tallyEdep = new G4double[MaxTally];
    5653  binLength = offsetX = 0.;
    57   histo[0] = 0;
    58  
    59 #ifdef G4ANALYSIS_USE
    60   // Creating the analysis factory
    61   af = AIDA_createAnalysisFactory();
    62   if(!af) {
    63     G4cout << "RunAction::RunAction() :"
    64            << " problem creating the AIDA analysis factory."
    65            << G4endl;
    66   }       
    67 #endif 
     54  histo = new Histo();
     55  histo->setFileName("testem7");
     56  histo->add1D("1","Edep (MeV/mm) along absorber (mm)", 100, 0, 100);
     57  histo->add1D("2","Edep (MeV/mm) along absorber zoomed (mm)", 100, 0, 100);
     58  histo->add1D("3","Projectile range (mm)", 100, 0, 100);
    6859}
    6960
     
    7364{
    7465  delete [] tallyEdep;
    75  
    76 #ifdef G4ANALYSIS_USE
    77   delete af; 
    78 #endif     
    79 }
    80 
    81 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    82 
    83 void RunAction::bookHisto()
    84 {
    85   length  = detector->GetAbsorSizeX();
    86   G4double stepMax = physics->GetStepMaxProcess()->GetMaxStep();
    87   const G4int nbmin = 100;
    88   G4int nbBins = (int)(0.5 + length/stepMax);
    89   if (nbBins < nbmin) nbBins = nbmin;
    90   binLength = length/nbBins;
    91   offsetX   = 0.5*length;
    92  
    93 #ifdef G4ANALYSIS_USE
    94   if (!af) return;
    95 
    96   // Create a tree mapped to an hbook file.
    97   G4bool readOnly  = false;
    98   G4bool createNew = true;
    99   G4String options = "--noErrors uncompress";
    100   AIDA::ITreeFactory* tf  = af->createTreeFactory(); 
    101   tree = tf->create("testem7.hbook","hbook", readOnly, createNew, options);
    102   //tree = tf->create("testem7.root", "root",readOnly, createNew, options);
    103   //tree = tf->create("testem7.XML" , "XML" ,readOnly, createNew, options);
    104   delete tf;
    105   if (!tree) {
    106     G4cout << "RunAction::bookHisto()" << G4endl;
    107     return;
    108   }
    109 
    110   // Create a histogram factory, whose histograms will be handled by the tree
    111   AIDA::IHistogramFactory* hf = af->createHistogramFactory(*tree);
    112  
    113   // Create histogram
    114   histo[0] = hf->createHistogram1D("1","Edep (MeV/mm) along absorber (mm)",
    115              nbBins, 0, length/mm);
    116              
    117   delete hf;         
    118   G4cout << "\n----> Histogram Tree opened" << G4endl;
    119 #endif
    120 }
    121 
    122 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
    123 
    124 void RunAction::cleanHisto()
    125 {
    126 #ifdef G4ANALYSIS_USE
    127   tree->commit();       // Writing the histograms to the file
    128   tree->close();        // and closing the tree (and the file)
    129   delete tree;
    130   tree = 0;
    131  
    132   G4cout << "\n----> Histogram Tree saved" << G4endl; 
    133 #endif
     66  delete histo; 
    13467}
    13568
     
    13871void RunAction::FillHisto(G4int ih, G4double x, G4double weight)
    13972{
    140 #ifdef G4ANALYSIS_USE
    141   if(histo[ih]) histo[ih]->fill(x, weight);
    142 #endif
     73  histo->fill(ih, x, weight);
    14374}
    14475
     
    15687  //
    15788  nPrimarySteps = 0;
     89  nRange = 0;
    15890  projRange = projRange2 = 0.;
    15991  edeptot = eniel = 0.;
    16092  for (G4int j=0; j<MaxTally; j++) tallyEdep[j] = 0.;
    16193  kinematic->ResetEbeamCumul();
    162   bookHisto();     
     94
     95  // define "1" histogram binning
     96  length  = detector->GetAbsorSizeX();
     97  G4double stepMax = physics->GetStepMaxProcess()->GetMaxStep();
     98  const G4int nbmin = 100;
     99  G4int nbBins = (G4int)(0.5 + length/stepMax);
     100  if (nbBins < nbmin) nbBins = nbmin;
     101  binLength = length/nbBins;
     102  offsetX   = 0.5*length;
     103   
     104  // histogram "1" is defined by the length of the target
     105  // zoomed histograms are defined by UI command
     106  histo->setHisto1D(0, nbBins, 0, length, mm);
     107 
     108  histo->book();
    163109}
    164110
     
    186132  //compute projected range and straggling
    187133  //
    188   projRange /= NbofEvents; projRange2 /= NbofEvents;
     134  if(nRange > 0) {
     135    projRange /= nRange;
     136    projRange2 /= nRange;
     137  }
    189138  G4double rms = projRange2 - projRange*projRange;       
    190139  if (rms>0.) rms = std::sqrt(rms); else rms = 0.;
     
    227176  }
    228177
    229 #ifdef G4ANALYSIS_USE
    230178  // normalize histogram
    231179  G4double fac = (mm/MeV)/(NbofEvents *  binLength);
    232   histo[0]->scale(fac);
    233 #endif
    234  
     180  for (G4int j=0; j<3; j++) {histo->scale(j, fac);}
    235181 
    236182  // save and clean histo
    237   cleanHisto();
     183  histo->save();
    238184 
    239185  // show Rndm status
  • trunk/examples/extended/electromagnetic/TestEm7/src/StepMax.cc

    r807 r1230  
    2525//
    2626// $Id: StepMax.cc,v 1.5 2006/06/29 16:58:45 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/src/StepMaxMessenger.cc

    r807 r1230  
    2525//
    2626// $Id: StepMaxMessenger.cc,v 1.3 2006/06/29 16:58:47 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/src/SteppingAction.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: SteppingAction.cc,v 1.12 2008/01/14 12:11:39 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: SteppingAction.cc,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......
     
    5151void SteppingAction::UserSteppingAction(const G4Step* aStep)
    5252{
    53  G4double edep = aStep->GetTotalEnergyDeposit();
    54  if (edep <= 0.) return;
     53  G4double edep = aStep->GetTotalEnergyDeposit();
     54  if (edep <= 0.) return;
    5555
    56  // G4cout << "edep= " << edep << "NIEL= " << aStep->GetNonIonizingEnergyDeposit()<<G4endl;
     56  // G4cout << "edep= " << edep << "NIEL= " << aStep->GetNonIonizingEnergyDeposit()<<G4endl;
    5757
    58  runAction->FillEdep(edep,aStep->GetNonIonizingEnergyDeposit());
     58  runAction->FillEdep(edep,aStep->GetNonIonizingEnergyDeposit());
    5959
    60  if(aStep->GetTrack()->GetTrackID() == 1) runAction->AddPrimaryStep(); 
     60  if(aStep->GetTrack()->GetTrackID() == 1) runAction->AddPrimaryStep(); 
    6161 
    62  //Bragg curve
    63  //     
    64  G4StepPoint* prePoint  = aStep->GetPreStepPoint();
    65  G4StepPoint* postPoint = aStep->GetPostStepPoint();
     62  //Bragg curve
     63  //   
     64  G4StepPoint* prePoint  = aStep->GetPreStepPoint();
     65  G4StepPoint* postPoint = aStep->GetPostStepPoint();
    6666   
    67  G4double x1 = prePoint->GetPosition().x(), x2 = postPoint->GetPosition().x(); 
    68  G4double x = runAction->GetOffsetX() + x1 + G4UniformRand()*(x2-x1);
    69  runAction->FillHisto(0, x/mm , edep);
     67  G4double x1 = prePoint->GetPosition().x(), x2 = postPoint->GetPosition().x(); 
     68  G4double x = runAction->GetOffsetX() + x1 + G4UniformRand()*(x2-x1);
     69  runAction->FillHisto(0, x/mm , edep);
     70  runAction->FillHisto(1, x/mm , edep);
    7071
    71  //fill tallies
    72  //
    73  G4TouchableHandle touchable = prePoint->GetTouchableHandle();
    74  G4LogicalVolume* lVolume = touchable->GetVolume()->GetLogicalVolume();
    75  if (lVolume == detector->GetLogicalTally())
    76      runAction->FillTallyEdep(touchable->GetCopyNumber(), edep);
     72  //fill tallies
     73  //
     74  G4TouchableHandle touchable = prePoint->GetTouchableHandle();
     75  G4LogicalVolume* lVolume = touchable->GetVolume()->GetLogicalVolume();
     76  if (lVolume == detector->GetLogicalTally())
     77    runAction->FillTallyEdep(touchable->GetCopyNumber(), edep);
    7778}
    7879
  • trunk/examples/extended/electromagnetic/TestEm7/src/SteppingVerbose.cc

    r807 r1230  
    2525//
    2626// $Id: SteppingVerbose.cc,v 1.3 2006/06/29 16:58:51 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/src/TrackingAction.cc

    r807 r1230  
    2424// ********************************************************************
    2525//
    26 // $Id: TrackingAction.cc,v 1.3 2006/11/22 17:58:11 vnivanch Exp $
    27 // GEANT4 tag $Name: geant4-09-01-patch-02 $
     26// $Id: TrackingAction.cc,v 1.5 2008/08/22 18:30:27 vnivanch Exp $
     27// GEANT4 tag $Name: geant4-09-03-cand-01 $
    2828//
    2929//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
     
    5050    G4double x = aTrack->GetPosition().x() + runAction->GetOffsetX();
    5151    if(x > runAction->GetLength()) x = runAction->GetLength();
    52     runAction->AddProjRange(x);
     52    //G4cout << " range= " << x << " x= " << aTrack->GetPosition().x()
     53    //     << " ofset= " << runAction->GetOffsetX() << G4endl;
     54    if(x > 0.0) runAction->AddProjRange(x);
     55    runAction->FillHisto(2, x/mm, 1.0);
    5356  } 
    5457}
Note: See TracChangeset for help on using the changeset viewer.