propagateErrorLN.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import numpy
  2. import convolveLN
  3. def generateSample(mu,cv):
  4. return numpy.array([convolveLN.ln(mu,cv) for i in range(10000)])
  5. def getEdges(a):
  6. #convert array of bin centers a to array of bin edges with one more element than a
  7. a1=numpy.zeros(len(a)+1)
  8. a2=numpy.zeros(a1.shape)
  9. a1[1:]=a
  10. a2[:-1]=a
  11. e=0.5*(a1+a2)
  12. e[0]=2*e[1]-e[2]
  13. e[-1]=2*e[-2]-e[-3]
  14. return e
  15. def calculateDistribution(fy,muTarget,mu,cv,dydp):
  16. #calculate distribution of random variable y with a functional dependence
  17. #on random parameters p, each with a log-normal
  18. #distribution with a mean mu(p) and coefficients of variation cv(p)
  19. #and dydp giving partial derivatives of y on p
  20. #muTarget is the target mean of y distribution
  21. #fy is the set of values y where distribution is evaluated at
  22. #Parameters mu, cv and dydp are given as vectors/lists
  23. qa=mu*dydp
  24. A=numpy.sum(qa)
  25. qa*=muTarget/A
  26. cvPrime=cv*A/muTarget
  27. sigmaS=numpy.sqrt(numpy.log(1+cvPrime*cvPrime))
  28. muS=numpy.log(qa/numpy.sqrt(1+cvPrime*cvPrime))
  29. y=convolveLN.convolveLN(fy,sigmaS,muS)
  30. return y/numpy.sum(y)
  31. def generateDistribution(fx,muTarget,mu,cv,dydp, dbg=0):
  32. #sum randomly generated variables to approximate distribution of
  33. #variable y with a functional dependence y(p) on random parameters p,
  34. #each with a log-normal (LN) distribution
  35. #with a mean mu(p) and coefficient of variation cv(p)
  36. #target mean of y is muTarget
  37. #distribution is evaluated at points fy,
  38. #dydp are derivatives of y with respect to parameters p
  39. qa=mu*dydp
  40. A=numpy.sum(qa)
  41. qa*=muTarget/A
  42. cvPrime=cv*A/muTarget
  43. samples=[a*generateSample(1,c) for a,c in zip(qa,cvPrime)]
  44. mean=[numpy.mean(s) for s in samples]
  45. std=[numpy.std(s) for s in samples]
  46. convSample=numpy.zeros(len(samples[0]))
  47. msg='[{}] mean={:.2f} std={:.2f} cv={:.2f}'
  48. for i in range(len(cv)):
  49. convSample+=samples[i]
  50. if dbg:
  51. print(msg.format(i,mean[i],std[i],std[i]/mean[i]))
  52. convM=numpy.mean(convSample)
  53. convS=numpy.std(convSample)
  54. if dbg:
  55. code=x
  56. print(msg.format(code,convM,convS,convS/convM))
  57. h,be=numpy.histogram(convSample,bins=getEdges(fx))
  58. #h should be len(fx)
  59. return h/numpy.sum(h)