September 14, 2014

Validating markup

PyRSS2Gen worked fine as a stop-gap for the last couple of years, despite the fact that it kept generating invalid XML markup for my RSS feed. Thankfully, feed readers seemed more tolerant than the FEED Validator. Chisel initially did not have this method of RSS generation within its code, but was recently accepted by its author from a pull request. I just happened to be using it well before it was officially accepted, since despite its misgivings it seemed to work for me.

Then, on a whim this weekend, I decided to fix the invalid markup, and so in one session, I plucked parts of PyRSS2Gen out, I’d introduced two years ago within chisel.py, and rewrote some of its code to generate an RSS feed natively. I needed a template in Jinja 2, which I further created for this purpose. (In a minute.) A couple of run-ins after with the validator — using various tags and markup escapes, the generated XML markup finally began to validate. Here’s the part I got rid of from chisel.py:

import PyRSS2Gen, datetime

RSS = PyRSS2Gen.RSS2(
    title = "Chyetanya Kunte", # Blog title
    description = "ckunte.net/log.", # Blog description
    link = BASEURL + "rss.xml", 
    lastBuildDate = datetime.datetime.now(),
    items = [])

@step
def gen_rss(f, e):
    for file in f[:3]:
        RSS.items.append(PyRSS2Gen.RSSItem(title=file['title'], link=BASEURL + file['url'], description=file['content'], author="Chyetanya Kunte", guid = PyRSS2Gen.Guid(BASEURL + file['url']), pubDate=datetime.datetime(file['year'], file['month'], file['day'])))
    RSS.write_xml(open(DESTINATION + "rss.xml", "w"))

which I replaced with the following:

RSSDATE_FORMAT = "%a, %d %b %Y %H:%M:%S %z"

def write_feed(url, data):
    path = DESTINATION + url
    with open(path, "w") as file:
        file.write(data.encode('UTF-8'))

@step
def gen_rss(f, e):
    write_feed('rss.xml', e.get_template('feed.html').render(entries=f[:HOME_SHOW]))

The feed.html template is as follows:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
   <title>Chyetanya Kunte</title>
   <description>A personal log</description>
   <atom:link href="http://ckunte.net/log/rss.xml" rel="self" type="application/rss+xml"/>
   <link>http://ckunte.net/log/</link>
   <language>en-us</language>
    {% for entry in entries %}
    <item>
      <title>{{ entry.title | escape }}</title>
      <link>http://ckunte.net/log/{{ entry.url }}</link>
      <guid>http://ckunte.net/log/{{ entry.url }}</guid>
      <pubDate>{{ entry.rssdate }}GMT</pubDate>
      <description>{{ entry.content | escape }}</description>
    </item>
    {% endfor %}
</channel>
</rss>

There’s a bit of unintended appendage — notice the GMT part. The time zone is supposed to be generated by python (%z), but for some reason it wasn’t. So, I plugged it with a quick and dirty manual tag, filing the problem away for later. At this point, the feed was validating, and so I stopped, since it solved the problem.

Buoyed by the idea, I thought I could take on another validation exercise. This one occurred in the footnotes. This wasn’t because of my plain text posts, but because of markdown in python. So, hoping for some improvement, I upgraded it to the latest version with the following:

sudo pip install --upgrade markdown

There was a new version (2.5) alright, but it broke chisel.py. (Yes, these things happen.) Errors suggested it was to do with markdown and mdx_smartypants — a third party extension that played well with an earlier version of markdown in python. Just to re-check I wasn’t seeing stars, I uninstalled the latest version of markdown in python and replaced it with the last working version (v 2.4.1):

sudo pip uninstall markdown
sudo pip install markdown==2.4.1

That got chisel.py working again. To be sure, I looked through 2.5’s release notes to realize that some call instructions to parse were different. For instance, I had this line in chisel.py:

FORMAT = lambda text: markdown.markdown(text, ['smartypants','footnotes'])

The release note advocated the following instead:

FORMAT = lambda text: markdown.markdown(text, extensions=['markdown.extensions.smarty','markdown.extensions.footnotes'])

Upon further checking through supported third party extensions, I realized mdx_smartypants did not make the list, which meant I needed to use the official extensions within markdown as above. So, I uninstalled mdx_smartypants, and replaced the above in chisel.py to get it working. The official smarty extension turned out to be different in the way it encoded emdash and endashes. (With mdx_smartypants, it was two dashes to produce an emdash, and one for endash. The official smarty extension requires three dashes to produce an emdash, and two for endash.) So, batch search and replace to the rescue:

perl -pi -w -e 's/ -- / --- /g;' *.md

