Skip to content

Commit

Permalink
added numerical integrator and libray call to __innit
Browse files Browse the repository at this point in the history
  • Loading branch information
Witt-D committed Jul 24, 2023
1 parent cb0c056 commit eb21002
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
1 change: 1 addition & 0 deletions gusto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
from gusto.timeloop import * # noqa
from gusto.transport_methods import * # noqa
from gusto.wrappers import * # noqa
from gusto.numerical_integrator import * # noqa
56 changes: 56 additions & 0 deletions gusto/numerical_integrator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import numpy as np


class NumericalIntegral(object):
"""
A class for numerically evaluating and tabulating some 1D integral.
:arg lower_bound: lower bound of integral
:arg upper_bound: upper_bound of integral
:arg num_points: number of points to tabulate integral at
"""
def __init__(self, lower_bound, upper_bound, num_points=500):

# if upper_bound <= lower_bound:
# raise ValueError('lower_bound must be lower than upper_bound')
self.x = np.linspace(lower_bound, upper_bound, num_points)
self.x_double = np.linspace(lower_bound, upper_bound, 2*num_points-1)
self.lower_bound = lower_bound
self.upper_bound = upper_bound
self.num_points = num_points
self.tabulated = False

def tabulate(self, expression):
"""
Tabulate some integral expression using Simpson's rule.
:arg expression: a function representing the integrand to be evaluated.
Should take a numpy array as an argument.
"""

self.cumulative = np.zeros_like(self.x)
self.interval_areas = np.zeros(len(self.x)-1)
# Evaluate expression in advance to make use of numpy optimisation
# We evaluate at the tabulation points and the midpoints of the intervals
f = expression(self.x_double)

# Just do Simpson's rule for evaluating area of each interval
self.interval_areas = ((self.x[1:] - self.x[:-1]) / 6.0
* (f[2::2] + 4.0 * f[1::2] + f[:-1:2]))

# Add the interval areas together to create cumulative integral
for i in range(self.num_points - 1):
self.cumulative[i+1] = self.cumulative[i] + self.interval_areas[i]

self.tabulated = True

def evaluate_at(self, points):
"""
Evaluates the integral at some point using linear interpolation.
:arg points: the point value, or array of point values to evaluate
the integral at.
"""
# Do linear interpolation from tabulated values
if not self.tabulated:
raise RuntimeError(
'Integral must be tabulated before we can evaluate it at a point')

return np.interp(points, self.x, self.cumulative)

0 comments on commit eb21002

Please sign in to comment.