Jekyll2023-11-27T19:57:04+00:00http://wapisani.github.io/feed.xmlWill PisaniScientist, Engineer, Musician, GamerAnalyzing My Spotify Top Songs 2016 - 2022 Part 12023-07-13T00:00:00+00:002023-07-13T00:00:00+00:00http://wapisani.github.io/Spotify_Top_Songs_2016_2022_Part1<p>In this series of blog posts, I will discuss how my musical tastes have changed over the past six years using the data from my Spotify top songs playlists. One of the things I love about Spotify is their summary playlists of the top 100 songs you listened to during the past year. These playlists are called “Your Top Songs (year)” and are usually created in early December of that year. I’ve been a Spotify premium subscriber since May/June 2014, but I don’t have a record of my top songs from 2014 or 2015. However, I do have a record of my top songs from 2016 to 2022.</p>
<h3 id="my-musical-tastes-prior-to-spotify">My Musical Tastes Prior to Spotify</h3>
<p>Before I met my wife, I pretty much just listened to video game and movie soundtracks and remixes of video game music made by the very talented folks at <a href="https://ocremix.org">OCReMix</a>. I exclusively used the <a href="https://foobar2000.org">foobar2000</a> software with a classic ‘green text on a black background’ theme to listen to my music. I turned my nose up at any kind of pop, hip hop, or country music. I was so into OCReMix that I named my college radio show after it - The OCReMix Show with DJ Willdabeast. Shortly after we met, my wife introduced me to Spotify and to music that didn’t come from a movie or video game. The OCReMix Show then became the OverClocked Fusion Show with DJ Willdabeast and DJ Supernova where video game music was played side-by-side with country, pop, hiphop, and rock/alternative.</p>
<h2 id="spotify-audio-features">Spotify Audio Features</h2>
<p>Every song on Spotify can be characterized by the following metrics: acousticness, danceability, duration, energy, instrumentalness, key, liveness, loudness, mode, speechiness, tempo, time signature, and valence. A description of each audio feature is below for your convenience. I lifted some of the language from Spotify’s official <a href="https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-features">documentation</a>.</p>
<ul>
<li>
<p>Acousticness is the confidence that a track is acoustic (0.0 - not acoustic, 1.0 - acoustic). Acoustic music primarily uses instruments that don’t use electricity to produce sound such as the trumpet, saxophone, clarinet, acoustic guitar, piano, violin, etc.</p>
</li>
<li>
<p>Danceability is the confidence that a track is suitable for dancing (0.0 - least danceable, 1.0 - most danceable). This metric combines several musical elements including tempo, rhythm stability, beat strength, and overall regularity.</p>
</li>
<li>
<p>Duration is the length of the track.</p>
</li>
<li>
<p>Energy describes the intensity and activity of a track (0.0 - very low energy, 1.0 - very high energy). Classical music scores low while metal music scores high. This metric combines several elements including dynamic range, perceived loudness, timbre, onset rate, and general entropy.</p>
</li>
<li>
<p>Instrumentalness is the confidence that a track contains no vocals other than “oohs” or “aahs” (values greater than 0.5 likely contain no vocals, but confidence increases as the value approaches 1.0).</p>
</li>
<li>
<p>Key - the key the track is in. From Spotify’s docs, “Integers map to pitches using standard Pitch Class (https://en.wikipedia.org/wiki/Pitch_class) notation. E.g. 0 = C, 1 = C♯/D♭, 2 = D, and so on. If no key was detected, the value is -1.”</p>
</li>
<li>
<p>Liveness is the confidence that a track was performed live (0.0 - recorded in studio, > 0.8 - likely song was recorded live).</p>
</li>
<li>
<p>Loudness is the loudness of the track. This value is the average loudness of the track and thus allows comparison between tracks.</p>
</li>
<li>
<p>Mode indicates whether a given track is major or minor key (0 - minor, 1 - major).</p>
</li>
<li>
<p>Speechiness is the confidence that a track primarily consists of speech. Values greater than 0.66 are likely all spoken words. Values between 0.33 and 0.66 contain a mix of music and speech. Values below 0.33 contain music with sung vocals.</p>
</li>
<li>
<p>Tempo is the overall tempo of a track in beats per minute (BPM).</p>
</li>
<li>
<p>Time signature indicates how many beats are in each measure. Values range from 3 to 7 which indicate “3/4” to “7/4” time.</p>
</li>
<li>
<p>Valence describes the musical positiveness of a track (0.0 - negative, 1.0 - positive). From Spotify’s docs: “Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric),
while tracks with low valence sound more negative (e.g. sad, depressed, angry).”</p>
</li>
</ul>
<h2 id="python-code">Python Code</h2>
<p>Using the power of Python and the <a href="https://developer.spotify.com/documentation/web-api/">Spotify API</a>, I downloaded my top songs from 2016 to 2022 along with their audio features as CSV files. Once I had my top songs playlists downloaded with the associated audio features, I collected them together using pandas and then used Seaborn to generate box-and-whisker plots of each year’s data side-by-side.</p>
<p>Below is the data extraction script. I used the requests library to interface with the API and the pandas library to convert the list of dicts to a CSV file.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span><span class="s">"""
@author: Will Pisani, PhD
This script will download my top songs from 2016 to 2022 and save them to CSV files.
"""</span>
<span class="kn">import</span> <span class="nn">requests</span><span class="p">,</span> <span class="n">os</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="k">def</span> <span class="nf">GetAllTracksInfo</span><span class="p">(</span><span class="n">playlist_id</span><span class="p">,</span><span class="n">authorization_header</span><span class="p">):</span>
<span class="s">"""
Parameters
----------
playlist_id : String
Spotify playlist ID.
authorization_header : dict
The standard Spotify API authorization header.
Returns
-------
tracks : list
List of dicts with each dict containing information about a song.
"""</span>
<span class="c1"># base URL of all Spotify API endpoints
</span> <span class="n">BASE_URL</span> <span class="o">=</span> <span class="s">'https://api.spotify.com/v1/'</span>
<span class="n">track_json</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">BASE_URL</span> <span class="o">+</span> <span class="s">'playlists/'</span> <span class="o">+</span> <span class="n">playlist_id</span> <span class="o">+</span> <span class="s">'/tracks'</span><span class="p">,</span><span class="n">headers</span><span class="o">=</span><span class="n">authorization_header</span><span class="p">).</span><span class="n">json</span><span class="p">()</span>
<span class="n">tracks</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">track</span> <span class="ow">in</span> <span class="n">track_json</span><span class="p">[</span><span class="s">'items'</span><span class="p">]:</span>
<span class="n">track</span> <span class="o">=</span> <span class="n">track</span><span class="p">[</span><span class="s">'track'</span><span class="p">]</span>
<span class="n">track_info</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">BASE_URL</span> <span class="o">+</span> <span class="s">'audio-features/'</span> <span class="o">+</span> <span class="n">track</span><span class="p">[</span><span class="s">'id'</span><span class="p">],</span><span class="n">headers</span><span class="o">=</span><span class="n">authorization_header</span><span class="p">).</span><span class="n">json</span><span class="p">()</span>
<span class="n">track_info</span><span class="p">.</span><span class="n">update</span><span class="p">({</span>
<span class="s">'track_name'</span><span class="p">:</span> <span class="n">track</span><span class="p">[</span><span class="s">'name'</span><span class="p">],</span>
<span class="s">'release_data'</span><span class="p">:</span> <span class="n">track</span><span class="p">[</span><span class="s">'album'</span><span class="p">][</span><span class="s">'release_date'</span><span class="p">],</span>
<span class="s">'album_name'</span><span class="p">:</span> <span class="n">track</span><span class="p">[</span><span class="s">'album'</span><span class="p">][</span><span class="s">'name'</span><span class="p">],</span>
<span class="s">'popularity'</span><span class="p">:</span> <span class="n">track</span><span class="p">[</span><span class="s">'popularity'</span><span class="p">]})</span>
<span class="n">artists</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># To handle multiple artists
</span> <span class="k">for</span> <span class="n">artist</span> <span class="ow">in</span> <span class="n">track</span><span class="p">[</span><span class="s">'artists'</span><span class="p">]:</span>
<span class="n">artists</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">artist</span><span class="p">[</span><span class="s">'name'</span><span class="p">])</span>
<span class="n">artists_str</span> <span class="o">=</span> <span class="s">', '</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">artists</span><span class="p">)</span>
<span class="n">track_info</span><span class="p">.</span><span class="n">update</span><span class="p">({</span>
<span class="s">'artists'</span><span class="p">:</span> <span class="n">artists_str</span><span class="p">})</span>
<span class="n">tracks</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">track_info</span><span class="p">)</span>
<span class="k">return</span> <span class="n">tracks</span>
<span class="n">auth_url</span> <span class="o">=</span> <span class="s">'https://accounts.spotify.com/api/token'</span>
<span class="n">CLIENT_ID</span> <span class="o">=</span> <span class="s">'your_client_id'</span>
<span class="n">CLIENT_SECRET</span> <span class="o">=</span> <span class="s">'your_client_secret'</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'grant_type'</span><span class="p">:</span> <span class="s">'client_credentials'</span><span class="p">,</span>
<span class="s">'client_id'</span><span class="p">:</span> <span class="n">CLIENT_ID</span><span class="p">,</span>
<span class="s">'client_secret'</span><span class="p">:</span> <span class="n">CLIENT_SECRET</span><span class="p">,</span>
<span class="p">}</span>
<span class="n">auth_response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">auth_url</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
<span class="n">access_token</span> <span class="o">=</span> <span class="n">auth_response</span><span class="p">.</span><span class="n">json</span><span class="p">().</span><span class="n">get</span><span class="p">(</span><span class="s">'access_token'</span><span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'Authorization'</span><span class="p">:</span> <span class="sa">f</span><span class="s">'Bearer </span><span class="si">{</span><span class="n">access_token</span><span class="si">}</span><span class="s">'</span>
<span class="p">}</span>
<span class="c1"># base URL of all Spotify API endpoints
</span><span class="n">BASE_URL</span> <span class="o">=</span> <span class="s">'https://api.spotify.com/v1/'</span>
<span class="c1"># My Top Songs = MTS
</span><span class="n">my_top_songs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2016</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2016_id'</span><span class="p">},</span>
<span class="mi">2017</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2017_id'</span><span class="p">},</span>
<span class="mi">2018</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2018_id'</span><span class="p">},</span>
<span class="mi">2019</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2019_id'</span><span class="p">},</span>
<span class="mi">2020</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2020_id'</span><span class="p">},</span>
<span class="mi">2021</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2021_id'</span><span class="p">},</span>
<span class="mi">2022</span> <span class="p">:</span> <span class="p">{</span><span class="s">'id'</span> <span class="p">:</span> <span class="s">'2022_id'</span><span class="p">}}</span>
<span class="n">os</span><span class="p">.</span><span class="n">chdir</span><span class="p">(</span><span class="sa">r</span><span class="s">'/directory/to/save/playlist/csvs/to'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">year</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2016</span><span class="p">,</span><span class="mi">2022</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="c1"># Add tracks to dictionary for debugging and inspection
</span> <span class="n">my_top_songs</span><span class="p">[</span><span class="n">year</span><span class="p">][</span><span class="s">'tracks'</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetAllTracksInfo</span><span class="p">(</span><span class="n">my_top_songs</span><span class="p">[</span><span class="n">year</span><span class="p">][</span><span class="s">'id'</span><span class="p">],</span><span class="n">headers</span><span class="p">)</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">my_top_songs</span><span class="p">[</span><span class="n">year</span><span class="p">][</span><span class="s">'tracks'</span><span class="p">])</span>
<span class="n">df</span><span class="p">.</span><span class="n">to_csv</span><span class="p">(</span><span class="sa">f</span><span class="s">"MTS</span><span class="si">{</span><span class="n">year</span><span class="si">}</span><span class="s">.csv"</span><span class="p">)</span>
</code></pre></div></div>
<p>Below is the data analysis script.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span><span class="s">"""
@author: Will Pisani, PhD
This script will analyze My Top Songs from 2016 to presently available data.
"""</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="n">directory</span> <span class="o">=</span> <span class="sa">r</span><span class="s">'/directory/to/csv/files'</span>
<span class="n">os</span><span class="p">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
<span class="n">years</span> <span class="o">=</span> <span class="p">[</span><span class="s">'2016'</span><span class="p">,</span><span class="s">'2017'</span><span class="p">,</span><span class="s">'2018'</span><span class="p">,</span><span class="s">'2019'</span><span class="p">,</span><span class="s">'2020'</span><span class="p">,</span><span class="s">'2021'</span><span class="p">,</span><span class="s">'2022'</span><span class="p">]</span>
<span class="c1"># Combine all years into one data frame
</span><span class="n">dataframes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">year</span> <span class="ow">in</span> <span class="n">years</span><span class="p">:</span>
<span class="n">dataframes</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="sa">f</span><span class="s">'MTS</span><span class="si">{</span><span class="n">year</span><span class="si">}</span><span class="s">.csv'</span><span class="p">).</span><span class="n">assign</span><span class="p">(</span><span class="n">Year</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">year</span><span class="p">)))</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">concat</span><span class="p">(</span><span class="n">dataframes</span><span class="p">)</span>
<span class="c1"># Get averages and standard deviations of each characteristic by year
</span><span class="n">mean_df</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">groupby</span><span class="p">([</span><span class="s">'Year'</span><span class="p">]).</span><span class="n">mean</span><span class="p">()</span>
<span class="n">std_df</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">groupby</span><span class="p">([</span><span class="s">'Year'</span><span class="p">]).</span><span class="n">std</span><span class="p">()</span>
<span class="n">cols</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">columns</span>
<span class="c1"># Add duration in minutes to the dataframe
</span><span class="n">df</span><span class="p">[</span><span class="s">'duration_min'</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s">'duration_ms'</span><span class="p">]</span><span class="o">/</span><span class="mi">1000</span><span class="o">/</span><span class="mi">60</span>
<span class="n">features</span> <span class="o">=</span> <span class="p">[</span><span class="s">'acousticness'</span><span class="p">,</span><span class="s">'danceability'</span><span class="p">,</span><span class="s">'duration_min'</span><span class="p">,</span><span class="s">'energy'</span><span class="p">,</span><span class="s">'instrumentalness'</span><span class="p">,</span>
<span class="s">'key'</span><span class="p">,</span><span class="s">'liveness'</span><span class="p">,</span><span class="s">'loudness'</span><span class="p">,</span><span class="s">'mode'</span><span class="p">,</span><span class="s">'speechiness'</span><span class="p">,</span><span class="s">'tempo'</span><span class="p">,</span><span class="s">'time_signature'</span><span class="p">,</span>
<span class="s">'valence'</span><span class="p">]</span>
<span class="c1"># Spotify's official docs on the audio features
# https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-features
</span>
<span class="n">os</span><span class="p">.</span><span class="n">chdir</span><span class="p">(</span><span class="sa">r</span><span class="s">'/directory/where/you/want/to/save/the/plots/to'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">feature</span> <span class="ow">in</span> <span class="n">features</span><span class="p">:</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">()</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">sns</span><span class="p">.</span><span class="n">boxplot</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="s">"Year"</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="n">feature</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">df</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="sa">f</span><span class="s">'My_Top_Songs_Box_Plot_</span><span class="si">{</span><span class="n">feature</span><span class="si">}</span><span class="s">.png'</span><span class="p">,</span><span class="n">dpi</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="my-top-songs-analysis---acousticness">My Top Songs Analysis - Acousticness</h2>
<p>Now let’s talk about the first audio feature - acousticness!</p>
<figure>
<img src="../images/Spotify/My_Top_Songs_Box_Plot_acousticness.png" alt="My Top Songs 2016-2022 Acousticness" />
<figcaption>Figure 1. Acousticness of Will Pisani's top songs as a function of time. The confidence that a song is acoustic increases as the value increases.</figcaption>
</figure>
<p>As you can see, the acousticness of my top songs has steadily decreased over the years with a large decrease in Q3 from 2019 to 2020. It’s clear I listened to significantly more music with electronic elements than orchestral elements. The more I listened to music on Spotify and discovered more music, the less I listened to orchestral/acoustic music.
<br /><br /></p>
<p>My top songs spanned nearly the entire acousticness range from 2016 to 2019, but the range decreased significantly from 2020 onwards. There are four outliers in 2021 that are close to 1.0 acousticness, but most songs are nowhere near 1.0. So what happened with 2020? Well, the COVID-19 pandemic happened. 2020 was a dark time for me and I started listening to a lot more pop, rock, pop-rock, and pop-punk (enough that I made a pop-rock/pop-punk playlist in Sept 2020). Acoustically, 2021 and 2022 were a continuation of the downward trend, with 2022 exhibiting a significant decrease relative to 2021. I’ve really leaned into the pop, pop-rock, and country-pop over the last three years. I listen to more pop now than video game music (Golly, I don’t think Will from 2014 would have ever thought that was possible!).</p>
<h2 id="conclusion">Conclusion</h2>
<p>I hope you enjoyed this post and found the Python code to be helpful. Stay tuned for the next part in the series!</p>In this series of blog posts, I will discuss how my musical tastes have changed over the past six years using the data from my Spotify top songs playlists. One of the things I love about Spotify is their summary playlists of the top 100 songs you listened to during the past year. These playlists are called “Your Top Songs (year)” and are usually created in early December of that year. I’ve been a Spotify premium subscriber since May/June 2014, but I don’t have a record of my top songs from 2014 or 2015. However, I do have a record of my top songs from 2016 to 2022.2020 New Years Resolutions2019-12-31T00:00:00+00:002019-12-31T00:00:00+00:00http://wapisani.github.io/2020-New-Years-Resolutions<p>In my 2019 resolutions post, I wrote that I wasn’t sure what my 2018 resolutions were. Thanks to this blog I know exactly what my 2019 resolutions were (see below).</p>
<h2 id="my-2019-resolutions-were">My 2019 resolutions were:</h2>
<ul>
<li>Finish my Ph.D.!</li>
<li>Release five singles of video game music</li>
<li>Release <a href="../The-Golden-Sun-Set/">“The Golden Sun Set” album</a></li>
<li>Read seven books</li>
</ul>
<p>My biggest 2019 resolution was to finish my Ph.D in mechanical engineering - engineering mechanics at Michigan Tech. I can proudly say that I was successful! I am now the third Dr. Pisani.</p>
<p><img src="https://pisanifamily.info/will/Pictures/Will_Pisani_PhD.png" class="w3-round" alt="Dr. Will Pisani" /></p>
<p>I only released one VGM single: “Secret of the Forest” from <em>Chrono Trigger</em>. It’s available on all of the major music distribution platforms under the name Will Pisani. Here are a few links: <a href="https://open.spotify.com/album/0bH15SPk9Tb3G635lHKU1x">Spotify</a>, <a href="https://itunes.apple.com/us/album/secret-of-the-forest-from-chrono-trigger-single/1449309810?ign-mpt=uo%3D4">iTunes</a>, <a href="https://www.amazon.com/dp/B07MCMTFVP">Amazon</a>, <a href="https://play.google.com/store/music/album/Will_Pisani_Secret_of_the_Forest_From_Chrono_Trigg?id=Bg5ubanzwil5jfbgocbksu6mefi">Google Play</a>, <a href="https://music.youtube.com/watch?v=aZlAx71Sa9c&list=RDAMVMaZlAx71Sa9c">Youtube Music</a>, <a href="https://www.deezer.com/us/album/84145192?utm_source=deezer&utm_content=album-84145192&utm_term=0_1547263200&utm_medium=web">Deezer</a>. I do have several singles ready to go, enough for an EP, actually. They are <a href="https://soundcloud.com/willpisani/mass-effect-main-theme-v11">“Main Theme” from <em>Mass Effect</em></a>, <a href="https://soundcloud.com/willpisani/kirby-air-ride-city-trial-v10">“City Trial” from <em>Kirby Air Ride</em></a>, <a href="https://soundcloud.com/willpisani/radiant-historia-from-radiant-historia-perfect-chronology-v1">“Title Theme” from <em>Radiant Historia: Perfect Chronology</em></a>, <a href="https://soundcloud.com/willpisani/metroid-prime-3-corruption-1">“Title Theme” from <em>Metroid Prime 3: Corruption</em></a>, and <a href="https://soundcloud.com/willpisani/title-theme-jet-force-gemini-v1">“Title Theme” from <em>Jet Force Gemini</em></a>.</p>
<p>I didn’t release <a href="../The-Golden-Sun-Set/">“The Golden Sun Set” album</a>, but I made good progress. This album probably won’t be released any time soon because I had to cancel my Composer Cloud subscription. The cost was doubling to $20/month which is too much to justify at this time (this is a hobby for me). Since the <em>Golden Sun</em> games have a great Oriental influence on the music, I would need to re-subscribe to get access to the Oriental sound libraries. I’ll finish it someday.</p>
<p>My book reading goal for 2019 was seven books….and I read seven books. They were “Wishful Drinking” by Carrie Fisher, “Miss Peregrine’s Home for Peculiar Children” by Ransom Riggs, “Harry Potter and the Sorcerer’s Stone” by J.K. Rowling (a re-read), “Moonbound: Apollo 11 and the Dream of Spaceflight” by Jonathan Fetter-Vorm, “Queer Eye: Love Yourself. Love Your Life” by The Fab 5, “Running with the Demon” by Terry Brooks (another re-read), and, my favorite of the year, “Dark Matter” by Blake Crouch.</p>
<h2 id="my-2020-resolutions">My 2020 Resolutions</h2>
<ul>
<li>Read 10 books</li>
<li>Cook more often</li>
<li>Work on music more often, at least one hour per month</li>
</ul>
<p>Since I read seven books this past year, I’m shooting for 10 books this year. I also want to work on my music more often, at least one hour per month.</p>
<p>In our household, Leila is usually the chef. I help out with most meals, but I rarely cook meals for the two of us on my own. My main 2020 resolution is to cook more often. I’ve made some good bread in our bread machine in the past, but I’d like to do more of that (and make Nisu bread, a local favorite in Houghton, MI).</p>
<p>I want to get into meal prepping my lunches for work (ORISE postdoc at a US Army Corps of Engineers laboratory). Thankfully there are many, many resources for this (Pinterest, Reddit, New York Times, the Internet in general). I also want to cut back on my carbon footprint by eating largely vegetarian lunches. The New York Times <a href="https://www.nytimes.com/interactive/2019/04/30/dining/climate-change-food-eating-habits.html">published a piece</a> on how the meat and dairy industries contribute to climate change (“14.5 percent of the world’s greenhouse gas emissions — as much each year as from all cars, trucks, airplanes and ships combined” - yikes!!). They also have a good guide on <a href="https://www.nytimes.com/2019/12/31/dining/flexitarian-eating-less-meat.html?action=click&module=Editors%20Picks&pgtype=Homepage">how to cut down on your meat and dairy consumption</a> without cutting it out entirely. A good way to go vegetarian from what I’ve read is by including a lot of beans. <a href="https://cooking.nytimes.com/guides/21-how-to-cook-beans">The New York Times has a good guide on cooking beans</a> that I plan on trying at least once. I’ve never cooked dried beans before so this will be interesting. I love eating Chinese cuisine so a lot of my lunches will probably be Chinese in nature. I was introduced to delicious Indian cuisine by my awesome friends at Michigan Tech during my Ph.D. Whether homemade by friends or eaten at restaurants with friends on our research trips, I loved it all. Butter chicken, chicken biryani, egg curry, and mango lassi are just a few of the dishes and drinks I plan on making for myself and Leila.</p>
<p>These goals are definitely more doable than last year’s, but the biggest challenge will be adapting to my first post-university job and to life in Mississippi. 2020 will be the first year in about 18 years that I won’t be living somewhere in the great state of Michigan. Leila and I both really loved the movie <em>Frozen 2</em> (probably more than <em>Star Wars: The Rise of Skywalker</em>), especially the song “Into the Unknown” sung by Idina Menzel and Aurora. I think the reason <em>Frozen 2</em> and “Into the Unknown” resonated with us so much is that we, like Elsa, are heading into the unknown. Nearly 1000 miles from both sides of the family, this is the furthest we’ve ever lived from our immediate families. From the cold, extremely snowy, but intimately familiar Keweenaw Peninsula to the hot, rainy, and unknown of Mississippi. 2020 will be the year of new beginnings and new adventures!</p>In my 2019 resolutions post, I wrote that I wasn’t sure what my 2018 resolutions were. Thanks to this blog I know exactly what my 2019 resolutions were (see below).Visualizing Windows/Unix Directory Trees with Gource2019-06-07T00:00:00+00:002019-06-07T00:00:00+00:00http://wapisani.github.io/Gource-Unix<p>I use Git and Github to keep all of my Ph.D. research in version control. This allows me to keep track of every change to the files and even pull out specific file versions from years ago (perhaps a presentation given at a certain conference). It also functions as a cloud backup in case something happens to your workstation or laptop. If you’re at the beginning of your Ph.D., I strongly, <em>strongly</em> recommend using a version control system. If you don’t want to pay for a private repository out of pocket, talk with your IT department, perhaps they already pay for Github hosting and can set you up with a private repo (thanks, G!).</p>
<p>Let’s say you’ve been using Git for quite a while now (for me it’s been about four years now) and you want to visualize your progress. Well, you’re in luck because someone developed the exact software for you! It’s called <a href="https://gource.io/">Gource</a> (<a href="https://github.com/acaudwell/Gource">Github link</a>). Gource works out of the box for Git, Mercurial, Bazaar, and SVN. Visualizing Git repos is a snap with Gource. But what if you don’t use a version control software?</p>
<p>One of my friends saw one of my recent visualizations (<a href="https://pisanifamily.info/will/videos/My_Blog_History.mp4">blog</a>, <a href="https://pisanifamily.info/will/videos/Pisani_Research_US-COMP_Work.mp4">US-COMP research</a>, my work in <a href="https://pisanifamily.info/will/videos/UN5390_Scientific_Computing_I.mp4">UN5390</a>/<a href="https://pisanifamily.info/will/videos/UN5395_Scientific_Computing_II.mp4">UN5395</a> Scientific Computing I and II) and was interested in generating a Gource visualization for their work. However, they don’t use version control software for their research. Gource has the option of visualizing a custom log that you point it to. It just needs to be formatted a certain way.</p>
<p>Version control software keeps track of nearly everything that you do with your files, but the main things you’re interested in for a Gource visualization are the time the file was created/modified, the path to the file, and the filename. If you’re on Windows, you can access the time that the file was created, but you’re out of luck if you run Unix. Modification time is universal across OSes, though only the last time the file was modified will be the modification time.</p>
<p>It was relatively straightforward to write a Python script which traverses a given directory tree, finds the modification time and path/filename, and writes the custom log format in the correct order. Here’s a <a href="https://pisanifamily.info/will/code/Gource_Custom_Log_Creator.py">link to the script</a>. This script was written for Python 2.7, but will run on Python 2.6.6 (the version on SUPERIOR) just fine.</p>
<p>I initially ran it on my Github directory tree, but the resulting output didn’t match the normal Gource visualization due to the way that Windows writes paths. I guess Git (or Gource) must use the Unix convention of using ‘/’ characters instead of Windows’ ‘\’ characters. I accounted for that in the code and now it works great! This code should work in whatever Windows or Unix directory you point it at. If you don’t have an unlimited data plan and you’re using data to view this blog post, you will not want to watch the following videos now. They’re fairly large. Here is a visualization of the <a href="https://pisanifamily.info/will/videos/Documents_Folder_on_F_Drive.mp4">Documents folder on my F: drive</a>. Here is a visualization of my <a href="https://pisanifamily.info/will/videos/Michigan_Tech_Folder_on_F_Drive.mp4">Michigan Tech coursework</a>. Another of my <a href="https://pisanifamily.info/will/videos/Music_Folder_F_Drive.mp4">music folder</a>.</p>
<p>Thankfully, it worked perfectly on the first try at the root directory of my high-performance computing (HPC) storage on SUPERIOR, Michigan Tech’s HPC cluster. This is the usecase for which this code was really meant for. For reference, here is a <a href="https://pisanifamily.info/will/videos/SUPERIOR_Will_Pisani_Timeline.mp4">link to what my SUPERIOR timeline looks like</a>. For my friends/colleagues who may be reading this, <strong>you should start a qlogin session before you run the code.</strong> I don’t think it is computationally intense, but it’s better to be cautious all the same. You don’t want to be the person who crashes the login node. (NOTE: the qlogin command logs you in to an available compute node.) To start a qlogin session, simply type “qlogin” without quotes and hit enter. The prompt should turn green, indicating that it is now safe to run things.</p>
<p>Place the Gource_Custom_Log_Creator.py file at the root of your research directory on SUPERIOR (or other HPC cluster). Next, you will need to change a couple lines in the code to match your information. First, you will need to change the root_dir string to match the path of your research directory. Second, you will need to change the username string to match your username. Lastly, save the file and run it using “python Gource_Custom_Log_Creator.py” without quotes. You should see a flurry of text fly past your screen. The code is printing each file it finds and its corresponding modification time. At the very end, if all went well, you should see “your_custom_log.log has been written to (your root directory here)”. Go ahead and view it using less, vi/vim, or your favorite text editor. You should see lines with a large number at the beginning followed by your username followed by an M followed by the path and filename. Now you can point Gource to this log file.</p>
<p>Download Gource onto your machine and unzip it somewhere. Download your newly created log file and save it somewhere close to where you put Gource. Then, in a terminal or command prompt window, run “Gource ../pathtologfile/your_custom_log.log” (Unix) or “Gource ..\pathtologfile\your_custom_log.log” (Windows). There are more options that you can add, but that will tell you if it worked. You should see a window pop up with the visualization. If you see a little figure zipping around and zapping clusters of dots into existence, congratulations! It worked!</p>I use Git and Github to keep all of my Ph.D. research in version control. This allows me to keep track of every change to the files and even pull out specific file versions from years ago (perhaps a presentation given at a certain conference). It also functions as a cloud backup in case something happens to your workstation or laptop. If you’re at the beginning of your Ph.D., I strongly, strongly recommend using a version control system. If you don’t want to pay for a private repository out of pocket, talk with your IT department, perhaps they already pay for Github hosting and can set you up with a private repo (thanks, G!).2019 New Years Resolutions2018-12-31T00:00:00+00:002018-12-31T00:00:00+00:00http://wapisani.github.io/2019-New-Years-Resolutions<p>I’m not sure what my 2018 resolutions were, but I surpassed my reading goal of five books by one. The books I read were: “The Arctic Incident” (Artemis Fowl #2) by Eoin Colfer, “Endurance: A Year in Space, A lifetime of Discovery” by Scott Kelly (U.S. astronaut), “Eragon” by Christopher Paolini, “American Gods” by Neil Gaiman, “Grunt: The Curious Science of Humans at War” by Mary Roach, and, my favorite of 2018, “The Oracle Year” by Charles Soule.</p>
<p>My 2019 resolutions are:</p>
<ul>
<li>Finish my Ph.D.!</li>
<li>Release five singles of video game music</li>
<li>Release <a href="../The-Golden-Sun-Set/">“The Golden Sun Set” album</a></li>
<li>Read seven books</li>
</ul>
<p>It’s looking like I’ll be defending my dissertation in August 2019!! So my biggest resolution of 2019 is to finish my Ph.D. by September and move on to the next chapter of my career.</p>
<p>I’d like to release five singles of video game music, each one from a different franchise. My first release will likely be a Chrono Trigger song titled “Secret of the Forest”; all I need is some album art. The other four will probably be a Metroid song, a Jet Force Gemini song, a Pokemon song, and a Mass Effect/Castlevania/Radiant Historia song.</p>
<p>In addition to the singles, my plan is to release “The Golden Sun Set” with as many songs as I can manage. The current tracklist consists of 41 Golden Sun and Golden Sun: The Lost Age and five Dark Dawn songs. It will probably be pared down to 15-20 songs, but we’ll see.</p>
<p>Since I read six books this past year, I should be able to read seven books amongst all the journal articles. I’ve been reading the second Eragon book, “Eldest”, and Leila gave me an awesome book by Neil deGrasse Tyson and Avis Lang titled <a href="https://www.amazon.com/Accessory-War-Unspoken-Alliance-Astrophysics/dp/0393064441">“Accessory to War: The Unspoken Alliance Between Astrophysics and the Military”</a> that I’ll be starting soon.</p>
<p>This seems like a lot, but I was told recently that I shouldn’t limit my goals.</p>I’m not sure what my 2018 resolutions were, but I surpassed my reading goal of five books by one. The books I read were: “The Arctic Incident” (Artemis Fowl #2) by Eoin Colfer, “Endurance: A Year in Space, A lifetime of Discovery” by Scott Kelly (U.S. astronaut), “Eragon” by Christopher Paolini, “American Gods” by Neil Gaiman, “Grunt: The Curious Science of Humans at War” by Mary Roach, and, my favorite of 2018, “The Oracle Year” by Charles Soule.The Golden Sun Set - Arriving Dec 25, 20192018-11-26T00:00:00+00:002018-11-26T00:00:00+00:00http://wapisani.github.io/The-Golden-Sun-Set<p>Over the next year, I will be working on a reorchestrated album of Golden Sun and Golden Sun: The Lost Age music called “The Golden Sun Set”. I’m hoping to release the album on December 25, 2019 on all of the major music platforms.</p>
<p>Update May 21, 2019:
Eleven (11) in-progress tracks so far. The target date for finishing the album is Thanksgiving 2019. I don’t think the original tracklist will be the final list since there are 35 more tracks left to go and six months left. Plus research to conduct, a dissertation to write and defend, moving, starting a new job, etc. There are probably not going to be more than 20 tracks, if that. Perhaps there will be a volume 2 in the future.</p>
<p>The final tracklist will probably be more like the list below.</p>
<ol>
<li>The First Book</li>
<li>On That Night 3 Years Ago - <a href="https://soundcloud.com/willpisani/on-that-night-3-years-ago-golden-sun-v-01">WiP Mar 8, 2019</a></li>
<li>Sol Sanctum - <a href="https://soundcloud.com/willpisani/sol-sanctum-golden-sun-v01">WiP May 21, 2019</a></li>
<li>The Elemental Stars</li>
<li>Battle! Isaac</li>
<li>Mercury Lighthouse</li>
<li>Oriental - <a href="https://soundcloud.com/willpisani/oriental-golden-sun-v01">WiP Mar 8, 2019</a></li>
<li>Set Sail! Through the Karagol Sea - <a href="https://soundcloud.com/willpisani/set-sail-through-the-karagol-sea-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Ready for a Challenge</li>
<li>Venus Lighthouse - <a href="https://soundcloud.com/willpisani/venus-lighthouse-golden-sun-v01">WiP May 21, 2019</a></li>
<li>Battle! [Fusion Dragon]</li>
<li>The Second Book</li>
<li>Battle! Jenna - <a href="https://soundcloud.com/willpisani/battle-jenna-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Battle! Felix</li>
<li>A Full Moon in Garoh - <a href="https://soundcloud.com/willpisani/a-full-moon-in-garoh-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Aqua Rock - <a href="https://soundcloud.com/willpisani/aqua-rock-v05-golden-sun">WiP Nov 26, 2018</a></li>
<li>Jupiter Lighthouse - <a href="https://soundcloud.com/willpisani/jupiter-lighthouse-golden-sunv01">WiP Aug 31, 2019</a></li>
<li>Walking Forward with Determination - <a href="https://soundcloud.com/willpisani/walking-forward-with-determination-golden-sun-v01">WiP Mar 8, 2019</a></li>
<li>Mars Lighthouse</li>
<li>Battle! Doom Dragon - <a href="https://soundcloud.com/willpisani/battle-doom-dragon-golden-sun-v01">WiP May 14, 2019</a></li>
<li>The Golden Sun Rises - <a href="https://soundcloud.com/willpisani/the-golden-sun-rises-golden-sun-v08">WiP May 14, 2019</a></li>
</ol>
<p>The album art is below. The album art base image was found at the URL: <a href="https://www.pexels.com/photo/flight-landscape-nature-sky-36717/">https://www.pexels.com/photo/flight-landscape-nature-sky-36717/</a>. It is a royalty-free image that can be used for any legal purpose and can be modified. The font I used for the text in the album art is called “Elementary Gothic Bookhand” and can be used for free for commercial and non-commercial use. It can be found at the URL: <a href="https://www.dafont.com/elementary-gothic-bookhand.font">https://www.dafont.com/elementary-gothic-bookhand.font</a>.
<img src="/images/TheGoldenSunSet_Album_Art.jpg" /></p>
<p>So far, it’s looking like the album will be about 41 GS/TLA songs and 5 Golden Sun: Dark Dawn songs, but the final count may change closer to release. The tentative tracklist is below. I’m planning on adding links to work-in-progress tracks on my SoundCloud as I work on the album.</p>
<ol>
<li>The Golden Sun Sets - ~12 seconds</li>
<li>The Golden Sun Rises - <a href="https://soundcloud.com/willpisani/the-golden-sun-rises-golden-sun-v08">WiP May 14, 2019</a></li>
<li>Walking Forward with Determination - <a href="https://soundcloud.com/willpisani/walking-forward-with-determination-golden-sun-v01">WiP Mar 8, 2019</a></li>
<li>Venus Lighthouse</li>
<li>Set Sail! Through the Karagol Sea - <a href="https://soundcloud.com/willpisani/set-sail-through-the-karagol-sea-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Mars Lighthouse</li>
<li>The First Book</li>
<li>The Second Book</li>
<li>Battle! [Isaac]</li>
<li>Battle! [Felix]</li>
<li>Jupiter Lighthouse</li>
<li>Mercury Lighthouse</li>
<li>Battle! [Fusion Dragon]</li>
<li>Battle! [Saturos and Menardi]</li>
<li>Battle! [Doom Dragon] - <a href="https://soundcloud.com/willpisani/battle-doom-dragon-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Battle! [Agatio and Karst]</li>
<li>Desert Heat</li>
<li>On That Night, 3 Years Ago - <a href="https://soundcloud.com/willpisani/on-that-night-3-years-ago-golden-sun-v-01">WiP Mar 8, 2019</a></li>
<li>Sol Sanctum</li>
<li>Ruins of Lemuria</li>
<li>The Elemental Stars</li>
<li>The Final Beacon</li>
<li>Traversing Weyard</li>
<li>The Angarian Journey</li>
<li>Oriental - <a href="https://soundcloud.com/willpisani/oriental-golden-sun-v01">WiP Mar 8, 2019</a></li>
<li>Forest’s Requiem</li>
<li>Inside the Great Gabomba</li>
<li>Sorrow and Regret</li>
<li>Air’s Rock</li>
<li>Aqua Rock - <a href="https://soundcloud.com/willpisani/aqua-rock-v05-golden-sun">WiP Nov 26, 2018</a></li>
<li>Gaia Rock</li>
<li>Magma Rock</li>
<li>An Adept’s Home</li>
<li>Battle! [Jenna] - <a href="https://soundcloud.com/willpisani/battle-jenna-golden-sun-v01">WiP May 14, 2019</a></li>
<li>A Full Moon in Garoh - <a href="https://soundcloud.com/willpisani/a-full-moon-in-garoh-golden-sun-v01">WiP May 14, 2019</a></li>
<li>Battle! [Saturos]</li>
<li>Battle! [Non-Adept]</li>
<li>Island Medley</li>
<li>Colosso Medley</li>
<li>Alhafra/There Goes Briggs!</li>
<li>Page One</li>
</ol>
<p>Dark Dawn Songs</p>
<ol>
<li>Battle! [Matthew]</li>
<li>Battle! [Chaos Chimera]</li>
<li>Battle! [Blados and Chalis]</li>
<li>Battle! [Formidable Enemy]</li>
<li>Arangoa Prelude</li>
</ol>Over the next year, I will be working on a reorchestrated album of Golden Sun and Golden Sun: The Lost Age music called “The Golden Sun Set”. I’m hoping to release the album on December 25, 2019 on all of the major music platforms.October is Castlevania Month!2018-10-05T00:00:00+00:002018-10-05T00:00:00+00:00http://wapisani.github.io/Castlevania-Month<p>October is Halloween month, with everything that that entails: searching for or making the perfect costume, enjoying scary TV shows and movies, eating candy and Halloween-inspired dishes, and, of course, playing Halloween-y video games like Resident Evil, Dark Souls, or <a href="https://www.wikiwand.com/en/Castlevania">Castlevania</a>.</p>
<p>This month I am going to attempt a marathon of the <a href="https://www.wikiwand.com/en/Metroidvania">Metroidvania-style</a> <a href="https://www.konami.com/games/castlevania/eu/en/history">Castlevania games</a>: Symphony of the Night (SotN), Harmony of Dissonance (HoD), Circle of the Moon (CotM), Aria of Sorrow (AoS), Dawn of Sorrow (DoS), Portrait of Ruin (PoR), and Order of Ecclesia (OoE). Prior to this October, I had only beaten DoS, PoR, CotM, and OoE. I have played the others, but haven’t beaten them. As I beat them, I’ll update this post with my thoughts. All of these games are at least nine years old so I won’t be avoiding spoilers.</p>
<p>The ranking so far:</p>
<ol>
<li>Castlevania: Dawn of Sorrow</li>
<li>Castlevania: Aria of Sorrow</li>
</ol>
<h3 id="castlevania-dawn-of-sorrow-beaten-november-2-2018">Castlevania: Dawn of Sorrow (Beaten November 2, 2018)</h3>
<p>Technically Castlevania month is over, but the marathon will continue!</p>
<p>I played DoS on my 3DS XL over several weeks. I did use some cheat codes for this playthrough; I used an all armor cheat to get all of the armors so I didn’t have to worry as much about dodging. Though by the end of the game I did have to worry a lot about dodging.</p>
<p>I enjoyed the graphics of DoS a TON more than AoS. I also really like the music of DoS; I <a href="https://open.spotify.com/track/20plhfU8r1i1aNlg5jbP5y?si=oa-N2_0OQyGkLQ-pqFhuhg">wrote an arrangement of Condemned Tower</a> for my first video game music album. The gameplay of DoS is much better than AoS because the souls system has been refined. For instance, multiple souls of the same soul can stack for more power or better effects. Souls are also used to create better weapons. This can be quite annoying when you need a soul from a monster that has a very low drop rate, but overall I like it better than just finding them in the world like AoS. For the games that don’t feature whips, I typically prefer the broadsword-type weapons (the ones that sweep above your head and to the side) and this playthrough was no exception. I started with a claymore and ended up with the Claimh Solais. Souls I used a lot in this playthrough were Flame Demon (of course), Great Axe Armor, Erinys, Bat Company, Ghost Dancer, and The Creature.</p>
<p>Here are a couple gifs showing the Claimh Solais sword in AoS (left) and DoS (right). I like the DoS animation better, but I like the sword better in AoS.</p>
<p><img src="https://vignette.wikia.nocookie.net/castlevania/images/4/4d/AoS_Claimh_Solais.gif/revision/latest?cb=20180510161304" /> <img src="https://vignette.wikia.nocookie.net/castlevania/images/3/38/DOS_Claimh_Solais.gif/revision/latest?cb=20170911192558" /></p>
<p>Overall, a great game!</p>
<h3 id="castlevania-aria-of-sorrow-beaten-october-5-2018">Castlevania: Aria of Sorrow (Beaten October 5, 2018)</h3>
<p>I started with AoS using a Game Boy Advance emulator called Visual Boy Advance with an Xbox 360 controller. I’ve played its sequel, DoS, on the Nintendo DS many times, but I never owned an AoS GBA cartridge so I haven’t beaten it even once. I beat it today (2018/10/5) with the <a href="https://www.neoseeker.com/castlevania-aria/gameshark/gba/">help of Gameshark codes</a> to speed things up. The codes I used were “max gold” and “all items” to purchase a ring to double the rate of soul drops and acquire 99 of each restorable so I didn’t have to be too careful in avoiding enemy attacks. I also used the “all accessories” code near the end to get the Chaos Ring (which gives you infinite magic points).</p>
<p>I’m very familiar with AoS’s sequel and I prefer the sequel’s gameplay much more; it’s definitely more refined the second time around. Still, it was very fun to play. Having played DoS I knew the gist of AoS’s story, but it’s better to actually experience it. The music and graphics are decent considering it’s a GBA game. I wasn’t terribly impressed with the variety of weapons; I used the Whip Sword for most of the beginning, then the Ascalon until I found the Claimh Solais. Later games definitely improve on the weapons.</p>
<p>But the point of AoS isn’t the weapons, it’s the souls. Soma Cruz, the protagonist, has the ability to absorb the souls of monsters and use their powers. My favorite souls to use were Flame Demon, Giant Bat, and Succubus because I felt like Dracula. I could turn into a bat and fly around while shooting fireballs! Now that’s something you can’t do in the sequel (EDIT 11/2/2018: You can do this in the sequel, too.). And with the Chaos Ring equipped, I could stay in bat form and shoot fireballs for as long as I wanted.</p>
<p>Overall, a great game, but not my favorite. Though, who knows which Castlevania game will be my favorite in 2018? I’ll have to play them all to find out!</p>October is Halloween month, with everything that that entails: searching for or making the perfect costume, enjoying scary TV shows and movies, eating candy and Halloween-inspired dishes, and, of course, playing Halloween-y video games like Resident Evil, Dark Souls, or Castlevania.Comparing Julia, C++, Fortran, and Python Run Times with Coin Flip Code2018-07-07T00:00:00+00:002018-07-07T00:00:00+00:00http://wapisani.github.io/Coin-Flip-Comparison<p>I’m a computational materials scientist, and naturally, I enjoy programming. Recently, I’ve been thinking about picking up a programming language other than Python to help prepare me for a post-doctoral position at a national lab. I was having a hard time choosing between C++ and Fortran. On the one hand C++ would be pretty useful because it’s the language that LAMMPS is written in and so I could extend LAMMPS to fit my needs. On the other hand, Fortran is used in NASA Glenn’s MAC/GMC code (along with tons of other legacy code) and I would love to work with the micromechanics group at NASA Glenn someday. And then I found Julia which is a programming language designed for parallelism and cloud computing and combines the ease of Python with the speed of C++/Fortran, but it is still in beta (v0.6.3 is the current version). All three would be very useful to have at my disposal. Since I have a lot of time on my hands right now, I’m going to try to learn all three.</p>
<p>The best way to learn a new programming language is not through a course or a book, but by trying to do something with that language. I set out to create simple coin flipping scripts in Julia, C++, Fortran, and Python (for comparison) and then time them all. I also created parallel versions for each language. In this blog post, I will go through each language’s code and then report on the timing of each script.</p>
<p>This is a pretty long post so I’ve provided a few links to jump to the Fortran, C++, Julia, and coding resources sections below.
<a href="#fortran">Fortran</a>, <a href="#cpp">C++</a>, <a href="#julia">Julia</a>, and <a href="#coding">coding resources</a></p>
<p>Below is the Python code.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span><span class="s">"""
Created on Mon Jul 02 00:16:48 2018
@author: wapisani
A simple coin flip function.
"""</span>
<span class="c1"># Define coin flip function
</span><span class="k">def</span> <span class="nf">coin_flip</span><span class="p">(</span><span class="n">times</span><span class="p">):</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">times</span><span class="p">:</span>
<span class="n">count</span> <span class="o">+=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">bool</span><span class="p">(</span><span class="n">random</span><span class="p">.</span><span class="n">getrandbits</span><span class="p">(</span><span class="mi">1</span><span class="p">)))</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">count</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="c1">#The above check ensures that I can import the above functions from a different script.
</span> <span class="c1">#Essentially kind of a future proofing technique.
</span> <span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">multiprocessing</span> <span class="k">as</span> <span class="n">multi</span>
<span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="kn">import</span> <span class="n">Pool</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="c1">#Start timer
</span> <span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">clock</span><span class="p">()</span>
<span class="c1"># Define variable that determines if this script runs in parallel or not
</span> <span class="c1"># 0 is no, 1 is yes
</span> <span class="n">parallel_flag</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># Initialize number of flips
</span> <span class="n">num_of_flips</span> <span class="o">=</span> <span class="mf">10E8</span>
<span class="c1"># Print program statement
</span> <span class="k">print</span><span class="p">(</span><span class="s">"This script will flip a coin {:2.0E} times and report the number of heads</span><span class="se">\n</span><span class="s">."</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">num_of_flips</span><span class="p">))</span>
<span class="c1"># Branch
</span> <span class="k">if</span> <span class="n">parallel_flag</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># The typical desktop i7 has four cores with hyperthreading
</span> <span class="c1"># enabled for a total of 8 cores. multi.cpu_count() will tell you how
</span> <span class="c1"># many total cores are in your computer.
</span>
<span class="c1">#Parallel processing code
</span> <span class="c1"># Define number of cores to run with
</span> <span class="n">num_of_cores</span> <span class="o">=</span> <span class="mi">4</span>
<span class="c1"># Print the number of cores running
</span> <span class="k">print</span><span class="p">(</span><span class="s">"Running coin flip script with {} cores in parallel"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">num_of_cores</span><span class="p">))</span>
<span class="c1">#Create process pool with specified number of processes
</span> <span class="n">pool</span> <span class="o">=</span> <span class="n">Pool</span><span class="p">(</span><span class="n">processes</span><span class="o">=</span><span class="n">num_of_cores</span><span class="p">)</span>
<span class="c1"># Create a work array that even divides up the work between
</span> <span class="c1"># the number of cores
</span> <span class="n">work_array</span> <span class="o">=</span> <span class="p">[</span><span class="n">num_of_flips</span><span class="o">/</span><span class="n">num_of_cores</span> <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_of_cores</span><span class="p">)]</span>
<span class="c1">#Have each process take a quarter of the work
</span> <span class="n">results</span> <span class="o">=</span> <span class="n">pool</span><span class="p">.</span><span class="nb">map</span><span class="p">(</span><span class="n">coin_flip</span><span class="p">,</span><span class="n">work_array</span><span class="p">)</span>
<span class="c1">#Each process returns a quarter of the total number of flips
</span> <span class="c1">#so sum them together
</span> <span class="n">count</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
<span class="c1">#Terminate processes
</span> <span class="n">pool</span><span class="p">.</span><span class="n">terminate</span><span class="p">()</span>
<span class="c1">#Wait for processes to exit
</span> <span class="n">pool</span><span class="p">.</span><span class="n">join</span><span class="p">()</span>
<span class="c1">#Note: Processes are still present in RAM. Need to figure
</span> <span class="c1">#out how to remove them from RAM.
</span>
<span class="k">print</span><span class="p">(</span><span class="s">"The number of heads is {}."</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">count</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"The percentage of heads is {:.5%}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">count</span><span class="o">/</span><span class="n">num_of_flips</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Time taken: {} seconds"</span><span class="p">.</span><span class="nb">format</span><span class="p">((</span><span class="n">time</span><span class="p">.</span><span class="n">clock</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span><span class="p">)))</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Running coin flip script with one core"</span><span class="p">)</span>
<span class="c1"># Run coin flip function 10^8 flips
</span> <span class="n">count</span> <span class="o">=</span> <span class="n">coin_flip</span><span class="p">(</span><span class="n">num_of_flips</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"The number of heads is {}."</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">count</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"The percentage of heads is {:.5%}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">count</span><span class="o">/</span><span class="n">num_of_flips</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Time taken: {} seconds"</span><span class="p">.</span><span class="nb">format</span><span class="p">((</span><span class="n">time</span><span class="p">.</span><span class="n">clock</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span><span class="p">)))</span>
</code></pre></div></div>
<p>All code was run on an <a href="https://ark.intel.com/products/97128/Intel-Core-i7-7700-Processor-8M-Cache-up-to-4_20-GHz">Intel Core i7-7700</a> clocked at 3.60 GHz (turbo boost up to 4.20 GHz) with 4 cores and 8 logical cores.</p>
<p>The random library in Python seems much more developed than the equivalent options in C++ and Fortran, though that could just be speaking to my inexperience with C++ and Fortran. random.getrandbits(1) retrieves a random bit and that bit is then converted into a bool (True or False) and then into an int (1 or 0). 1’s are considered to be heads. Though this code can handle larger numbers than 10E8, all run times are limited to 10E8 due to a RAM limitation in the Fortran code.</p>
<div class="w3-container" style="text-align:center;">
Table 1: Python Coin Flip Results
</div>
<table>
<thead>
<tr>
<th style="text-align: left">Flips</th>
<th style="text-align: center">Number of Cores</th>
<th style="text-align: center">Run Time (sec)</th>
<th style="text-align: center">Speed Up</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">10E8</td>
<td style="text-align: center">1</td>
<td style="text-align: center">407.2</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">205.7</td>
<td style="text-align: center">1.98</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">148.7</td>
<td style="text-align: center">2.74</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">130.7</td>
<td style="text-align: center">3.11</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">116.5</td>
<td style="text-align: center">3.50</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">112.9</td>
<td style="text-align: center">3.61</td>
</tr>
</tbody>
</table>
<p><br /></p>
<div class="w3-container">
<img src="/images/Coin_flip_timings_Python.png" class="w3-round" alt="Python speed up" />
<div class="w3-container" style="text-align:center;">
Figure 1: Python Code Speed Up
</div>
</div>
<p>As seen in Table 1, using two cores cuts the run time in half while four cores gives a speedup of three times. It’s interesting that five cores gives another 14 seconds of speedup because hyperthreaded cores are not usually known to benefit parallel programming. The following is dependent on exactly what you’re doing (i.e. int operations vs floating point operations) and your processor architecture, but in general it’s true. A hyperthreaded core has two logical cores that can be scheduled simultaneously, but both cores can’t run instructions at the exact same time because only one core physically exists. So the two logical cores switch back and forth quickly. Generally, high performance computing (HPC) clusters have hyperthreading functionality turned off because the performance of most HPC software is adversely affected with hyperthreading on. Figure 1 shows the speed up as a function of number of cores. There is nearly a linear relationship up to 3 cores, but then the curve levels off.</p>
<div id="fortran">Below is the Fortran code:</div>
<div class="language-fortran highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">! coin_flip_omp.f90 </span><span class="w">
</span><span class="c1">!</span><span class="w">
</span><span class="c1">! FUNCTIONS:</span><span class="w">
</span><span class="c1">! coin_flip - Entry point of console application.</span><span class="w">
</span><span class="c1">!</span><span class="w">
</span><span class="c1">!****************************************************************************</span><span class="w">
</span><span class="c1">!</span><span class="w">
</span><span class="c1">! PROGRAM: coin_flip</span><span class="w">
</span><span class="c1">!</span><span class="w">
</span><span class="c1">! PURPOSE: A simple parallel coin flipping program</span><span class="w">
</span><span class="c1">! CREATOR: Will Pisani</span><span class="w">
</span><span class="c1">! DATE: July 2, 2018</span><span class="w">
</span><span class="c1">!</span><span class="w">
</span><span class="c1">!****************************************************************************</span><span class="w">
</span><span class="k">program</span><span class="w"> </span><span class="n">coin_flip_omp</span><span class="w">
</span><span class="c1">! Import libraries</span><span class="w">
</span><span class="k">use</span><span class="w"> </span><span class="n">omp_lib</span><span class="w">
</span><span class="k">implicit</span><span class="w"> </span><span class="k">none</span><span class="w">
</span><span class="c1">! Variables</span><span class="w">
</span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">parameter</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">MyLongIntType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">selected_int_kind</span><span class="w"> </span><span class="p">(</span><span class="mi">10</span><span class="p">)</span><span class="w">
</span><span class="kt">integer</span><span class="w"> </span><span class="p">(</span><span class="nb">kind</span><span class="o">=</span><span class="n">MyLongIntType</span><span class="p">)</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">num_of_flips</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">10E8</span><span class="w">
</span><span class="kt">integer</span><span class="w"> </span><span class="p">(</span><span class="nb">kind</span><span class="o">=</span><span class="n">MyLongIntType</span><span class="p">)</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="nb">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="w">
</span><span class="kt">integer</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">proc_num</span><span class="p">,</span><span class="w"> </span><span class="n">thread_num</span><span class="w">
</span><span class="kt">real</span><span class="p">,</span><span class="w"> </span><span class="k">allocatable</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">rand_num_array</span><span class="p">(:)</span><span class="w">
</span><span class="kt">real</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">seconds</span><span class="p">,</span><span class="w"> </span><span class="n">seconds_rand_array</span><span class="w">
</span><span class="c1">! Begin timing program</span><span class="w">
</span><span class="n">seconds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">omp_get_wtime</span><span class="p">()</span><span class="w">
</span><span class="c1">! Allocate rand_num_array</span><span class="w">
</span><span class="k">allocate</span><span class="p">(</span><span class="n">rand_num_array</span><span class="p">(</span><span class="n">num_of_flips</span><span class="p">))</span><span class="w">
</span><span class="c1">! Program statement</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'This program will flip a coin'</span><span class="p">,</span><span class="w"> </span><span class="n">num_of_flips</span><span class="p">,</span><span class="w"> </span><span class="s1">'times and report on the number of heads'</span><span class="w">
</span><span class="c1">! Generate an array num_of_flips long of random numbers</span><span class="w">
</span><span class="k">call</span><span class="w"> </span><span class="nb">RANDOM_NUMBER</span><span class="p">(</span><span class="n">rand_num_array</span><span class="p">)</span><span class="w">
</span><span class="c1">! Get time used to create random array</span><span class="w">
</span><span class="n">seconds_rand_array</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">omp_get_wtime</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">seconds</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'Time to generate random array on one core: '</span><span class="p">,</span><span class="w"> </span><span class="n">seconds_rand_array</span><span class="p">,</span><span class="w"> </span><span class="s1">'seconds'</span><span class="w">
</span><span class="c1">! How many processors are available?</span><span class="w">
</span><span class="n">proc_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">omp_get_num_procs</span><span class="p">()</span><span class="w">
</span><span class="n">thread_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w">
</span><span class="c1">! Set number of threads to use</span><span class="w">
</span><span class="k">call</span><span class="w"> </span><span class="n">omp_set_num_threads</span><span class="p">(</span><span class="n">thread_num</span><span class="p">)</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'Number of cores is '</span><span class="p">,</span><span class="w"> </span><span class="n">proc_num</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'Number of threads requested is '</span><span class="p">,</span><span class="w"> </span><span class="n">thread_num</span><span class="w">
</span><span class="c1">! Start while loop</span><span class="w">
</span><span class="c1">!$OMP PARALLEL DO REDUCTION(+:count)</span><span class="w">
</span><span class="k">DO</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">num_of_flips</span><span class="w">
</span><span class="c1">! if the jth value is less than 0.5, then call it heads </span><span class="w">
</span><span class="k">IF</span><span class="w"> </span><span class="p">(</span><span class="n">rand_num_array</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mf">0.5</span><span class="p">)</span><span class="w"> </span><span class="k">THEN</span><span class="w">
</span><span class="nb">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">count</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span><span class="k">END</span><span class="w"> </span><span class="k">IF</span><span class="w">
</span><span class="k">END</span><span class="w"> </span><span class="k">DO</span><span class="w">
</span><span class="c1">!$OMP END PARALLEL DO</span><span class="w">
</span><span class="c1">! End timing </span><span class="w">
</span><span class="n">seconds</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">omp_get_wtime</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">seconds</span><span class="w">
</span><span class="c1">! Print the number of heads</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'The number of heads is '</span><span class="p">,</span><span class="w"> </span><span class="nb">count</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'The percentage of heads is '</span><span class="p">,</span><span class="w"> </span><span class="nb">dble</span><span class="p">(</span><span class="nb">count</span><span class="p">)/</span><span class="nb">dble</span><span class="p">(</span><span class="n">num_of_flips</span><span class="p">)</span><span class="o">*</span><span class="mi">100</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'Time taken to tally up heads: '</span><span class="p">,</span><span class="w"> </span><span class="n">seconds</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">seconds_rand_array</span><span class="p">,</span><span class="w"> </span><span class="s1">'seconds'</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s1">'Total time taken to run:'</span><span class="p">,</span><span class="w"> </span><span class="n">seconds</span><span class="p">,</span><span class="w"> </span><span class="s1">'seconds'</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">program</span><span class="w"> </span><span class="n">coin_flip_omp</span><span class="w">
</span></code></pre></div></div>
<p>My first draft of this code was written very similarly to the Python code, but it was taking uncharacteristically long for a Fortran program to run. On a single core the code took ~200 seconds and two cores took ~800 seconds to run. The reason was <a href="https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/781695#comment-1924240">“that calling RANDOM_NUMBER inside a parallel region will introduce lock contention as there is a single seed per program.”</a> The current version of the code is significantly faster as you’ll see in the next table. Unfortunately, generating an array 1x10E8 filled with real numbers takes up a significant amount of RAM (3.8 GB, as seen in task manager on Windows 10) and an array 10E9 would take more RAM than I have. The Fortran code builds an array 10E8 long and populates it with random (real) numbers between 0 and 1. Then it goes through the array and tallies up the heads. One core builds the random array which takes ~3.9 seconds. The timings in Table 2 are the times the code took to tally up the number of heads and not the total time taken by the entire program.</p>
<div class="w3-container" style="text-align:center;">
Table 2: Fortran Coin Flip Results
</div>
<table>
<thead>
<tr>
<th style="text-align: left">Flips</th>
<th style="text-align: center">Number of Cores</th>
<th style="text-align: center">Run Time (sec)</th>
<th style="text-align: center">Speed Up</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">10E8</td>
<td style="text-align: center">1</td>
<td style="text-align: center">3.979</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">2.071</td>
<td style="text-align: center">1.92</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">1.339</td>
<td style="text-align: center">2.97</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">1.027</td>
<td style="text-align: center">3.87</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">0.890</td>
<td style="text-align: center">4.47</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">0.723</td>
<td style="text-align: center">5.50</td>
</tr>
</tbody>
</table>
<p><br /></p>
<div class="w3-container">
<img src="/images/Coin_flip_timings_Fortran.png" class="w3-round" alt="Fortran speed up" />
<div class="w3-container" style="text-align:center;">
Figure 2: Fortran Code Speed Up
</div>
</div>
<p>It’s interesting to see the difference between the Python and Fortran timings. While there is not a linear relationship between speed up and number of cores with the Python code, there definitely is a linear relationship with the Fortran code as shown by the trendline in Figure 2.</p>
<div id="cpp">Below is the C++ code:</div>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// coin_flip.cpp </span>
<span class="c1">// Purpose: A coin flipping program with OpenMP</span>
<span class="c1">// Creator: Will Pisani</span>
<span class="c1">// Date: July 3, 2018</span>
<span class="cp">#include "stdafx.h"
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <random>
#include <omp.h>
</span>
<span class="c1">// Timer code taken from https://stackoverflow.com/questions/17432502/how-can-i-measure-cpu-time-and-wall-clock-time-on-both-linux-windows</span>
<span class="c1">// Mysticial's solution</span>
<span class="c1">// Windows</span>
<span class="cp">#ifdef _WIN32
#include <Windows.h>
</span><span class="kt">double</span> <span class="nf">get_wall_time</span><span class="p">()</span> <span class="p">{</span>
<span class="n">LARGE_INTEGER</span> <span class="n">time</span><span class="p">,</span> <span class="n">freq</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">QueryPerformanceFrequency</span><span class="p">(</span><span class="o">&</span><span class="n">freq</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// Handle error</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">QueryPerformanceCounter</span><span class="p">(</span><span class="o">&</span><span class="n">time</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// Handle error</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">time</span><span class="p">.</span><span class="n">QuadPart</span> <span class="o">/</span> <span class="n">freq</span><span class="p">.</span><span class="n">QuadPart</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">double</span> <span class="nf">get_cpu_time</span><span class="p">()</span> <span class="p">{</span>
<span class="n">FILETIME</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">GetProcessTimes</span><span class="p">(</span><span class="n">GetCurrentProcess</span><span class="p">(),</span> <span class="o">&</span><span class="n">a</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">,</span> <span class="o">&</span><span class="n">c</span><span class="p">,</span> <span class="o">&</span><span class="n">d</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Returns total user time.</span>
<span class="c1">// Can be tweaked to include kernel times as well.</span>
<span class="k">return</span>
<span class="p">(</span><span class="kt">double</span><span class="p">)(</span><span class="n">d</span><span class="p">.</span><span class="n">dwLowDateTime</span> <span class="o">|</span>
<span class="p">((</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">)</span><span class="n">d</span><span class="p">.</span><span class="n">dwHighDateTime</span> <span class="o"><<</span> <span class="mi">32</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.0000001</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="c1">// Handle error</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Posix/Linux</span>
<span class="cp">#else
#include <time.h>
#include <sys/time.h>
</span><span class="kt">double</span> <span class="nf">get_wall_time</span><span class="p">()</span> <span class="p">{</span>
<span class="k">struct</span> <span class="nc">timeval</span> <span class="n">time</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">gettimeofday</span><span class="p">(</span><span class="o">&</span><span class="n">time</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// Handle error</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">time</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">+</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">time</span><span class="p">.</span><span class="n">tv_usec</span> <span class="o">*</span> <span class="mf">.000001</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">double</span> <span class="nf">get_cpu_time</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">clock</span><span class="p">()</span> <span class="o">/</span> <span class="n">CLOCKS_PER_SEC</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif
</span>
<span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Declare variables</span>
<span class="kt">long</span> <span class="n">num_of_flips</span> <span class="o">=</span> <span class="mf">10E8</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="n">row</span> <span class="o">=</span> <span class="mf">10E8</span><span class="p">;</span>
<span class="kt">double</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">// Start timing</span>
<span class="kt">double</span> <span class="n">wall0</span> <span class="o">=</span> <span class="n">get_wall_time</span><span class="p">();</span>
<span class="kt">double</span> <span class="n">cpu0</span> <span class="o">=</span> <span class="n">get_cpu_time</span><span class="p">();</span>
<span class="c1">// Program statement</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"This program will flip a coin "</span> <span class="o"><<</span> <span class="n">setprecision</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span> <span class="o"><<</span> <span class="n">num_of_flips</span> <span class="o"><<</span> <span class="s">" times and report on the number of heads.</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="cp">#pragma omp parallel num_threads(4)
</span> <span class="p">{</span>
<span class="c1">// Print number of threads in use</span>
<span class="k">if</span> <span class="p">(</span><span class="n">omp_get_thread_num</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"Number of threads: "</span> <span class="o"><<</span> <span class="n">omp_get_num_threads</span><span class="p">()</span> <span class="o"><<</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Set random number generator</span>
<span class="c1">// Each thread needs a seed which is why the following code is in the pragma section</span>
<span class="c1">//srand( (unsigned int)time(NULL));</span>
<span class="n">std</span><span class="o">::</span><span class="n">random_device</span> <span class="n">rd</span><span class="p">;</span> <span class="c1">// Will be used to obtain a seed for the random number engine</span>
<span class="n">std</span><span class="o">::</span><span class="n">mt19937</span> <span class="n">gen</span><span class="p">(</span><span class="n">rd</span><span class="p">());</span> <span class="c1">//Standard mersenne_twister_engine seeded with rd()</span>
<span class="n">std</span><span class="o">::</span><span class="n">uniform_int_distribution</span><span class="o"><></span> <span class="n">dis</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="c1">// Start for loop</span>
<span class="cp">#pragma omp for reduction(+:count)
</span> <span class="k">for</span> <span class="p">(</span><span class="kt">long</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o"><=</span> <span class="n">num_of_flips</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// Flip a coin and add it to the count.</span>
<span class="c1">// Each flip can only result in 0 and 1</span>
<span class="c1">// so each 1 will be treated as heads.</span>
<span class="n">count</span> <span class="o">=</span> <span class="n">count</span> <span class="o">+</span> <span class="n">dis</span><span class="p">(</span><span class="n">gen</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Stop timing</span>
<span class="kt">double</span> <span class="n">wall1</span> <span class="o">=</span> <span class="n">get_wall_time</span><span class="p">();</span>
<span class="kt">double</span> <span class="n">cpu1</span> <span class="o">=</span> <span class="n">get_cpu_time</span><span class="p">();</span>
<span class="c1">// Print the number of heads</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"The number of heads is "</span> <span class="o"><<</span> <span class="n">setprecision</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span> <span class="o"><<</span> <span class="n">count</span> <span class="o"><<</span> <span class="s">".</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"The percentage of heads is "</span> <span class="o"><<</span> <span class="n">count</span> <span class="o">/</span> <span class="n">num_of_flips</span> <span class="o">*</span> <span class="mi">100</span> <span class="o"><<</span> <span class="n">endl</span><span class="p">;</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"Wall Time = "</span> <span class="o"><<</span> <span class="n">wall1</span> <span class="o">-</span> <span class="n">wall0</span> <span class="o"><<</span> <span class="s">" seconds"</span> <span class="o"><<</span> <span class="n">endl</span><span class="p">;</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"CPU Time = "</span> <span class="o"><<</span> <span class="n">cpu1</span> <span class="o">-</span> <span class="n">cpu0</span> <span class="o"><<</span> <span class="s">" seconds"</span> <span class="o"><<</span> <span class="n">endl</span><span class="p">;</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I used Mysticial’s solution for getting the wall time and cpu time of OpenMP C++ code because it was the best solution I could find. This code works similarly to the Python code in that it generates a random integer on each loop. This code was easier to write than the Fortran code since I’ve had some experience coding with C/C++ and OpenMP (and MPI) during two awesome courses I took at Michigan Tech called UN5390/5391 Scientific Computing 1/2 (thanks Gowtham!). There is still room for improvement in the OpenMP sections, but it works well as is.</p>
<div class="w3-container" style="text-align:center;">
Table 3: C++ Coin Flip Results
</div>
<table>
<thead>
<tr>
<th style="text-align: left">Flips</th>
<th style="text-align: center">Number of Cores</th>
<th style="text-align: center">Run Time (sec)</th>
<th style="text-align: center">Speed Up</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">10E8</td>
<td style="text-align: center">1</td>
<td style="text-align: center">11.82</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">6.39</td>
<td style="text-align: center">1.85</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">4.56</td>
<td style="text-align: center">2.59</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">4.01</td>
<td style="text-align: center">2.95</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">3.88</td>
<td style="text-align: center">3.05</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">3.35</td>
<td style="text-align: center">3.53</td>
</tr>
</tbody>
</table>
<p><br /></p>
<div class="w3-container">
<img src="/images/Coin_flip_timings_Cpp.png" class="w3-round" alt="C++ speed up" />
<div class="w3-container" style="text-align:center;">
Figure 3: C++ Code Speed Up
</div>
</div>
<p>The C++ timings are shown in Table 3 and the speed up trend is shown in Figure 3. The speed up trend is similar to the Python code, which is interesting. I would have figured that the C++ and Fortran scaling would be similar since they share the same parallelization backend.</p>
<div id="julia">Finally, here is the Julia code:</div>
<div class="language-julia highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">#=
Parallel coin flipping code
Code mostly from Seven More Languages in Seven Weeks
=#</span>
<span class="c"># Define a variable for number of flips</span>
<span class="n">num_flips</span> <span class="o">=</span> <span class="mi">10</span><span class="o">^</span><span class="mi">8</span>
<span class="n">println</span><span class="x">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">A coin will be flipped </span><span class="si">$</span><span class="s">num_flips times."</span><span class="x">)</span>
<span class="c"># Define single proc coin flip function</span>
<span class="k">function</span><span class="nf"> flip_coins_single</span><span class="x">(</span><span class="n">times</span> <span class="o">::</span> <span class="kt">Int64</span><span class="x">)</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">:</span><span class="n">times</span>
<span class="c"># Generate a random Bool (true or false) and convert</span>
<span class="c"># that bool to an integer. Increment the count by</span>
<span class="c"># that integer (0 for false, 1 for true).</span>
<span class="n">count</span> <span class="o">+=</span> <span class="kt">Int</span><span class="x">(</span><span class="n">rand</span><span class="x">(</span><span class="kt">Bool</span><span class="x">))</span>
<span class="k">end</span>
<span class="n">println</span><span class="x">(</span><span class="s">"The number of heads is </span><span class="si">$</span><span class="s">count."</span><span class="x">)</span>
<span class="k">end</span>
<span class="c"># Run single proc coin flip function and time it</span>
<span class="n">println</span><span class="x">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Running single process coin flip function."</span><span class="x">)</span>
<span class="nd">@time</span> <span class="n">flip_coins_single</span><span class="x">(</span><span class="n">num_flips</span><span class="x">)</span>
<span class="c"># Define parallel coin flip function</span>
<span class="k">function</span><span class="nf"> pflip_coins</span><span class="x">(</span><span class="n">times</span><span class="x">)</span>
<span class="n">nheads</span> <span class="o">=</span> <span class="nd">@parallel</span> <span class="x">(</span><span class="o">+</span><span class="x">)</span> <span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">:</span><span class="n">times</span>
<span class="kt">Int</span><span class="x">(</span><span class="n">rand</span><span class="x">(</span><span class="kt">Bool</span><span class="x">))</span>
<span class="k">end</span>
<span class="n">println</span><span class="x">(</span><span class="s">"The number of heads is </span><span class="si">$</span><span class="s">nheads."</span><span class="x">)</span>
<span class="k">end</span>
<span class="c"># Add four worker processes</span>
<span class="n">num_of_proc</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">addprocs</span><span class="x">(</span><span class="n">num_of_proc</span><span class="x">)</span>
<span class="n">println</span><span class="x">(</span><span class="s">"The number of cores is </span><span class="si">$</span><span class="s">num_of_proc."</span><span class="x">)</span>
<span class="c"># Run parallel coin flip function</span>
<span class="n">println</span><span class="x">(</span><span class="s">"Running parallel coin flip function."</span><span class="x">)</span>
<span class="nd">@time</span> <span class="n">pflip_coins</span><span class="x">(</span><span class="n">num_flips</span><span class="x">)</span>
<span class="c"># Remove added worker processes</span>
<span class="n">rmprocs</span><span class="x">(</span><span class="n">workers</span><span class="x">())</span>
</code></pre></div></div>
<p>Julia is an interesting language; it’s easy to learn and very fast. I hope it achieves 1.0 status soon. With this program, I defined two functions: a single core version and a parallel core version. The Python code is actually based on this Julia code. I discovered Julia (and this coin flip algorithm) in an interesting book called <a href="https://www.amazon.com/Seven-More-Languages-Weeks-Shaping/dp/1941222153">Seven More Languages in Seven Weeks: Languages That Are Shaping the Future</a>. Julia is surprisingly the fastest of the four languages I tested. The timings in Table 4 are for the parallel function.</p>
<div class="w3-container" style="text-align:center;">
Table 4: Julia Coin Flip Results
</div>
<table>
<thead>
<tr>
<th style="text-align: left">Flips</th>
<th style="text-align: center">Number of Cores</th>
<th style="text-align: center">Run Time (sec)</th>
<th style="text-align: center">Speed Up</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">10E8</td>
<td style="text-align: center">1</td>
<td style="text-align: center">0.404</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">0.336</td>
<td style="text-align: center">1.20</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">0.325</td>
<td style="text-align: center">1.24</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">0.339</td>
<td style="text-align: center">1.19</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">0.364</td>
<td style="text-align: center">1.11</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">0.380</td>
<td style="text-align: center">1.06</td>
</tr>
<tr>
<td style="text-align: left">10E9</td>
<td style="text-align: center">1</td>
<td style="text-align: center">2.09</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">1.27</td>
<td style="text-align: center">1.65</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">1.01</td>
<td style="text-align: center">2.07</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">0.9</td>
<td style="text-align: center">2.32</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">0.81</td>
<td style="text-align: center">2.58</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">0.79</td>
<td style="text-align: center">2.65</td>
</tr>
<tr>
<td style="text-align: left">10E10</td>
<td style="text-align: center">1</td>
<td style="text-align: center">18.04</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">9.6</td>
<td style="text-align: center">1.88</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">6.95</td>
<td style="text-align: center">2.60</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">5.78</td>
<td style="text-align: center">3.12</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">5.15</td>
<td style="text-align: center">3.50</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">4.95</td>
<td style="text-align: center">3.64</td>
</tr>
<tr>
<td style="text-align: left">10E11</td>
<td style="text-align: center">1</td>
<td style="text-align: center">180.08</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">92.21</td>
<td style="text-align: center">1.95</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">69.12</td>
<td style="text-align: center">2.61</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">55.76</td>
<td style="text-align: center">3.23</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">48.8</td>
<td style="text-align: center">3.69</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">44.38</td>
<td style="text-align: center">4.06</td>
</tr>
<tr>
<td style="text-align: left">10E12</td>
<td style="text-align: center">1</td>
<td style="text-align: center">1771.9</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">2</td>
<td style="text-align: center">942.4</td>
<td style="text-align: center">1.88</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">3</td>
<td style="text-align: center">670.5</td>
<td style="text-align: center">2.64</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">4</td>
<td style="text-align: center">543</td>
<td style="text-align: center">3.26</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">5</td>
<td style="text-align: center">481.9</td>
<td style="text-align: center">3.68</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: center">6</td>
<td style="text-align: center">439.5</td>
<td style="text-align: center">4.03</td>
</tr>
</tbody>
</table>
<p><br /></p>
<div class="w3-container">
<img src="/images/Coin_flip_timings_Julia.png" class="w3-round" alt="Julia speed up" />
<div class="w3-container" style="text-align:center;">
Figure 4: Julia Code Speed Up
</div>
</div>
<p>As shown in Figure 4, I ran several different numbers of flips to examine how speed up is influenced by problem size. For 10E8 flips, there is very little speed up across the board which suggests that the problem size is not large enough to overcome the parallel overhead. For flips 10E9, 10E10, and 10E11, the corresponding scaling increases. For 10E12 flips, the scaling is nearly exactly the same as 10E11 flips.</p>
<p>For single core run times, Julia is fastest at 0.404 s followed by Fortran at 3.979 s, C++ at 11.82 s, and Python at 407.2 s. The language with the best parallel scaling is Fortran.</p>
<div id="coding">
<h3> C++, Fortran, Julia, Python Coding Resources</h3>
</div>
<p>For compiling C++ and Fortran code on Windows/macOS/Linux, I recommend downloading <a href="https://software.intel.com/en-us/parallel-studio-xe/choose-download#students">Intel Parallel Studio XE 2018</a> which is free for students with a .edu email address. For writing C++ and Fortran code on Windows 10 and macOS, I recommend downloading <a href="https://visualstudio.microsoft.com/vs/">Visual Studio IDE</a> which is also free for students. There is a bit of a learning curve with writing code, compiling, and optimizing your code with Visual Studio, but in general, it’s easier than using g++ or gfortran with a standard text editor. <a href="https://software.intel.com/en-us/articles/installing-microsoft-visual-studio-2017-for-use-with-intel-compilers">You will need to install the Intel compiler first and then install Visual Studio second with a special option selected (“Desktop development with C++”).</a>. Here are links to a <a href="https://learnxinyminutes.com/docs/c++/">C++ cheat sheet</a> and a <a href="https://learnxinyminutes.com/docs/fortran95/">Fortran cheat sheet</a>.</p>
<p>The best Python distribution is <a href="https://www.anaconda.com/download/">Anaconda Python</a> and it’s available on Windows, macOS, and Linux. If you’ve never used Python before, I recommend using Python 3.6 and sticking with that for a while (even if 3.7 comes out). I’m still on Python 2.7, but I’ll make the move soon. The best way to code Python is with the Spyder IDE (included in the Anaconda distribution). Those coming from MATLAB will feel more comfortable with Spyder since the UI is similar. Another reason to use Spyder is that it forces you to use best practices (indenting properly, etc.) and tells you when you’re missing something or made a mistake prior to running. Here is a <a href="https://learnxinyminutes.com/docs/python3/">Python cheat sheet</a>.</p>
<p>Julia is still in beta (v0.6.4) so any examples or <a href="https://julialang.org/learning/#books">books</a> you find may not be exactly correct. Google is your friend. The <a href="https://julialang.org/downloads/">Julia website</a> lists several ways to run Julia, but the way I’m using it is <a href="https://juliacomputing.com/products/juliapro.html">JuliaPro</a> which includes a customized Atom editor called Juno IDE, a debugger, and many packages for plotting, optimization, machine learning, etc. Here is a <a href="https://learnxinyminutes.com/docs/julia/">Julia cheat sheet</a>; it’s for an older version (0.4), but most of it probably is the same.</p>I’m a computational materials scientist, and naturally, I enjoy programming. Recently, I’ve been thinking about picking up a programming language other than Python to help prepare me for a post-doctoral position at a national lab. I was having a hard time choosing between C++ and Fortran. On the one hand C++ would be pretty useful because it’s the language that LAMMPS is written in and so I could extend LAMMPS to fit my needs. On the other hand, Fortran is used in NASA Glenn’s MAC/GMC code (along with tons of other legacy code) and I would love to work with the micromechanics group at NASA Glenn someday. And then I found Julia which is a programming language designed for parallelism and cloud computing and combines the ease of Python with the speed of C++/Fortran, but it is still in beta (v0.6.3 is the current version). All three would be very useful to have at my disposal. Since I have a lot of time on my hands right now, I’m going to try to learn all three.Roleplaying with Skyrim2017-11-20T00:00:00+00:002017-11-20T00:00:00+00:00http://wapisani.github.io/Roleplaying-with-Skyrim<p>When I first saw the reveal trailer for the Nintendo Switch, I was quite surprised and happy to see The Elder Scrolls V: Skyrim running on the hybrid console. I’ve put in nearly 150 hours into the original PC version of the game over several characters, but I still haven’t experienced everything the game offers. Of the three DLC expansions, I had only played Dawnguard (the other two being Hearthfire and Dragonborn). At the time of the trailer, it was speculated that the Switch version of Skyrim would be the special edition of the game. Now we <i>know</i> that it is the special edition which not only includes the three DLC expansions, but also has updated graphical effects. Some reviews are calling it the definitive version of the vanilla game (vanilla == no mods). I can’t wait to play it again come Christmas Day.</p>
<p>I saw this Reddit thread the other day titled <a href="https://www.reddit.com/r/NintendoSwitch/comments/7dgetm/make_skyrim_great_again_build_your_character_here/?st=ja8h9sk4&sh=41e2d277">“Make Skyrim Great Again - Build Your Character Here”</a> that suggests people who have played Skyrim for many, many hours try something new by coming up with a character to roleplay as. Since I’ve already played the game for 150 hours, this sounded like a grand idea to me. I have never roleplayed a character like this before. I mean, I’ve said to myself “this character will be sneaky” or “this character will use brute force”, but I have never come up with a complete character with name and everything before even starting the game. So I’ve been thinking about this and writing down some notes on my character every day since I saw that thread. This blog post will outline and discuss this character.</p>
<p>I’ve been thinking about the next Star Wars film entry “The Last Jedi” and how Luke might now be a gray jedi (walking the line between light and dark side, and capable of using either side’s Force powers). I thought it would be fun to make my Skyrim character walk the line between light and dark. And so my character’s primary skills will be conjuration, restoration, and sneak. The sneak skill may sound dark-side, but it is an all-around useful skill. (Now, I just want to say that Skyrim doesn’t have a morality meter like Knights of the Old Republic, Jade Empire, or Mass Effect. I am imposing a dichotomous morality system on the game.) Conjuration involves summoning weapons and creatures from “beyond”, as well as reanimating dead bodies. Necromancy is widely considered to be very dark-side not only in many other video games, but also in other mediums (books and films). My thinking is that my character would regularly rely upon summoned weapons, but would only summon creatures and reanimate dead bodies when in great need. Restoration is as light-side a skill as there is, especially when you consider that there are restoration spells that deal damage only to the undead like zombies and vampires.</p>
<p>Even my character’s name revolves around this idea of straddling the light and dark: Luciana Nyx. Luciana means “light” and Nyx means “night”. Light in the night could mean a good, light-side person brightening the night, but I intend it to mean someone who walks the line between light and dark. Her Dawnguard adventures will literally be a light-side person brightening the night as she combats vampires with sun magic.</p>
<p>Luciana’s secondary skills would be enchanting, lockpicking, pickpocket, alteration, and alchemy. Enchanting is always a useful skill for a mage. Considering the absolute plethora of locked objects in Skyrim, lockpicking is a necessary skill. Pickpocket will be part of her dark side. Alteration is a very useful skill for exploring (waterbreathing, detect life, detect undead, magelight) and combat (passive magic resistance and active magic armor). Now that I have writen it down, I’m thinking that alteration and sneak will switch places. I chose alchemy because I always avoided it in the past and I want to try it out.</p>
<p>Luciana’s birthsign and race will be the lord and Breton, respectively. The Lord Stone adds 50 points to your armor rating and adds 25% magic resistance. Breton bloods grants a 25% magic resistance and give +10 to conjuration and +5 to alchemy, alteration, illusion, restoration, and speech. So Luciana would have a total of 50% magic resistance without accounting for any armor effects or skill perks.</p>
<p>In Skyrim, there is a civil war between the Empire and the Stormcloaks. Luciana will choose to join the Empire because they have a big picture view of the world. They know that there will be another conflict with the Thalmor and a unified empire is the way to victory. Ulfric Stormcloak is also a racist that reminds me too much of Donald Trump so that’s another reason for Luciana to choose the empire.</p>
<p>A character actually living in the world of Skyrim would have favorite foods, books, gemstones, beverages, etc. Luciana’s favorite beverage will be Honningbrew Mead, favorite food will be Elsweyr Fondue, favorite treat will be Honey Nut Treat, and favorite gemstone will be flawless sapphire (but she’ll take normal sapphires as well). As for her favorite book, Luciana will be an academic that wants to read every book she comes across. She likely won’t have a favorite book, but we’ll see.</p>
<p>There are several different guilds in Skyrim that one can join. Luciana will join the College of Winterhold to learn more about magic and to read all of their books (she will be quite the voracious reader). She will also join the Dawnguard to rid the world of vampires.</p>
<p>One aspect of Luciana that I still don’t know is her origin. Where did she come from? How did she end up being captured along with Ulfric Stormcloak? Does she know that she is Dragonborn? Did her family know that she has such great potential? Maybe these are questions that will never be answered. One thing I do know is that she is young, in her mid-20s.</p>
<p>There are nine Divines in Skyrim: Akatosh, Arkay, Dibella, Julianos, Kynareth, Mara, Stendarr, Zenithar, and Talos. Luciana’s favorite is Julianos because he is the god of wisdom and logic. Her favorite Daedric Prince is Meridia because Meridia has an everlasting hatred of the undead and will reward those who seek to destroy them. Luciana plans to become Meridia’s champion and obtain the fabled Daedric artifact Dawnbreaker. Dawnbreaker is a holy sword forged to burn away corruption and false life (the undead). This will help Luciana tremendously in her Dawnguard adventure. Another Daedric artifact that would be useful is Spellbreaker which is imbued with a ward spell that reduces magic damage by 50 points. This ward is renewed every time the shield is raised. This artifact would be quite useful when facing a powerful enemy mage or a dragon.</p>
<p>If there’s interest, I might write a few journal entries from Luciana Nyx’s perspective once I get Skyrim on the Nintendo Switch.</p>When I first saw the reveal trailer for the Nintendo Switch, I was quite surprised and happy to see The Elder Scrolls V: Skyrim running on the hybrid console. I’ve put in nearly 150 hours into the original PC version of the game over several characters, but I still haven’t experienced everything the game offers. Of the three DLC expansions, I had only played Dawnguard (the other two being Hearthfire and Dragonborn). At the time of the trailer, it was speculated that the Switch version of Skyrim would be the special edition of the game. Now we know that it is the special edition which not only includes the three DLC expansions, but also has updated graphical effects. Some reviews are calling it the definitive version of the vanilla game (vanilla == no mods). I can’t wait to play it again come Christmas Day.Album Statistics with Python2017-09-20T00:00:00+00:002017-09-20T00:00:00+00:00http://wapisani.github.io/Album-Statistics<p>In May of 2014, I released my first video game music album titled <i>Aural Nostalgia Vol. 1</i> in partial fulfillment of the requirements to graduate from the Honors Institute at Michigan Tech.</p>
<p>Fast-forward three years and I have made somewhere in the realm of $200 to $300. The past several months my income from this album has been roughly $9/month. The company that distributes my album (and takes care of royalty payments to the copyright holders) is Soundrop and every month they send me a CSV file of the previous month’s transactions. This file contains a wealth of information that is tedius to go through by hand using MS Excel. So I put my coding skills to good use and wrote up a Python script that will read in the CSV file, parse the contents, and plot several variables as pie charts.</p>
<p>The variables I’m interested in are total quantities purchased or streamed as a function of service and total money earned as a function of track, country, and service. Figure 1 shows the total amount of streams or purchases by service. Spotify has the most streams at 87.7% and Apple Music has the second largest piece of the pie at 7.9%. Figure 1 shows that people stream my music more than they buy and download it.</p>
<div class="w3-card-4">
<img src="/images/Sep_2017_09-15-2017_Quantity.png" class="w3-round" alt="Quantity Stats" />
<div class="w3-container" style="text-align:center;">
Figure 1: Total streams/purchases by service
</div>
</div>
<p><br />
Figure 2 shows the income earned by country. Unsurprisingly, the United States makes up almost three-quarters of the pie. The “Other” category includes all countries with income less than 15 cents. I <i>am</i> surprised by how many countries (39!) listen to my music, though.</p>
<div class="w3-card-4">
<img src="/images/Sep_2017_09-15-2017.png" class="w3-round" alt="Money by country" />
<div class="w3-container" style="text-align:center;">
Figure 2: Total money earned by country
</div>
</div>
<p><br /></p>
<p>Figure 3 shows the income earned by service. Spotify again makes up the largest piece of the pie, which is a little surprising because streams earn less than purchases. As seen in Figure 1, there was a lot of streams this month. Unlike some other artists, I don’t mind people streaming my music instead of buying it outright. That’s what I do. I can’t even remember the last time I purchased music from iTunes, Google Play, or Amazon. I have backed a few Kickstarter albums, though.</p>
<p>Before now, I haven’t even heard of iTunes Match or Google Play Locker. It seems that iTunes Match lets you upload your own iTunes library (up to 100,000 songs) to the cloud for $25 a year so you can stream them from up to nine devices. So kind of like Google Music in the beginning except Google Music was free. So I guess artists still make money when a song is uploaded to the cloud via iTunes Match? It looks like Google Play Locker is similar, but is free and allows for 50,000 songs.</p>
<div class="w3-card-4">
<img src="/images/Sep_2017_09-15-2017_Service.png" class="w3-round" alt="service stats" />
<div class="w3-container" style="text-align:center;">
Figure 3: Total money earned by service
</div>
</div>
<p><br />
Figure 4 shows the total money earned by track. It appears that my arrangements of the two Metroid Prime 1/2 songs are the most popular followed by “Mt. Coronet” from Pokemon Diamond/Pearl/Platinum. Maybe I should release more Metroid Prime Trilogy music. Well, I do have <a href="https://soundcloud.com/willpisani/theme-of-u-mos-3-13-2013">four</a> <a href="https://soundcloud.com/willpisani/torvus-bog-redux-3-13-2013">in</a> <a href="https://soundcloud.com/willpisani/metroid-prime-3-corruption-1">the</a> <a href="https://soundcloud.com/willpisani/mptrilogy-title-theme-7-4-2012">pipeline</a>, at various stages of completion.</p>
<div class="w3-card-4">
<img src="/images/Sep_2017_09-15-2017_Track.png" class="w3-round" alt="Track Stats" />
<div class="w3-container" style="text-align:center;">
Figure 4: Total money earned by track
</div>
</div>
<p><br /></p>In May of 2014, I released my first video game music album titled Aural Nostalgia Vol. 1 in partial fulfillment of the requirements to graduate from the Honors Institute at Michigan Tech.2016/2017 New Years Resolutions2016-12-28T00:00:00+00:002016-12-28T00:00:00+00:00http://wapisani.github.io/New-Years-Resolutions<p>This post reviews my 2016 resolutions and details my resolutions for 2017.</p>
<p><b>2016 Resolutions</b><br />
I believe I had three main resolutions in 2016: keep in better touch with friends and family, release a new music album, and read 20 books. The first I did okay with, but I definitely could have done better. The second I regret not completing because now it will cost me $9.99 per cover song that I wish to release. Loudr is undergoing some rather unfavorable changes (for cover artists, at least). If I had submitted my album before December I wouldn’t have had to pay anything for the licensing up front. The previous model took a percentage of your sales figures as royalties. I’m definitely rather upset with Loudr now; being a hobbyist arranger and poor grad student, I don’t have the money to purchase mechanical licensing for each of the songs I want to release. For a 10 song album, that’s $100 up front! My <a href="https://play.spotify.com/album/6GbX9I4VbLUTvQJAiRSkGy">8 song album released in May 2014</a> made around $250 since release. If I paid the mechanical license fees, I wouldn’t see any profits for almost a year! Ridiculous! So I’m done with releasing music for money until I can find a better licensing company.</p>
<p>The third resolution, I will only make it about halfway. As of this post, I have read 10 books in 2016 which is half of my goal of 20 books. Still, 10 books is much, much better than previous years. I used <a href="http://www.pisanifamily.info/will/Book_List.html">my personal website to keep track of my reading</a> which increased the fun I had reading this year. I love coding, and writing a web page in HTML/CSS is very similar. I came up with a nice way of calculating how many books I’ve read: using javascript to count the number of instances of the word “Grade” on the web page. Only the books I’ve finished have the word “Grade” in their section. Anyway, I consider this resolution to be “successful” because it has reignited my love of reading novels for pleasure. After re-reading the <i>The Last Herald-Mage</i> trilogy by Mercedes Lackey, I’ve been drawn back into the Valdemar series. I plan to read through all of the Valdemar books that I own again, and I’ll add them to the book list. Then I’ll go through and read the ones that I don’t yet own (and haven’t read). Another series that I’m planning on reading is the Word and Void series by Terry Brooks; I’ve read the first book <i>Running with the Demon</i>, but I haven’t read the second or third books. Depending on how those books go, I may return to the Shannara series by Terry Brooks. I’ll start with <i>Armageddon’s Children</i>, <i>The Elves of Cintra</i>, and <i>The Gypsy Morph</i> because they transition from the Word and Void series into the Shannara series plus I haven’t read them. As for the Shannara books, I think I’ve read most of them, but it’s been a very long time. I’m also planning on reading the Mass Effect novels by Drew Karpyshyn which I’ve had for a couple years, but somehow haven’t read yet. I’m also planning on re-reading the His Dark Materials series by Philip Pullman again; it’s been about 8 years since I read those books. I’ll also probably re-read the Eragon books at some point. The reason I re-read books is because I really like them or their series and want to enjoy reading them again, and because I wonder how my more adult perspective will affect the experience. Will I enjoy them even more? Will I enjoy them less? The same? Guess I’ll have to read them and find out!</p>
<p><b>Now on to discussing the 2017 resolutions!</b></p>
<p>I feel like I’m ambitious with my resolutions this year because I have two primary resolutions and two secondary resolutions. The primary resolutions are (1) play my alto saxophone for at least 60 minutes per week and (2) spend at least 60 minutes of my free time per week writing up an ebook focused on MD modeling. The secondary resolutions are (1) spend 30 minutes per week attempting to learn how to play the piano and (2) read at least 100 pages per week.</p>
<p>I played the alto and baritone (bari) saxophones, switching back and forth, throughout my seven years of musical education; I played the alto sax in 6th grade and all of high school and the bari sax in 7th, 8th, 10th, and 12th grades. I marched the alto sax all four years of high school marching band and played it for concert band in 9th grade and wind symphony in 11th grade. I played the bari sax in concert band in 10th grade and wind symphony in 12th grade. I really enjoyed playing the saxophone and being in band all seven years. I considered myself to be pretty good, but not amazing. I enjoyed playing, but I wasn’t ambitious in my playing. Not like my amazing sister who is fantastic at playing the french horn and loves music so much that in high school she drove an hour each way to participate in the <a href="http://grys.org/">Grand Rapids Youth Symphony</a>, an organization for “Western Michigan’s most talented young musicians to rehearse and perform together under demanding professional standards.” And now she’s going to school for music education and participates in a bunch of music-related activities. Much more musically ambitious than me. If Michigan Tech had a marching band instead of the pep band, I likely would have continued my playing. That wasn’t the only factor, though. My coursework, other interests, making friends, broomball, etc. caused my sax playing to fall by the wayside during my time as an undergrad. Now I would like to start playing again.</p>
<p>So I’m going to try playing my alto sax for at least 60 minutes per week. It’ll be hard going in the beginning because I’ll have to review how to read sheets of music and the saxophone fingerings. But it’ll get easier with practice. I’m hoping that getting back into playing will help with my music arranging. I also want to play for Leila, my fiancé, because she has never heard me play.</p>
<p>Being a poor Ph.D. student I’ve looked into additional income streams, but a lot of them don’t work well. A bunch of survey type things that pay pennies per survey. Well, in my googling I found a <a href="http://thegradstudentway.com/blog/?p=86">web page</a> (authored by a grad student) which said that an ebook written to solve a problem that is unique to your situation is the best way to make a second income. It takes a lot of work to write it, but once it’s written and published, you’re set.</p>
<p>I’m going to try working on this ebook for at least 60 minutes per week. The problem this ebook will solve is becoming familiar with MD modeling and running simulations. To avoid ethical/legal issues, all simulations, post-processing, and compiling will be done with my own hardware. All time put into this ebook will be my own free time and will not take time away from my research. All compilation, simulation, and post-processing scripts will be written from scratch. All models will be created from scratch and will be different models than the ones used in my research. The book will assume that the reader has little to no knowledge of MD modeling and LAMMPS. It will assume basic UNIX and Python skills, but will include links to learning resources just in case. This book is not meant to be a comprehensive resource for MD modeling or LAMMPS; it’s meant to explain just enough to understand what’s going on and how to interpret standard MD simulations. It will be an excellent primer on getting started with MD modeling and running simulations with LAMMPS. Perhaps some excerpts will become blog posts.</p>
<p>My first secondary resolution is to spend at least 30 minutes per week learning how to play the piano. I have an old MIDI keyboard that would be super helpful in my video game music arranging if only I knew how to play it. The goal of this resolution is to become good enough with the keyboard to enable me to compose music. It’s quite painful clicking every single note into the piano roll of a DAW (Digital Audio Workstation). I feel like I could compose something halfway decent if only I could get it into the computer easily. The other secondary resolution is to read at least 100 pages per week. By my calculations, reading 100 pages per week should result in reading about 17 books in 2017. I assumed that the average novel contains 300 pages. Here’s my math:</p>
<center><img src="/images/book_equation_12-28-2016.png" alt="How I calculated the number of books" /></center>
<p>Between these four resolutions, my Ph.D., and my life at home with my lovely fiancé I should be quite busy!</p>This post reviews my 2016 resolutions and details my resolutions for 2017.