Now all is well again; the update to the new markdown 2.5 did not fix the validation errors concerning footnotes; so posts with footnotes still do not validate. But I am happy to note that from this exercise, chisel’s line count was actually reduced by two lines. :)

August 30, 2014

Fram and Vasa

On our two-weeks trip across Scandinavia, spending three days each in Oslo, and Stockholm, I got a chance to see two legendary Nordic ships: Fram and Vasa. Separated by 265 years, with one being the first ever to go closest to both geographic poles in human history, while the other sank after sailing only twenty minutes into its maiden voyage. Yet they both capture public’s imagination like few other. In the case of Fram, it is not hard to see why.

Fram

Well funded marine expeditions began around mid-nineteenth century to find a new northwest sea passage through Greenland interior or the Canadian arctic archipelago to the Pacific towards the riches of Asia. Successive attempts, however, were met with one disaster after another. Nearly everyone who tried, could not go past frozen waterways of the archipelago. The wooden boats were no match to the formidable crushing pressure of sheet or pack ice.

Despite these challenges, the British explorers managed to chart greater parts of the region from their successive failed attempts, and documented what worked and what didn’t. While this went on, in 1888, Fridtjof Nansen’s early success in penetrating Greenland’s inland ice, at 27 years of age, grew his ambitions of reaching the North Pole. Nansen handed the arduous task of building a custom ship for this extreme adventure to Scottish-Norwegian shipwright, Colin Archer. Archer then went on to design Fram featuring a belly-like hull of extraordinary strength, using strongest oak timbers and well braced intricate system, with an awkward 3:1 length to beam ratio, so it would slip up from pack ice’s wedge-like grip.

In March 1895, Fram (Norwegian for Forward) reached a never-before achieved latitude of 84°4’N. With unreliable drift thereafter, Nansen then made a final dash towards to North Pole on skis and dog sledges. The last mile is excruciating just to read, and I cannot imagine a worse expedition — weather wise. He eventually turned back just shy of 3°46’ — approximately 230 nautical miles south of North Pole. Miraculously or by design, Fram survived the worst on its return voyage before sailing south to Tromsø. It made Nansen and Fram legends, but Nansen would never sail again. The arctic crushes the toughest, as they say. Nansen’s pioneering techniques of travel and survival would come to influence all subsequent explorations.

Inspired by Nansen’s achievements and techniques, Roald Amundsen in 1906, after three years of trying, achieved a break-through in successfully navigating across the Canadian arctic archipelago and found the north west passage in a similarly proportioned 45ton fishing vessel Gjøa, thereby proving to the World that Pacific could be reached via the archipelago. Four years later, Amundsen would take the Fram (used by Nansen for his North Pole expedition) to a South Pole expedition. In this expedition, Fram reached the farthest possible latitude of 78°41’S before Amundsen and team began the rest of the journey on sledges and skis to the South Pole, successfully reaching it on 14 December 1911. (Robert Scott, his British counterpart, reached over a month late, and unlike Amundsen and team, he and four of his crew did not survive the return journey to base.)

Fram

Standing humble in an understated museum belies their incredible achievements in history. We took the kids to see Fram and Gjøa stand every inch proud at their home in Oslo, the Fram museum this August. (Low light iPhone photography is hard. If not for my lovely wife’s numerous photos of the Fram, I wouldn’t have had a decent picture.)

Vasa

If Fram was a boat for the nordic polar conquerors, Vasa was an unprecedented tragedy — of very low metacentric height, of over-reliance on geometric proportions, of high ambitions, of immaturity in the art of naval architecture, of fear of breaking unfavorable news to the king of Sweden, and of poor judgement of ballast by its captain.

Sweden was fighting its two great foes: Denmark — to reduce its navigation tax, and Russia — to open up its markets. Prior to Vasa, Sweden had lost twelve of its large vessels in the 1620s — one captured, one self-destroyed while resisting capture, and ten ran aground in the Bay of Riga, prompting the king to urgently seek replacements to keep up the pressure in the Baltic.

Armed to gills with two gun decks full totaling an unprecedented sixty-four bronze cannons, specially cast in Stockholm, the ambition and intent of Gustavus was fierce. An operational Vasa as a destroyer would have been a terror of the Baltic, where it was to rendezvous with the king’s fleet, striking fear into the hearts of Sweden’s enemies.

Through changing specifications, an ill shipwright, poor change management, and shortened delivery date due to urgent pleas from the battle field, Vasa got built despite failing a stability test (third run stopped as Vasa begins heeling and heaving violently as 30 men run back and forth on the top deck to test) conducted by Rear Admiral Klas Fleming.

