Mapping dynamics

While sifting through some of my files yesterday, I found a spread-sheet using Gaussian elimination technique, refreshing old memories. In 2004, we were engineering a spar + topside — the first of its kind for the region. For transport, we designed the topside to straddle atop two lean barges — like a catamaran. This enabled the topside to be floated over, and mate with the spar. (Image courtesy: Offshore Kinematics Inc. OTC 19639 paper offers more details on installation.)

Kikeh's topside straddling two dummy barges like a catamaran, the novelty that put Murphy Oil back in Southeast Asian waters beating other super majors, is in view, and is ready to mate with its substructure, the mighty deep truss spar, Asia's first deep water offshore structure. (Image courtesy: Offshore Kinematics Inc)
Kikeh's topside straddling two dummy barges like a catamaran, the novelty that put Murphy Oil back in Southeast Asian waters beating other super majors, is in view, and is ready to mate with its substructure, the mighty deep truss spar, Asia's first deep water offshore structure. (Courtesy: OKI)

We quickly realised that the catamaran arrangement was a stiffness hog for the topside during tow (racking moments resulting from quartering seas) — driving the need for more steel in the topside, far more than in its in-service conditions. (Michael Luo’s US 8312828 B2 patent titled, “Pre-loading to reduce loads and save steel on topsides and grillage of catamaran systems” describes the measures we took to save steel.)

Marine team furnished motion-induced dynamic loads of the catamaran barge ensemble (from motion responses) for topside stress check during its fourteen-day tow. To transfer these on to the topside as inertia loads, we did the following:

  1. First, we converted the dynamic loads into topside coordinate system along with sign conventions.
  2. Then, we generated inertia loads on topside corresponding to 1.0⋅g of linear (surge, sway, heave) and angular accelerations (roll, pitch, yaw), which resulted in a load case each — six in total, with each containing loads (Fx, Fy, Fz) and moments (Mx, My, Mz).
  3. From the two above, the idea was to get suitable factor to apply to the loads generated in step 2 to match the dynamic loads received from the Marine team — using the Gaussian elimination technique.

Upon solving the following grid, we’d end up with six load factors to multiply with our set of six inertia load sets respectively.

+-                                 -+
| Fx1  Fx2  Fx3  Fx4  Fx5  Fx6 | Fx |
| Fy1  Fy2  Fy3  Fy4  Fy5  Fy6 | Fy |
| Fz1  Fz2  Fz3  Fz4  Fz5  Fz6 | Fz |
| Mx1  Mx2  Mx3  Mx4  Mx5  Mx6 | Mx |
| My1  My2  My3  My4  My5  My6 | My |
| Mz1  Mz2  Mz3  Mz4  Mz5  Mz6 | Mz |
+-                                 -+

Back to the spreadsheet, I noticed that we had actually generated a multiple pivot-eliminate routines through iterations, until all coefficients (except the principal diagonal) were decomposed, and coefficients in the principal diagonal contained 1 each — as is done in the technique.

Matrices are now available in most modern computing software. Gaussian elimination, on the other hand, was perhaps from an era of logarithms and radians — designed to simplify computational complexity when done by hand. So, I am not sure why we used this technique, in lieu of matrix functions in Excel or MathCAD available at our disposal.

Following the classic recipe of solving linear equations (A . x = B) for x, a column matrix of load factors, where A is a square matrix of inertia loads — corresponding to 1.0⋅g, and B is a column matrix of dynamic loads from catamaran’s motion responses, I punched in the two arrays to see if I could get the same set of x. Here’s how simple it is with numpy:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
mat.py -- 2015 ckunte.
"""
import numpy

def main():
    # Inertia matrix, A, corresponds to 1.0g in surge, sway, 
    # heave, roll, pitch, and yaw.    
    A = numpy.mat("[-11364.0, 0.0, 0.0, 0.0, -412.3, -9.1; \
        0.0, -11364.0, 0.0, 412.3, 0.0, -9.9; \
        0.0, 0.0, -11364.0, 9.1, 9.9, 0.0; \
        0.0, 231661.7, 5129.7, -11569.7, 322.5, 266.6; \
        -231661.7, 0.0, 5574.3, 322.5, -15050.3, -239.8; \
        -5129.7, -5574.3, 0.0, 266.6, -239.8, -8929.5]")
    # Motion-induced dynamic loads (one of numerous cases)
    B = numpy.mat("[-2961.0; -1358.0; -40613.0; 119921.5; \
    -68588.5; 210347.9]")
    # getI() is the matrix inverse function from numpy.
    x = A.getI() * B
    print x

if __name__ == '__main__':
    main()

The output looks like below — matching the result we’d obtained from Gaussian elimination method:

$ python mat.py
[[  0.16090823]
 [ -0.71351288]
 [  3.55783674]
 [-23.53602482]
 [  3.27622169]
 [-23.99421225]]