For points in recur_data, compute { Note: The length of the return is one less than the length of recur_data. partial_integrals() uses a method with an error O(dx**10) with full information from the derivatives. the integration is adaptive, starting from the grid provided, and returning data in the intervals between the grid points.
Definition at line 316 of file C2Functions.py. 00316 : 00317 """def partial_integrals(self, xgrid, relative_error_tolerance=1e-12, derivs=2, 00318 absolute_error_tolerance=1e-12, depth=0, debug=0, extrapolate=1, allow_recursion=True) 00319 Return the integrals of a function between the sampling points xgrid. 00320 The sum is the definite integral. 00321 The choices for derivs are 0, 1 or 2, anything else is an error. 00322 The derivs parameter is used as follows: 00323 derivs=0 uses Simpsons rule (no derivative information). 00324 derivs=1 uses a 6th order technique based the first derivatives, but no second derivatives 00325 derivs=2 uses a 9th (really 10th, since the 9th order error vanishes by symmetry) 00326 order tehcnique based the first and second derivatives. 00327 Be very aware that the 9th order method will only really benefit with very smooth functions, 00328 but then it is magic! 00329 """ 00330 00331 if type(recur_data[1]) is not tuple: #this is an initialization call, set everything up 00332 funcgrid=[ ( (x, )+ self.value_with_derivatives(x) ) for x in recur_data ] 00333 self.total_func_evals=len(recur_data) 00334 00335 derivs= args.get('derivs', 2) 00336 if derivs==0: 00337 eps_scale, extrap_coef= 0.1, 16.0 00338 elif derivs==1: 00339 eps_scale, extrap_coef = 0.1, 64.0 00340 elif derivs==2: 00341 eps_scale, extrap_coef = 0.01, 1024.0 00342 00343 else: 00344 raise C2Exception("derivs passed to partial_integrals, must be 0, 1 or 2, got %d" % derivs) 00345 00346 allow_rec= args.get('allow_recursion', True) 00347 extrapolate = args.get('extrapolate', True) and allow_rec #can only extrapolate after recursion 00348 00349 recur_data=[0, funcgrid, ( ), 00350 args.get('absolute_error_tolerance', 1e-12), 00351 args.get('relative_error_tolerance', 1e-12), 00352 args.get('debug', 0), 00353 extrapolate, derivs, eps_scale, extrap_coef, allow_rec 00354 ] 00355 00356 (depth, funcgrid, old_integrals, absolute_error_tolerance, relative_error_tolerance, 00357 debug, extrapolate, derivs, eps_scale, extrap_coef, allow_rec)=recur_data 00358 00359 retvals=[0.0]*(len(funcgrid)-1) 00360 00361 for i in range(len(funcgrid)-1): 00362 x0, y0, yp0, ypp0=funcgrid[i] 00363 x2, y2, yp2, ypp2=funcgrid[i+1] 00364 x1=0.5*(x0+x2) 00365 y1, yp1, ypp1=self.value_with_derivatives(x1) 00366 self.total_func_evals+=1 00367 dx=x2-x0 00368 dx2=0.5*dx 00369 00370 #check for underflow on step size, which prevents us from achieving specified accuracy. 00371 if abs(dx) < abs(x1)*relative_error_tolerance: 00372 raise C2Exception("Step size underflow in partial_integrals, depth = %d, x = %.4f" % 00373 (depth, x1)) 00374 00375 #if we are below the top level, the previous term is already computed. 00376 # Otherwise, compute it to one lower order 00377 if old_integrals: 00378 total=old_integrals[i] 00379 elif derivs==2: 00380 total=( (14*y0 + 32*y1 + 14*y2) + dx * (yp0 - yp2) ) * dx /60. 00381 00382 elif derivs==1: 00383 total=(y0+4.0*y1+y2)*dx/6.0 00384 else: 00385 total=0.5*(y0+y2)*dx 00386 00387 if derivs==2: 00388 #use ninth-order estimates for each side. (Thanks, Mathematica!) 00389 left= ( ( (169*ypp0 + 1024*ypp1 - 41*ypp2)*dx2 + (2727*yp0 - 5040*yp1 + 423*yp2) )*dx2 + 00390 (17007*y0 + 24576*y1 - 1263*y2) )* (dx2/40320.0) 00391 right= ( ( (169*ypp2 + 1024*ypp1 - 41*ypp0)*dx2 - (2727*yp2 - 5040*yp1 + 423*yp0) )*dx2 + 00392 (17007*y2 + 24576*y1 - 1263*y0) )* (dx2/40320.0) 00393 elif derivs==1: 00394 left= ( (202*y0 + 256*y1 + 22*y2) + dx*(13*yp0 - 40*yp1 - 3*yp2) ) * dx /960. 00395 right= ( (202*y2 + 256*y1 + 22*y0) - dx*(13*yp2 - 40*yp1 - 3*yp0) ) * dx /960. 00396 else: 00397 left= (5*y0 + 8*y1 - y2)*dx/24. 00398 right= (5*y2 + 8*y1 - y0)*dx/24. 00399 00400 eps= abs(total-(left+right))*eps_scale 00401 #the real error should be 2**order times smaller on this iteration, be conservative 00402 if extrapolate: 00403 eps=eps*eps_scale 00404 #gain another factor of 2**order if extrapolating (typical), but be conservative 00405 00406 if (not allow_rec) or eps < absolute_error_tolerance or eps < abs(total)*relative_error_tolerance: 00407 if not extrapolate: 00408 retvals[i]=left+right 00409 else: 00410 retvals[i]=(extrap_coef*(left+right) - total) / (extrap_coef-1) 00411 #since h fell by 2, h**6=64, and we are extrapolating in h**6 00412 if debug==1: 00413 print "accepted results at depth ", depth, "x, dx = %7.3f, %10.6f" % (x1, dx), 00414 print "scaled error = ", eps/ (abs(total)*relative_error_tolerance) 00415 else: 00416 if debug==1: 00417 print "rejected results at depth ", depth, "x, dx = %7.3f, %10.6f" % (x1, dx), 00418 print "scaled error = ", eps/ (abs(total)*relative_error_tolerance) 00419 recur_data[0:4]=(depth+1, (funcgrid[i], (x1, y1, yp1, ypp1), funcgrid[i+1]), 00420 (left, right), absolute_error_tolerance/2 ) 00421 l, r =self.partial_integrals(recur_data) 00422 retvals[i]=l+r 00423 if debug ==2: 00424 print "\nintegrating at depth ", depth 00425 print xgrid 00426 print funcgrid 00427 import operator 00428 print retvals 00429 if old_integrals: 00430 print map(operator.sub, old_integrals, retvals) 00431 print "\nreturning from depth ", depth 00432 return retvals 00433 ##
|