Just as it set sail from Stockholm port on August 10, 1628, catching the southwest squall, Vasa began heeling hard over its lee-side to the extent that lower gun ports began taking water, and disappeared. The crux of this tragedy is succinctly summarized in a paper by Richard Fairley and Mary Jane Willshire:

Methods for calculating the center of gravity, heeling characteristics, and stability factors for sailing ships were unknown, so ships’ captains had to learn their vessels’ operational characteristics by trial-and-error testing. The Vasa was the most spectacular, but certainly not the only ship to capsize during the 17th and 18th centuries. Measurements taken and calculations performed since 1961 indicate that the Vasa was so unstable that it would have capsized at a heeling over of 10° it could not have withstood the estimated wind gust of 8 knots (9 miles per hour) that caused the ship to capsize. Recent calculations indicate the ship would have capsized in a breeze of 4 knots. That the wind was so light during the Vasa’s initial (and final) cruise is verified by the fact that the crew had to extend the sails by hand upon launch.

What’s remarkable about Vasa though is not how it went down, but after 333 sunken years, when it was raised in 1961 in a televised national effort, it turned out to be over 90% intact! The theory is that the sheltered Stockholm harbor, and Baltic Sea’s low salinity prevented worms from destroying the wooden vessel.

Vasa

Sweden’s efforts in Vasa’s preservation is admirable, and one can see its majestic stature its exquisite custom wooden carvings and embellished sculptures reveal. Aside from being a deadly machine, it was beautiful art, capturing seventeenth century culture and sophistication. We spent half a day looking at the impressive Vasa this August in Stockholm.

July 31, 2014

S-N curves

In order to set a suitable design criteria, I was looking to compare two classes of S-N curves for a fatigue design, viz., E and F2, and I could not find a handy plot to refer to. The basic S-N curve equation is as follows, which one may know is from Paris-Erdogan law (fracture mechanics):

N = k1 * S^(-m)

The standard does describe it in its logarithmic form, which is as follows:

log(N) = log(k1) - m * log(S)

and then it goes on to furnish its two sets of key components that form parts of the equation — highlighted below.

From ISO 19902:2007

Playing with logarithms is fraught with error, as they are not the same as plain algebra — Leonhard Euler’s gift to the world, which reminds me I should jog my memory from high-school. Anyway, not to waste any time, I pulled Calca, punched in the basic equation, and then, case after case, I provided the variables from the table above. Calca, in turn provided me with an equation ready to be pasted in Grapher for a ready plot. Here are those equations for all available S-N curves.

# Basic S-N curves
#
# Basic representative S-N curve is of the 
# form (where, x is Number of cycles, and
# y is S Stress range):

log(x) = a - m * log(y)

# a = log(k1).

# Seawater with adequate corrosion protection

For TJ curve:

a = 12.18 # for N =< 1.8E6
m = 3     # -- do --
y => -0.33 * log(x) + 4.06

a = 16.13 # for N > 1.8E6
m = 5     # -- do --
y => -0.2 * log(x) + 3.23

For B curve:

a = 14.61 # for N =< 1E5
m = 4     # -- do --
y => -0.25 * log(x) + 3.65

a = 17.01 # for N > 1E5
m = 5     # -- do --
y => -0.2 * log(x) + 3.4

For C curve:

a = 13.23 # for N =< 4.68E5
m = 3.5   # -- do --
y => -0.29 * log(x) + 3.78

a = 16.47 # for N > 4.68E5
m = 5     # -- do --
y => -0.2 * log(x) + 3.29

For D curve:

a = 11.78 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.93

a = 15.63 # for N > 1E6
m = 5     # -- do --
y => -0.2 * log(x) + 3.13

For E curve:

a = 11.62 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.87

a = 15.37 # for N > 1E6
m = 5     # -- do --
y => -0.2 * log(x) + 3.07

For F curve:

a = 11.40 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.8

a = 15.0 # for N > 1E6
m = 5    # -- do --
y => -0.2 * log(x) + 3

For F2 curve:

a = 11.23 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.74

a = 14.71 # for N > 1E6
m = 5     # -- do --
y => -0.2 * log(x) + 2.94

For G curve:

a = 11.00 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.67

a = 14.33 # for N > 1E6
m = 5     # -- do --
y => -0.2 * log(x) + 2.87

For W1 curve:

a = 10.57 # for N =< 1E6
m = 3     # -- do --
y => -0.33 * log(x) + 3.52

a = 13.62 # for N > 1E6
m = 5     # -- do --
y => -0.2 * log(x) + 2.72

And finally, here’s the plot I was looking to generate. (The black lines are TJ, green lines are E, and red lines are F2 curves.) Grapher makes it easy to switch curves on and off — using check marks in the equation side bar.

S-N Curve plot