We define a Python class Polygon which takes as argument a list of coordinates and a parameter. The purpose of this class is twofold:
it stores all vertices an a convenient manner
it sorts the vertices in CCW order.
Show the code
class Polygon:def__init__(self, x, z, density): xc = np.mean(x) zc = np.mean(z) angles = np.array([np.arctan2(p[1] - zc, p[0] - xc) for p inzip(x, z)]) ind = np.argsort(angles) # if reverse order is required, flip sign of angles x = x[ind] z = z[ind] x = np.append(x, x[0]) z = np.append(z, z[0]) x[isclose(x, 0.0)] =0.0 z[isclose(z, 0.0)] =0.0self.x = xself.z = zself.density = densityself.n =len(x) -1def__str__(self):returnf"n: {self.n}\nx:\n{self.x}\nz:\n{self.z}\nDensity:\n{self.density}"
To compare the numerical results, we provide here a simple function which computes the gravitational attraction of a horizontal cylinder of mass m that intersects the vertical plane at the coordinate given by the 2-D array axis. The point of observation is given by the coordinates in the 2-D array obs:
g = cylinder(obs, mass, axis)
Show the code
def cylinder(obs, mass, axis): g =-2*6.674e-11* mass / np.linalg.norm(obs - axis)**2* (obs - axis)return g
The following code implements the Talwani approach:
We define a cylinder of radius \(r=8\) m at a depth of \(z=20\) m that will be approximated in the \(x-z\)-plane by a sufficiently large number of line segments around its enclosing circle.
Show the code
n =32xc =0.0zc =20.0radius =8.0x = np.array([xc + radius * np.cos(1e-6+2* np.pi * k / n) for k in np.linspace(0, n-1, n)])z = np.array([zc + radius * np.sin(1e-6+2* np.pi * k / n) for k in np.linspace(0, n-1, n)])poly = Polygon(x, z, 500)
Comparison of analytical and numerical solutions (left) and absolute difference (right).
The relative error is
Show the code
print(norm(gtal - gcyl) / norm(gcyl))Ac = np.pi * radius**2print(f"Area ratio is {A/Ac:.4e}")
5.711301342967773e-15
Area ratio is 9.9359e-01
CautionNote
We have seen that in Python a comparison of floats to zero is dangerous. This is why we use np.isclose() with appropriate tolerances (ATOL and RTOL) throughout the talwani function instead of direct equality checks. Direct comparisons like xv == 0.0 can fail due to floating-point arithmetic precision issues, leading to incorrect results in the special case handling (cases A through G in the implementation).