Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:58:09

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /*
0027  * G4DNASmoluchowskiDiffusion.hh
0028  *
0029  *  Created on: 2 févr. 2015
0030  *      Author: matkara
0031  */
0032 
0033 #ifndef G4DNASMOLUCHOWSKIDIFFUSION_HH_
0034 #define G4DNASMOLUCHOWSKIDIFFUSION_HH_
0035 
0036 //#if __cplusplus >= 201103L
0037 #include <cstdlib>
0038 #include <cmath>
0039 #include <vector>
0040 #include <iostream>
0041 #include <algorithm>
0042 
0043 //#define DNADEV_TEST
0044 
0045 #ifdef DNADEV_TEST
0046 #include <TF1.h>
0047 #endif
0048 
0049 #include <cassert>
0050 
0051 #ifndef DNADEV_TEST
0052 #include "globals.hh"
0053 #include "Randomize.hh"
0054 #endif
0055 
0056 #ifdef DNADEV_TEST
0057 #include "TRandom.h"
0058 TRandom root_random;
0059 double G4UniformRand()
0060 {
0061   return root_random.Rndm();
0062 }
0063 
0064 #define G4cout std::cout
0065 #define G4endl std::endl
0066 #endif
0067 
0068 #include "G4Exp.hh"
0069 
0070 class G4DNASmoluchowskiDiffusion
0071 {
0072 public:
0073   G4DNASmoluchowskiDiffusion(double epsilon = 1e-5);
0074   virtual ~G4DNASmoluchowskiDiffusion();
0075 
0076   static double ComputeS(double r, double D, double t)
0077   {
0078     double sTransform = r / (2. * std::sqrt(D * t));
0079     return sTransform;
0080   }
0081 
0082   static double ComputeDistance(double sTransform, double D, double t)
0083   {
0084     return sTransform * 2. * std::sqrt(D * t);
0085   }
0086 
0087   static double ComputeTime(double sTransform, double D, double r)
0088   {
0089     return std::pow(r / sTransform, 2.) / (4. * D);
0090   }
0091 
0092   //====================================================
0093 
0094   double GetRandomDistance(double _time, double D)
0095   {
0096     double proba = G4UniformRand();
0097 //    G4cout << "proba = " << proba << G4endl;
0098     double sTransform = GetInverseProbability(proba);
0099 //    G4cout << "sTransform = " << sTransform << G4endl;
0100     return ComputeDistance(sTransform, D, _time);
0101   }
0102 
0103   double GetRandomTime(double distance, double D)
0104   {
0105     double proba = G4UniformRand();
0106     double sTransform = GetInverseProbability(proba);
0107     return ComputeTime(sTransform, D, distance);
0108   }
0109 
0110   double EstimateCrossingTime(double proba,
0111                               double distance,
0112                               double D)
0113   {
0114     double sTransform = GetInverseProbability(proba);
0115     return ComputeTime(sTransform, D, distance);
0116   }
0117 
0118   //====================================================
0119   // 1-value transformation
0120 
0121   // WARNING : this is NOT the differential probability
0122   // this is the derivative of the function GetCumulativeProbability
0123   static double GetDifferential(double sTransform)
0124   {
0125     static double constant = -4./std::sqrt(3.141592653589793);
0126     return sTransform*sTransform*G4Exp(-sTransform*sTransform)*constant; // -4*sTransform*sTransform*exp(-sTransform*sTransform)/sqrt(3.141592653589793)
0127   }
0128 
0129   static double GetDensityProbability(double r, double _time, double D)
0130   {
0131     static double my_pi = 3.141592653589793;
0132     static double constant = 4.*my_pi/std::pow(4.*my_pi, 1.5);
0133     return r*r/std::pow(D * _time,1.5)*G4Exp(-r*r/(4. * D * _time))*constant;
0134   }
0135 
0136   //====================================================
0137   // BOUNDING BOX
0138   struct BoundingBox
0139   {
0140     double fXmax;
0141     double fXmin;
0142     double fXmaxDef;
0143     double fXminDef;
0144     double fToleranceY;
0145     double fSum{0};
0146     double    fIncreasingCumulativeFunction;
0147 
0148     enum PreviousAction
0149     {
0150       IncreaseProba,
0151       DecreaseProba,
0152       Undefined
0153     };
0154 
0155     PreviousAction fPreviousAction;
0156 
0157     BoundingBox(double xmin,
0158                 double xmax,
0159                 double toleranceY) :
0160      fXmax(xmax), fXmin(xmin),
0161      fToleranceY(toleranceY) 
0162     {
0163       if(fXmax < fXmin)
0164       {
0165         double tmp = fXmin;
0166         fXmin = fXmax;
0167         fXmax = tmp;
0168       }
0169       
0170       fXminDef = fXmin;
0171       fXmaxDef = fXmax;
0172       fPreviousAction = BoundingBox::Undefined;
0173       fIncreasingCumulativeFunction = (GetCumulativeProbability(fXmax) - GetCumulativeProbability(fXmin))/(fXmax-fXmin);
0174     }
0175     
0176     void Print()
0177     {
0178       G4cout << "fXmin: " << fXmin << " | fXmax: " << fXmax << G4endl;
0179     }
0180 
0181     bool Propose(double proposedXValue,
0182                  double proposedProba,
0183                  double nextProba,
0184                  double& returnedValue)
0185     {
0186 //      G4cout << "---------------------------" << G4endl;
0187 //      G4cout << "Proposed x value: " << proposedXValue
0188 //          << "| proposedProba: " << proposedProba
0189 //          << "| nextProba: " << nextProba
0190 //          << " | fXmin: " << fXmin << " (" << G4DNASmoluchowskiDiffusion::GetCumulativeProbability(fXmin) <<")"
0191 //          << " | fXmax: " << fXmax << " (" << G4DNASmoluchowskiDiffusion::GetCumulativeProbability(fXmax) <<")"
0192 //          << G4endl;
0193 
0194       bool returnFlag = false;
0195       
0196       if(proposedProba < nextProba-fToleranceY) // proba trop petite ==> augmente
0197       {
0198         // G4cout << "proposedProba < nextProba-fToleranceY" << G4endl;
0199 
0200         if(fIncreasingCumulativeFunction > 0) // croissant
0201         {
0202           if(proposedXValue > fXmin)
0203             fXmin = proposedXValue;
0204         }
0205         else if(fIncreasingCumulativeFunction < 0) // decroissant
0206         {
0207           if(proposedXValue < fXmax)
0208             fXmax = proposedXValue;
0209         }
0210         
0211         returnedValue = (fXmax + fXmin)/2;
0212         returnFlag = false;
0213         fPreviousAction = BoundingBox::IncreaseProba;
0214       }
0215       else if(proposedProba > nextProba+fToleranceY) // proba trop grande
0216       {
0217         // G4cout << "proposedProba > nextProba+fToleranceY" << G4endl;
0218 
0219         if(fIncreasingCumulativeFunction>0)
0220         {
0221           if(proposedXValue < fXmax)
0222             fXmax = proposedXValue;
0223         }
0224         else if(fIncreasingCumulativeFunction<0)
0225         {
0226           if(proposedXValue > fXmin)
0227           {
0228             fXmin = proposedXValue;
0229           }
0230         }
0231         
0232         returnedValue = (fXmax + fXmin)/2;
0233         returnFlag = false;
0234         fPreviousAction = BoundingBox::DecreaseProba;
0235       }
0236       else
0237       {
0238         // G4cout << "IN THE INTERVAL !! : " << nextProba << G4endl;
0239         fSum = proposedProba;
0240         
0241         // Assuming search for next proba is increasing
0242         if(fIncreasingCumulativeFunction<0)
0243         {
0244          fXmin = fXminDef;
0245          fXmax = proposedXValue;
0246         }
0247         else if(fIncreasingCumulativeFunction>0)
0248         {
0249           fXmin = proposedXValue;
0250           fXmax = fXmaxDef;
0251         }
0252         returnFlag = true;
0253         fPreviousAction = BoundingBox::Undefined;
0254       }
0255       
0256       return returnFlag;
0257     }
0258   };
0259   // END OF BOUNDING BOX
0260   //==============================
0261   
0262   void PrepareReverseTable(double xmin, double xmax)
0263   {
0264     double x = xmax;
0265     int index = 0;
0266     double nextProba = fEpsilon;
0267     double proposedX;
0268 
0269     BoundingBox boundingBox(xmin, xmax, fEpsilon*1e-5);
0270 
0271     while(index <= fNbins)
0272     // in case GetCumulativeProbability is exact (digitally speaking), replace with:
0273     // while(index <= fNbins+1)
0274     {
0275       nextProba = fEpsilon*index;
0276 
0277       double newProba = GetCumulativeProbability(x);
0278 
0279       if(boundingBox.Propose(x, newProba, nextProba, proposedX))
0280       {
0281         fInverse[index] = x;
0282         index++;
0283       }
0284       else
0285       {
0286         if(x == proposedX)
0287         {
0288           G4cout << "BREAK : x= " << x << G4endl;
0289           G4cout << "index= " << index << G4endl;
0290           G4cout << "nextProba= " << nextProba << G4endl;
0291           G4cout << "newProba= " << newProba << G4endl;
0292           abort();
0293         }
0294         x = proposedX;
0295       }
0296     }
0297     
0298     fInverse[fNbins+1] = 0; // P(1) = 0, because we want it exact !
0299     // Tips to improve the exactness: get an better value of pi, get better approximation of erf and exp, use long double instead of double
0300 //    boundingBox.Print();
0301   }
0302 
0303   static double GetCumulativeProbability(double sTransform)
0304   {
0305     static double constant = 2./std::sqrt(3.141592653589793);
0306     return erfc(sTransform) + constant*sTransform*G4Exp(-sTransform*sTransform);
0307   }
0308 
0309   double GetInverseProbability(double proba) // returns sTransform
0310   {
0311     auto  index_low = (size_t) trunc(proba/fEpsilon);
0312     
0313     if(index_low == 0) // assymptote en 0
0314     {
0315       index_low = 1;
0316       size_t index_up = 2;
0317       double low_y = fInverse[index_low];
0318       double up_y = fInverse[index_up];
0319       double low_x = index_low*fEpsilon;
0320       double up_x = proba+fEpsilon;
0321       double tangente = (low_y-up_y)/(low_x - up_x); // ou utiliser GetDifferential(proba) ?
0322       // double tangente = GetDifferential(proba);
0323       return low_y + tangente*(proba-low_x);
0324     }
0325 
0326     size_t index_up = index_low+1;
0327     if(index_low > fInverse.size()) return fInverse.back();
0328     double low_y = fInverse[index_low];
0329     double up_y = fInverse[index_up];
0330 
0331     double low_x = index_low*fEpsilon;
0332     double up_x = low_x+fEpsilon;
0333 
0334     if(up_x > 1) // P(1) = 0
0335     {
0336       up_x = 1;
0337       up_y = 0; // more general : fInverse.back()
0338     }
0339 
0340     double tangente = (low_y-up_y)/(low_x - up_x);
0341 
0342     return low_y + tangente*(proba-low_x);
0343   }
0344 
0345   double PlotInverse(double* x, double* )
0346   {
0347     return GetInverseProbability(x[0]);
0348   }
0349 
0350   double Plot(double* x, double* )
0351   {
0352     return GetDifferential(x[0]);
0353   }
0354 
0355 
0356   void InitialiseInverseProbability(double xmax = 3e28)
0357   {
0358     // x > x'
0359     // P'(x) = p(x') = lim(x->x') (P(x') - P(x))/(x'-x)
0360     // x'-x = (P(x') - P(x))/p(x')
0361     // x = x' - (P(x') - P(x))/p(x')
0362 
0363     // fInverse initialized in the constructor
0364 
0365     assert(fNbins !=0);
0366     PrepareReverseTable(0,xmax);
0367   }
0368 
0369   std::vector<double> fInverse;
0370   int fNbins;
0371   double fEpsilon;
0372 };
0373 
0374 #endif /* SOURCE_PROCESSES_ELECTROMAGNETIC_DNA_MODELS_G4DNASMOLUCHOWSKIDIFFUSION_HH_ */