GammaRV.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 2001, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** Reliability module developed by:                                   **
00020 **   Terje Haukaas (haukaas@ce.berkeley.edu)                          **
00021 **   Armen Der Kiureghian (adk@ce.berkeley.edu)                       **
00022 **                                                                    **
00023 ** ****************************************************************** */
00024                                                                         
00025 // $Revision: 1.6 $
00026 // $Date: 2003/03/04 00:44:33 $
00027 // $Source: /usr/local/cvs/OpenSees/SRC/reliability/domain/distributions/GammaRV.cpp,v $
00028 
00029 
00030 //
00031 // Written by Terje Haukaas (haukaas@ce.berkeley.edu) 
00032 //
00033 
00034 #include <GammaRV.h>
00035 #include <math.h>
00036 #include <string.h>
00037 #include <Vector.h>
00038 #include <classTags.h>
00039 
00040 GammaRV::GammaRV(int passedTag, 
00041                  double passedMean,
00042                  double passedStdv,
00043                  double passedStartValue)
00044 :RandomVariable(passedTag, RANDOM_VARIABLE_gamma)
00045 {
00046         tag = passedTag ;
00047         k = (passedMean/passedStdv) * (passedMean/passedStdv);
00048         lambda = passedMean / (passedStdv*passedStdv);
00049         startValue = passedStartValue;
00050 }
00051 GammaRV::GammaRV(int passedTag, 
00052                  double passedParameter1,
00053                  double passedParameter2,
00054                  double passedParameter3,
00055                  double passedParameter4,
00056                  double passedStartValue)
00057 :RandomVariable(passedTag, RANDOM_VARIABLE_gamma)
00058 {
00059         tag = passedTag ;
00060         k = passedParameter1;
00061         lambda = passedParameter2;
00062         startValue = passedStartValue;
00063 }
00064 GammaRV::GammaRV(int passedTag, 
00065                  double passedMean,
00066                  double passedStdv)
00067 :RandomVariable(passedTag, RANDOM_VARIABLE_gamma)
00068 {
00069         tag = passedTag ;
00070         k = (passedMean/passedStdv) * (passedMean/passedStdv);
00071         lambda = passedMean / (passedStdv*passedStdv);
00072         startValue = getMean();
00073 }
00074 GammaRV::GammaRV(int passedTag, 
00075                  double passedParameter1,
00076                  double passedParameter2,
00077                  double passedParameter3,
00078                  double passedParameter4)
00079 :RandomVariable(passedTag, RANDOM_VARIABLE_gamma)
00080 {
00081         tag = passedTag ;
00082         k = passedParameter1;
00083         lambda = passedParameter2;
00084         startValue = getMean();
00085 }
00086 
00087 
00088 GammaRV::~GammaRV()
00089 {
00090 }
00091 
00092 
00093 void
00094 GammaRV::Print(OPS_Stream &s, int flag)
00095 {
00096 }
00097 
00098 
00099 double
00100 GammaRV::getPDFvalue(double rvValue)
00101 {
00102         double result;
00103         if ( 0.0 < rvValue ) {
00104                 result = lambda*pow((lambda*rvValue),(k-1.0))*exp(-lambda*rvValue) / gammaFunction(k);
00105         }
00106         else {
00107                 result = 0.0;
00108         }
00109         return result;
00110 }
00111 
00112 
00113 double
00114 GammaRV::getCDFvalue(double rvValue)
00115 {
00116         double result;
00117         if ( 0.0 < rvValue ) {
00118                 result = incompleteGammaFunction(k,(lambda*rvValue));
00119         }
00120         else {
00121                 result = 0.0;
00122         }
00123 
00124         return result;
00125 }
00126 
00127 
00128 double
00129 GammaRV::getInverseCDFvalue(double probValue)
00130 {
00131         double result = 0.0;
00132         // Here we want to solve the nonlinear equation:
00133         //         probValue = getCDFvalue(x)
00134         // with respect to x. 
00135         // A Newton scheme to find roots - f(x)=0 - looks something like:
00136         //         x(i+1) = x(i) - f(xi)/f'(xi)
00137         // In our case the function f(x) is: f(x) = probValue - getCDFvalue(x)
00138         // The derivative of the function can be found approximately by a
00139         // finite difference scheme where e.g. stdv/200 is used as perturbation.
00140         double tol = 0.000001;
00141         double x_old = getMean();   // Start at the mean of the random variable
00142         double x_new;
00143         double f;
00144         double df;
00145         double h;
00146         double perturbed_f;
00147         for (int i=1;  i<=100;  i++ )  {
00148                 // Evaluate function
00149                 f = probValue - getCDFvalue(x_old);
00150                 // Evaluate perturbed function
00151                 h = getStdv()/200.0;
00152                 perturbed_f = probValue - getCDFvalue(x_old+h);
00153                 // Evaluate derivative of function
00154                 df = ( perturbed_f - f ) / h;
00155                 // Take a Newton step
00156                 x_new = x_old - f/df;
00157                 // Check convergence; quit or continue
00158                 if (fabs(1.0-fabs(x_old/x_new)) < tol) {
00159                         result = x_new;
00160                 }
00161                 else {
00162                         if (i==100) {
00163                                 opserr << "WARNING: Did not converge to find inverse CDF!" << endln;
00164                                 result = 0.0;
00165                         }
00166                         else {
00167                         x_old = x_new;
00168                         }
00169                 }
00170         }
00171         return result;
00172 }
00173 
00174 
00175 const char *
00176 GammaRV::getType()
00177 {
00178         return "GAMMA";
00179 }
00180 
00181 
00182 double 
00183 GammaRV::getMean()
00184 {
00185         return k/lambda;
00186 }
00187 
00188 
00189 
00190 double 
00191 GammaRV::getStdv()
00192 {
00193         return sqrt(k)/lambda;
00194 }
00195 
00196 
00197 double 
00198 GammaRV::getStartValue()
00199 {
00200         return startValue;
00201 }
00202 
00203 
00204 
00205 double GammaRV::getParameter1()  {return k;}
00206 double GammaRV::getParameter2()  {return lambda;}
00207 double GammaRV::getParameter3()  {opserr<<"No such parameter in r.v. #"<<tag<<endln; return 0.0;}
00208 double GammaRV::getParameter4()  {opserr<<"No such parameter in r.v. #"<<tag<<endln; return 0.0;}
00209 
00210 
00211 
00212 
00213 
00214 double
00215 GammaRV::gammaFunction(double x)
00216 {
00217         double res;
00218 
00219         if (x==0 || ( x < 0.0 && floor(x)==x ) )  {
00220                 opserr << "Invalid input to the gamma function" << endln;
00221         }
00222         else {
00223                 Vector p(9);
00224                 Vector q(9);
00225                 Vector c(8);
00226 
00227                 p(0) = 0.0;
00228                 p(1) = -1.71618513886549492533811e+0; 
00229                 p(2) = 2.47656508055759199108314e+1;
00230                 p(3) = -3.79804256470945635097577e+2; 
00231                 p(4) = 6.29331155312818442661052e+2;
00232                 p(5) = 8.66966202790413211295064e+2; 
00233                 p(6) = -3.14512729688483675254357e+4;
00234                 p(7) = -3.61444134186911729807069e+4; 
00235                 p(8) = 6.64561438202405440627855e+4;
00236                 
00237                 q(0) = 0.0;
00238                 q(1) = -3.08402300119738975254353e+1; 
00239                 q(2) = 3.15350626979604161529144e+2;
00240                 q(3) = -1.01515636749021914166146e+3; 
00241                 q(4) = -3.10777167157231109440444e+3;
00242                 q(5) = 2.25381184209801510330112e+4; 
00243                 q(6) = 4.75584627752788110767815e+3;
00244                 q(7) = -1.34659959864969306392456e+5; 
00245                 q(8) = -1.15132259675553483497211e+5;
00246                 
00247                 c(0) = 0.0;
00248                 c(1) = -1.910444077728e-03; 
00249                 c(2) = 8.4171387781295e-04;
00250                 c(3) = -5.952379913043012e-04; 
00251                 c(4) = 7.93650793500350248e-04;
00252                 c(5) = -2.777777777777681622553e-03; 
00253                 c(6) = 8.333333333333333331554247e-02;
00254                 c(7) = 5.7083835261e-03;
00255 
00256                 double pi = 3.14159265358979;
00257                 double y;
00258                 double y1;
00259                 double fact;
00260                 double x1;
00261                 double xn;
00262                 double ysq;
00263                 double sum;
00264                 double spi;
00265                 bool flag01 = false;
00266                 bool flag1_12 = false;
00267                 bool flagNegative = false;
00268 
00269                 // If x is negative
00270                 if (x<0.0) {
00271                         y = -x;
00272                         y1 = floor(y);
00273                         res = y - y1;
00274                         fact = -pi / sin(pi*res) * (1 - 2*fmod(y1,2));
00275                         x = y + 1;
00276                         flagNegative = true;
00277                 }
00278                 // Now x is positive
00279 
00280                 // Map x in interval [0,1] to [1,2]
00281                 if (x<1.0) {
00282                         x1 = x;
00283                         x = x1 + 1.0;
00284                         flag01 = true;
00285                 }
00286 
00287                 // Map x in interval [1,12] to [1,2]
00288                 if (x<12.0) {
00289                         xn = floor(x) - 1;
00290                         x = x - xn;
00291                         // Evaluate approximation for 1 < x < 2
00292                         double z = x - 1.0;
00293                         double xnum = 0.0;
00294                         double xden = xnum + 1.0;
00295 
00296                         
00297                         for (int i = 1 ; i<=8; i++ ) {
00298                                 xnum = (xnum + p(i)) * z;
00299                                 xden = xden * z + q(i);
00300                         }
00301 
00302                         res = xnum / xden + 1.0;
00303                         flag1_12 = true;
00304                 }
00305 
00306                 // Adjust result for case  0.0 < x < 1.0
00307                 if (flag01)  {
00308                         res = res / x1;
00309                 }
00310                 else if (flag1_12){   // Adjust result for case  2.0 < x < 12.0
00311                         double max_xn = xn;
00312                         for (int m=1;  m<=max_xn; m++) {
00313                                 res = res * x;
00314                                 x = x + 1;
00315                                 xn = xn - 1;
00316                         }
00317                 }
00318 
00319                 // Evaluate approximation for x >= 12
00320                 if (x>=12.0) {
00321                         y = x;
00322                         ysq = y * y;
00323                         sum = c(7);
00324                         for (int i = 1; i<=6; i++ ) {
00325                                 sum = sum / ysq + c(i);
00326                         }
00327 
00328                         spi = 0.9189385332046727417803297;
00329                         sum = sum / y - y + spi;
00330                         sum = sum + (y-0.5)*log(y);
00331                         res = exp(sum);
00332                 }
00333 
00334                 if (flagNegative) {
00335                         res = fact / res;
00336                 }
00337         }
00338         
00339         return res;
00340 }
00341 
00342 
00343 
00344 double 
00345 GammaRV::incompleteGammaFunction(double x, double a)
00346 {
00347         double gam = log(gammaFunction(a));
00348         double b = x;
00349         if (x==0.0) {
00350                 b = 0.0;
00351         }
00352         if (a==0.0) {
00353                 b = 1.0;
00354         }
00355         // Series expansion for x < a+1
00356         if (a!=0.0 && x!=0.0 && x<a+1.0) {
00357                 double ap = a;
00358                 double sum = 1.0/ap;
00359                 double del = sum;
00360                 while (fabs(del) >= 1.0e-10*fabs(sum)) {
00361                         ap = ap + 1.0;
00362                         del = x * del / ap;
00363                         sum = sum + del;
00364                 }
00365                 b = sum * exp(-x + a*log(x) - gam);
00366         }
00367 
00368         // Continued fraction for x >= a+1
00369         if ((a != 0) && (x != 0) && (x >= a+1.0))  {
00370                 double a0 = 1.0;
00371                 double a1 = x;
00372                 double b0 = 0.0;
00373                 double b1 = a0;
00374                 double fac = 1.0;
00375                 double n = 1;
00376                 double g = b1;
00377                 double gold = b0;
00378                 while (fabs(g-gold) >= 1.0e-10*fabs(g))  {
00379                         gold = g;
00380                         double ana = n - a;
00381                         a0 = (a1 + a0 *ana) * fac;
00382                         b0 = (b1 + b0 *ana) * fac;
00383                         double anf = n*fac;
00384                         a1 = x * a0 + anf * a1;
00385                         b1 = x * b0 + anf * b1;
00386                         fac = 1.0 / a1;
00387                         g = b1 * fac;
00388                         n = n + 1.0;
00389                 }
00390                 b = 1 - exp(-x + a*log(x) - gam) * g;
00391         }
00392 
00393         return b;
00394 }

Generated on Mon Oct 23 15:05:26 2006 for OpenSees by doxygen 1.5.0