<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>eScience Center Blog</title><description>Research software engineering, data science, and digital scholarship — by the Netherlands eScience Center</description><link>https://blog.esciencecenter.nl/</link><language>en</language><atom:link href="https://blog.esciencecenter.nl/rss.xml" rel="self" type="application/rss+xml"/><item><title>Research Software Engineers: Between Academia and Industry</title><link>https://blog.esciencecenter.nl/posts/2026-08-27---rse-survey</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-08-27---rse-survey</guid><description>&lt;p&gt;What is exactly a Research Software Engineer?&lt;/p&gt;
&lt;h2 id=&quot;a-representative-survey&quot;&gt;A Representative Survey&lt;/h2&gt;
&lt;p&gt;The definition of Research Software Engineers (RSEs) is, according to the &lt;a href=&quot;http://researchsoftware.org/&quot;&gt;website of the international RSE community&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Research Software Engineers are people who combine professional software expertise with an understanding of research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Defining the specifics, however is less straight-forward. How much of a researcher is somebody with ‘an understanding of research’? How much ‘professional software expertise’ is there? To get a more fine-grained view, we have asked the people who know best: RSEs working in this profession.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;RSEs Technical Work between engineering and research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;767&quot; height=&quot;431&quot; src=&quot;https://blog.esciencecenter.nl/_astro/rse-scale.DEaUFCV7_1lkowP.webp&quot; srcset=&quot;&quot;&gt;
Source: &lt;a href=&quot;https://zenodo.org/record/5531839&quot;&gt;Katz et al., 2021&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For a survey sent out to the 38 RSEs at the Netherlands eScience Center — one of the largest institutions of Research Software Engineering in the world — we have received 28 completed responses. This proportion gives statistically robust insights about how the RSEs NL eScience Center see their role.&lt;/p&gt;
&lt;h2 id=&quot;engineer-or-researcher&quot;&gt;Engineer or Researcher?&lt;/h2&gt;
&lt;p&gt;The core of this survey is the question: “do you see yourself more as a software engineer or as a researcher?” The following chart also shows how they spend their time (discounting administrative and other work):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Do you see yourself as an engineer or a researcher&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/engineer-vs-researcher.DmBht059_Z1b0vvk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;More than half of the participants (15) see themselves more as engineers (upper bar). 8 RSEs, on the other hand, position themselves towards the researcher’s end of the scale. A clear majority on the engineering side, but the result is far from definitive.&lt;/p&gt;
&lt;p&gt;When it comes to spending time, on the other hand, it is. Less than a third of the RSEs divide their time equally, but most of them are mostly busy with software engineering. Many of them would prefer spending more time with research. However, this preference is not shared by the whole RSE population either, as the same number of mostly-engineering RSEs would even like to increase their engineering time proportion:&lt;/p&gt;
&lt;!-- Values 1,2 merged as &quot;mostly engineering&quot; --&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want more engineering,7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want to keep current balance,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want more Research,8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want more engineering,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want to keep current balance,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want more Research,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;!-- Same as above with all values separate
```mermaid
sankey
    Doing mostly Engineering,Want much more Engineering,1
    Doing mostly Engineering,Keep current balance,3
    Doing mostly Engineering,Want more Research,3
    Doing more Engineering,Want much more Engineering,3
    Doing more Engineering,Want more Engineering,3
    Doing more Engineering,Keep current balance,3
    Doing more Engineering,Want more Research,5
    Doing both Equally,Want more Engineering,1
    Doing both Equally,Keep current balance,5
    Doing both Equally,Want more Research,1
``` --&gt;
&lt;p&gt;Let’s focus on the types of output that RSEs value more. The most important contribution for an engineer is software itself, whereas researchers traditionally mostly contribute to academic publications. These answers are not mutually exclusive, hence respondents can deem both software and academic output as equally important.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How important is contribution to software vs. academic output for you?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/software-vs-academic.Y965509W_ks174.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Nevertheless, there is a near-consensus among RSEs that software contributions are somewhat important (upper bar). For academic publications, this looks different: a third of the participants does not consider academic output as important part of their work (bottom bar).&lt;/p&gt;
&lt;p&gt;At the same time, the RSEs see a difference between their own priorities and those of their employer. While the organisation’s importance for software output roughly aligns with their own judgement, only two RSEs think that the eScience Center does not consider academic output important.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How important is contribution to software vs. academic output for your employer?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/software-vs-academic-employer.COOZXhpI_Z2k0uYi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;skills&quot;&gt;Skills&lt;/h2&gt;
&lt;p&gt;Ideally, the tasks in a job align with the skills required for those tasks. In the self-perception of the NL eScience Center RSEs, this is not always the case. Again, we have asked the RSEs about the differences between software engineering and research, but in relation to their own qualification. In summary, all RSEs feel (highly) qualified for their engineering tasks. For research, the group of highly qualified ones is slightly smaller, and a few RSEs even feel underqualified.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Self-estimation of software and research skills&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/skills.D0Ohh8YY_zJjni.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The next question zooms in to whether the respective skills of RSEs are sufficient for doing their job. In line with the self-estimated qualification, there is a large group that has more than sufficient skills for solving their engineering tasks. For the research tasks, the image looks similar: most RSEs feel over-qualified rather than lacking skills.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Are your skills sufficient?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/skills-sufficient.BY7ejRUh_Z1ppOaN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;!-- The high level of qualification on both software engineering and research, aligns with the Center&apos;s ambition to be the national center of research software expertise. For the engineering part in particular, it indicates that the bar could even be raised. --&gt;
&lt;h2 id=&quot;where-do-we-come-from&quot;&gt;Where do we come from?&lt;/h2&gt;
&lt;p&gt;While not being a requirement for the profession, almost two-thirds of RSEs at the NL eScience Center have a PhD. Among the rest, most hold a Master’s degree.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pie showData&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    title Highest Degrees of RSEs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;PhD&quot;: 18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Master&apos;s or equivalent&quot;: 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Bachelor&apos;s or equivalent&quot;: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Other (please comment)&quot;: 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;a href=&quot;https://blog.esciencecenter.nl/posts/(http://rse-survey.soton.ac.uk/superset/dashboard/p/2Kjmv91MxeB/)&quot;&gt;global RSE Survey&lt;/a&gt;, the picture looks similar, albeit more scattered:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE Survey highest degree&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;583&quot; height=&quot;401&quot; src=&quot;https://blog.esciencecenter.nl/_astro/highest-level-of-education-2026-07-13T13-33-15.552Z.DEqvMuxd_Zc6fIu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the age distribution, we do not see much diversity either, with most RSEs being in the age group of 36 to 45 years of age.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Age distribution of RSEs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;563&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/age.CiCtgmQV_YDcV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/yxKPJp5mNgO/&quot;&gt;the global RSE community&lt;/a&gt;, the age distribution has roughly the same shape:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE Age Distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;724&quot; height=&quot;410&quot; src=&quot;https://blog.esciencecenter.nl/_astro/age-2026-07-13T13-43-05.695Z.CjJ3gM4o_1r5wAa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;When it comes to specific subjects of study, on the other hand, we see a rather broad distribution. The group who studied Physics or a sub-discipline thereof is the largest, followed by Computer/Computational Science. Computational Linguistics and Artificial Intelligence are the only other subjects studied by more than a single RSE.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Degrees by subject&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;729&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/subjects.ug0wj1Hb_Zq3cSV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The distribution, however, appears less diverse when zooming out a bit: the proportion of &lt;em&gt;STEM&lt;/em&gt; subjects (&lt;em&gt;Science, technology, engineering, mathematics&lt;/em&gt;) resembles election results seen in dictatorships: it comes close to 100%, even when considering Computational Linguistics as at least partly outside of the STEM category.
Again, the &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/Wj3Pn9dZvqo/&quot;&gt;global RSE survey&lt;/a&gt; shows almost the same tendency:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE survey subjects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1350&quot; height=&quot;544&quot; src=&quot;https://blog.esciencecenter.nl/_astro/subjects-global.DpnD91CO_ReSf0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;-and-where-do-we-go&quot;&gt;… and where do we go?&lt;/h2&gt;
&lt;p&gt;By the definition of this survey, all participants have the same current job title: Research Software Engineer. But we wanted to know about their previous roles as well as about their anticipated next job.
The following diagram shows the flow from previous jobs (left) to future jobs (right) of the surveyed RSEs.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Research Software Engineer or similar,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Research Software Engineer or similar,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Software Developer,-&gt;Software Developer,3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Research Software Engineer or similar,2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Researcher,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Researcher,-&gt;(Assistant) Professor,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Assistant) Professor,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Other,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Researcher,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Software Developer,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly, more than half of the RSEs do not hope for a change in their role: 15 of them anticipated RSE or similar as their next job as well. The second-largest group sees their future in a Software Developer position, presumably abandoning the research part of the RSE work. Other options like &lt;code&gt;Manager&lt;/code&gt; and &lt;code&gt;Post-doc&lt;/code&gt; did not get a single vote.
Apparently, there is no desire to go back to where they come from either. The vast majority of the RSEs comes from a PhD or Post-doc position, but only two RSEs express interest in pursuing another academic position in the future.&lt;/p&gt;
&lt;p&gt;The same questions with a focus on the sector rather than the specific role confirms what we see above: two thirds of the RSEs come from an academic position. For the future, we clearly see that returning to academia has little appeal compared to industry or public sector jobs. Among the three ‘Other’ respondents, two did not wish to define a preferred sector while one explicitly specified ‘Not academia’.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Public Sector,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Academia,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Industry,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Industry,4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Public Sector,2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Other,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Public Sector,-&gt;Public Sector,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also included a bit of trick question: what sector do you currently work in? It turns out that the RSEs of the eScience Center reflect the ambiguous position of the eScience Center between academia and public sector: their answers are distributed almost evenly:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    title &quot;In which sector do you currently work (the eScience Center)?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Public Sector&quot;: 15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Academia&quot;: 13&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Apart from the demographics, we can divide our survey into two main sections:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the distribution between software engineering and research, and&lt;/li&gt;
&lt;li&gt;the career paths.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the former, we see that most RSEs position themselves mostly as engineers and see themselves as better qualified for the respective tasks. In that regard, they see a slight misalignment between their own priorities and those of their employer that seems to value academic contributions higher than the RSEs do. That being said, however, there is also a significant minority that tends towards the research side of the spectrum.&lt;/p&gt;
&lt;p&gt;Looking at the career path: most RSEs come from an academic background and have joined the eScience Center after doing a PhD or a Post-doc. At the same time, almost none of them would like to go back to an academic position. Most prefer to stay RSEs, with some showing interest in a future as software developers.&lt;/p&gt;
&lt;p&gt;However, a survey among RSEs creates a blind spot regarding former RSEs that have left the profession. The results indicate that the respondents are RSEs by choice and are not planning to pursue other career paths as a next step. They do not provide insights about those who have chosen a different role.&lt;/p&gt;
&lt;p&gt;Compared to the &lt;a href=&quot;https://www.software.ac.uk/news/rse-survey-data-release&quot;&gt;RSE Survey&lt;/a&gt; that is run globally by the &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; every year, the advantage of this smaller survey lies in its representativeness, albeit for a smaller community. Individual outliers could have a larger statistical impact here, but a larger survey is not immune to biases either as it relies on a smaller, not necessarily statistically representative proportion of their total target audience.&lt;/p&gt;
&lt;p&gt;The comparisons between the two surveys have revealed very similar demographics between the eScience Center and the global RSE community. Apart from the age group and the education levels, this also applies to the gender distribution that we have not even included for the eScience Center because its distribution is even more extremely skewed than in the &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/eAgPq9lPj2J/&quot;&gt;global RSE survey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE gender distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;583&quot; height=&quot;410&quot; src=&quot;https://blog.esciencecenter.nl/_astro/gender-2026-07-13T13-44-08.240Z.BlCo9CI7_ZnLOc8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;data-publishing&quot;&gt;Data Publishing&lt;/h2&gt;
&lt;p&gt;The dataset is small enough to allow de-anonymisation. Skewed categories like gender and education in combination with a small total number of rows make it possible to identify individual survey participants. Publishing such a dataset would therefore leak private data and is therefore not desired, nor legal (cf. &lt;a href=&quot;https://gdpr.eu/&quot;&gt;GDPR&lt;/a&gt;). Before we publish the raw survey data, we have to find a validated way to do so without compromising the privacy of the participants.&lt;/p&gt;</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What is exactly a Research Software Engineer?&lt;/p&gt;
&lt;h2 id=&quot;a-representative-survey&quot;&gt;A Representative Survey&lt;/h2&gt;
&lt;p&gt;The definition of Research Software Engineers (RSEs) is, according to the &lt;a href=&quot;http://researchsoftware.org/&quot;&gt;website of the international RSE community&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Research Software Engineers are people who combine professional software expertise with an understanding of research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Defining the specifics, however is less straight-forward. How much of a researcher is somebody with ‘an understanding of research’? How much ‘professional software expertise’ is there? To get a more fine-grained view, we have asked the people who know best: RSEs working in this profession.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;RSEs Technical Work between engineering and research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;767&quot; height=&quot;431&quot; src=&quot;https://blog.esciencecenter.nl/_astro/rse-scale.DEaUFCV7_1lkowP.webp&quot; srcset=&quot;&quot;&gt;
Source: &lt;a href=&quot;https://zenodo.org/record/5531839&quot;&gt;Katz et al., 2021&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For a survey sent out to the 38 RSEs at the Netherlands eScience Center — one of the largest institutions of Research Software Engineering in the world — we have received 28 completed responses. This proportion gives statistically robust insights about how the RSEs NL eScience Center see their role.&lt;/p&gt;
&lt;h2 id=&quot;engineer-or-researcher&quot;&gt;Engineer or Researcher?&lt;/h2&gt;
&lt;p&gt;The core of this survey is the question: “do you see yourself more as a software engineer or as a researcher?” The following chart also shows how they spend their time (discounting administrative and other work):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Do you see yourself as an engineer or a researcher&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/engineer-vs-researcher.DmBht059_Z1b0vvk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;More than half of the participants (15) see themselves more as engineers (upper bar). 8 RSEs, on the other hand, position themselves towards the researcher’s end of the scale. A clear majority on the engineering side, but the result is far from definitive.&lt;/p&gt;
&lt;p&gt;When it comes to spending time, on the other hand, it is. Less than a third of the RSEs divide their time equally, but most of them are mostly busy with software engineering. Many of them would prefer spending more time with research. However, this preference is not shared by the whole RSE population either, as the same number of mostly-engineering RSEs would even like to increase their engineering time proportion:&lt;/p&gt;
&lt;!-- Values 1,2 merged as &quot;mostly engineering&quot; --&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want more engineering,7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want to keep current balance,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing mostly Engineering,Want more Research,8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want more engineering,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want to keep current balance,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Doing both Equally,Want more Research,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;!-- Same as above with all values separate
```mermaid
sankey
    Doing mostly Engineering,Want much more Engineering,1
    Doing mostly Engineering,Keep current balance,3
    Doing mostly Engineering,Want more Research,3
    Doing more Engineering,Want much more Engineering,3
    Doing more Engineering,Want more Engineering,3
    Doing more Engineering,Keep current balance,3
    Doing more Engineering,Want more Research,5
    Doing both Equally,Want more Engineering,1
    Doing both Equally,Keep current balance,5
    Doing both Equally,Want more Research,1
``` --&gt;
&lt;p&gt;Let’s focus on the types of output that RSEs value more. The most important contribution for an engineer is software itself, whereas researchers traditionally mostly contribute to academic publications. These answers are not mutually exclusive, hence respondents can deem both software and academic output as equally important.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How important is contribution to software vs. academic output for you?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/software-vs-academic.Y965509W_ks174.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Nevertheless, there is a near-consensus among RSEs that software contributions are somewhat important (upper bar). For academic publications, this looks different: a third of the participants does not consider academic output as important part of their work (bottom bar).&lt;/p&gt;
&lt;p&gt;At the same time, the RSEs see a difference between their own priorities and those of their employer. While the organisation’s importance for software output roughly aligns with their own judgement, only two RSEs think that the eScience Center does not consider academic output important.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How important is contribution to software vs. academic output for your employer?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/software-vs-academic-employer.COOZXhpI_Z2k0uYi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;skills&quot;&gt;Skills&lt;/h2&gt;
&lt;p&gt;Ideally, the tasks in a job align with the skills required for those tasks. In the self-perception of the NL eScience Center RSEs, this is not always the case. Again, we have asked the RSEs about the differences between software engineering and research, but in relation to their own qualification. In summary, all RSEs feel (highly) qualified for their engineering tasks. For research, the group of highly qualified ones is slightly smaller, and a few RSEs even feel underqualified.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Self-estimation of software and research skills&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/skills.D0Ohh8YY_zJjni.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The next question zooms in to whether the respective skills of RSEs are sufficient for doing their job. In line with the self-estimated qualification, there is a large group that has more than sufficient skills for solving their engineering tasks. For the research tasks, the image looks similar: most RSEs feel over-qualified rather than lacking skills.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Are your skills sufficient?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;889&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/skills-sufficient.BY7ejRUh_Z1ppOaN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;!-- The high level of qualification on both software engineering and research, aligns with the Center&apos;s ambition to be the national center of research software expertise. For the engineering part in particular, it indicates that the bar could even be raised. --&gt;
&lt;h2 id=&quot;where-do-we-come-from&quot;&gt;Where do we come from?&lt;/h2&gt;
&lt;p&gt;While not being a requirement for the profession, almost two-thirds of RSEs at the NL eScience Center have a PhD. Among the rest, most hold a Master’s degree.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pie showData&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    title Highest Degrees of RSEs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;PhD&quot;: 18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Master&apos;s or equivalent&quot;: 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Bachelor&apos;s or equivalent&quot;: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Other (please comment)&quot;: 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;a href=&quot;https://blog.esciencecenter.nl/posts/(http://rse-survey.soton.ac.uk/superset/dashboard/p/2Kjmv91MxeB/)&quot;&gt;global RSE Survey&lt;/a&gt;, the picture looks similar, albeit more scattered:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE Survey highest degree&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;583&quot; height=&quot;401&quot; src=&quot;https://blog.esciencecenter.nl/_astro/highest-level-of-education-2026-07-13T13-33-15.552Z.DEqvMuxd_Zc6fIu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the age distribution, we do not see much diversity either, with most RSEs being in the age group of 36 to 45 years of age.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Age distribution of RSEs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;563&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/age.CiCtgmQV_YDcV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/yxKPJp5mNgO/&quot;&gt;the global RSE community&lt;/a&gt;, the age distribution has roughly the same shape:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE Age Distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;724&quot; height=&quot;410&quot; src=&quot;https://blog.esciencecenter.nl/_astro/age-2026-07-13T13-43-05.695Z.CjJ3gM4o_1r5wAa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;When it comes to specific subjects of study, on the other hand, we see a rather broad distribution. The group who studied Physics or a sub-discipline thereof is the largest, followed by Computer/Computational Science. Computational Linguistics and Artificial Intelligence are the only other subjects studied by more than a single RSE.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Degrees by subject&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;729&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/subjects.ug0wj1Hb_Zq3cSV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The distribution, however, appears less diverse when zooming out a bit: the proportion of &lt;em&gt;STEM&lt;/em&gt; subjects (&lt;em&gt;Science, technology, engineering, mathematics&lt;/em&gt;) resembles election results seen in dictatorships: it comes close to 100%, even when considering Computational Linguistics as at least partly outside of the STEM category.
Again, the &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/Wj3Pn9dZvqo/&quot;&gt;global RSE survey&lt;/a&gt; shows almost the same tendency:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE survey subjects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1350&quot; height=&quot;544&quot; src=&quot;https://blog.esciencecenter.nl/_astro/subjects-global.DpnD91CO_ReSf0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;-and-where-do-we-go&quot;&gt;… and where do we go?&lt;/h2&gt;
&lt;p&gt;By the definition of this survey, all participants have the same current job title: Research Software Engineer. But we wanted to know about their previous roles as well as about their anticipated next job.
The following diagram shows the flow from previous jobs (left) to future jobs (right) of the surveyed RSEs.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Research Software Engineer or similar,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Research Software Engineer or similar,5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Software Developer,-&gt;Software Developer,3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Research Software Engineer or similar,2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Researcher,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Post-doc,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Researcher,-&gt;(Assistant) Professor,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Assistant) Professor,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Other,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Researcher,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Software Developer,-&gt;Research Software Engineer or similar,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PhD Student,-&gt;Founder/entrepreneur,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Research Software Engineer or similar,-&gt;Software Developer,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly, more than half of the RSEs do not hope for a change in their role: 15 of them anticipated RSE or similar as their next job as well. The second-largest group sees their future in a Software Developer position, presumably abandoning the research part of the RSE work. Other options like &lt;code&gt;Manager&lt;/code&gt; and &lt;code&gt;Post-doc&lt;/code&gt; did not get a single vote.
Apparently, there is no desire to go back to where they come from either. The vast majority of the RSEs comes from a PhD or Post-doc position, but only two RSEs express interest in pursuing another academic position in the future.&lt;/p&gt;
&lt;p&gt;The same questions with a focus on the sector rather than the specific role confirms what we see above: two thirds of the RSEs come from an academic position. For the future, we clearly see that returning to academia has little appeal compared to industry or public sector jobs. Among the three ‘Other’ respondents, two did not wish to define a preferred sector while one explicitly specified ‘Not academia’.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sankey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Public Sector,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Academia,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Industry,6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Industry,4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Public Sector,2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Academia,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Other,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Public Sector,-&gt;Public Sector,1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Industry,-&gt;Other,1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also included a bit of trick question: what sector do you currently work in? It turns out that the RSEs of the eScience Center reflect the ambiguous position of the eScience Center between academia and public sector: their answers are distributed almost evenly:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    title &quot;In which sector do you currently work (the eScience Center)?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Public Sector&quot;: 15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &quot;Academia&quot;: 13&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Apart from the demographics, we can divide our survey into two main sections:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the distribution between software engineering and research, and&lt;/li&gt;
&lt;li&gt;the career paths.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the former, we see that most RSEs position themselves mostly as engineers and see themselves as better qualified for the respective tasks. In that regard, they see a slight misalignment between their own priorities and those of their employer that seems to value academic contributions higher than the RSEs do. That being said, however, there is also a significant minority that tends towards the research side of the spectrum.&lt;/p&gt;
&lt;p&gt;Looking at the career path: most RSEs come from an academic background and have joined the eScience Center after doing a PhD or a Post-doc. At the same time, almost none of them would like to go back to an academic position. Most prefer to stay RSEs, with some showing interest in a future as software developers.&lt;/p&gt;
&lt;p&gt;However, a survey among RSEs creates a blind spot regarding former RSEs that have left the profession. The results indicate that the respondents are RSEs by choice and are not planning to pursue other career paths as a next step. They do not provide insights about those who have chosen a different role.&lt;/p&gt;
&lt;p&gt;Compared to the &lt;a href=&quot;https://www.software.ac.uk/news/rse-survey-data-release&quot;&gt;RSE Survey&lt;/a&gt; that is run globally by the &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; every year, the advantage of this smaller survey lies in its representativeness, albeit for a smaller community. Individual outliers could have a larger statistical impact here, but a larger survey is not immune to biases either as it relies on a smaller, not necessarily statistically representative proportion of their total target audience.&lt;/p&gt;
&lt;p&gt;The comparisons between the two surveys have revealed very similar demographics between the eScience Center and the global RSE community. Apart from the age group and the education levels, this also applies to the gender distribution that we have not even included for the eScience Center because its distribution is even more extremely skewed than in the &lt;a href=&quot;http://rse-survey.soton.ac.uk/superset/dashboard/p/eAgPq9lPj2J/&quot;&gt;global RSE survey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Global RSE gender distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;583&quot; height=&quot;410&quot; src=&quot;https://blog.esciencecenter.nl/_astro/gender-2026-07-13T13-44-08.240Z.BlCo9CI7_ZnLOc8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;data-publishing&quot;&gt;Data Publishing&lt;/h2&gt;
&lt;p&gt;The dataset is small enough to allow de-anonymisation. Skewed categories like gender and education in combination with a small total number of rows make it possible to identify individual survey participants. Publishing such a dataset would therefore leak private data and is therefore not desired, nor legal (cf. &lt;a href=&quot;https://gdpr.eu/&quot;&gt;GDPR&lt;/a&gt;). Before we publish the raw survey data, we have to find a validated way to do so without compromising the privacy of the participants.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/rse-scale.DEaUFCV7.png" medium="image"/><author>Carsten Schnober</author></item><item><title>New, refurbished blog</title><link>https://blog.esciencecenter.nl/posts/2026-08-19---new-refurbished-blog</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-08-19---new-refurbished-blog</guid><description>&lt;p&gt;Goodbye, Medium! Our blog is now self-hosted!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Photo by Mantas Hesthaven on Unsplash&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;572&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_euevYqprJJrV2a6t.DchowK11_hlLMV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dear readers,&lt;/p&gt;
&lt;p&gt;In the spirit of open science, we decided to leave Medium as our blogging platform. &lt;strong&gt;Since today, our blog is fully owned by us and 100% freely accessible&lt;/strong&gt;. No paywalls, no restrictions. The posts’ source is now markdown-based plain text. We are hosting it in &lt;a href=&quot;https://github.com/NLeSC/blog&quot;&gt;this public repository&lt;/a&gt;, and rendering it via GitHub actions.&lt;/p&gt;
&lt;p&gt;In order to make it future-proof, we are following a decoupled architecture: content and aesthetics are independent; so migrating the content or modifying the aesthetics is painless. We chose &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;, an open-source static website generator, as the software that puts everything together.&lt;/p&gt;
&lt;p&gt;In the near future we’ll release a blogpost about our reasons and technical details behind this refurbishment.&lt;/p&gt;
&lt;h3 id=&quot;does-it-affect-me&quot;&gt;Does it affect me?&lt;/h3&gt;
&lt;p&gt;Most likely not, unless:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You subscribed to us via Medium. If that’s the case, please be aware you’ll stop receiving updates. If you want to keep following us, we recommend that you subscribe to our &lt;a href=&quot;https://blog.esciencecenter.nl/rss.xml&quot;&gt;RSS feed&lt;/a&gt;, or follow our socials (&lt;a href=&quot;https://bsky.app/profile/esciencecenter.bsky.social&quot;&gt;Bluesky&lt;/a&gt;, &lt;a href=&quot;https://akademienl.social/@eScienceCenter&quot;&gt;Mastodon&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/company/netherlands-escience-center/?viewAsMember=true&quot;&gt;LinkedIn&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;You want to author a blogpost. This is actually easier than before. Now you can &lt;a href=&quot;https://github.com/NLeSC/blog/pulls&quot;&gt;submit your draft&lt;/a&gt; through a pull request.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For everyone else, the change should be automatic and painless&lt;/strong&gt;. The usual URL, &lt;a href=&quot;https://blog.esciencecenter.nl&quot;&gt;blog.esciencecenter.nl&lt;/a&gt;, now points to the new backend. We cloned all the content to the new version. The URLs of the cloned blogposts are preserved, and so is the URL of the RSS feed. To be even safer, the original old posts will remain available at &lt;a href=&quot;https://medium.com/escience-center/&quot;&gt;https://medium.com/escience-center/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To summarize, chances are that without the announcement you are currently reading, you probably wouldn’t have even noticed the change!&lt;/p&gt;
&lt;h2 id=&quot;a-call-for-help&quot;&gt;A call for help&lt;/h2&gt;
&lt;p&gt;Of course, we could have missed something. Please let us know if you notice that something is off. You can do so by opening a &lt;a href=&quot;https://github.com/NLeSC/blog/pulls&quot;&gt;pull request&lt;/a&gt; or contacting &lt;a href=&quot;mailto:editors@esciencecenter.nl&quot;&gt;editors@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy blogging!&lt;/p&gt;</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Goodbye, Medium! Our blog is now self-hosted!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Photo by Mantas Hesthaven on Unsplash&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;572&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_euevYqprJJrV2a6t.DchowK11_hlLMV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dear readers,&lt;/p&gt;
&lt;p&gt;In the spirit of open science, we decided to leave Medium as our blogging platform. &lt;strong&gt;Since today, our blog is fully owned by us and 100% freely accessible&lt;/strong&gt;. No paywalls, no restrictions. The posts’ source is now markdown-based plain text. We are hosting it in &lt;a href=&quot;https://github.com/NLeSC/blog&quot;&gt;this public repository&lt;/a&gt;, and rendering it via GitHub actions.&lt;/p&gt;
&lt;p&gt;In order to make it future-proof, we are following a decoupled architecture: content and aesthetics are independent; so migrating the content or modifying the aesthetics is painless. We chose &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;, an open-source static website generator, as the software that puts everything together.&lt;/p&gt;
&lt;p&gt;In the near future we’ll release a blogpost about our reasons and technical details behind this refurbishment.&lt;/p&gt;
&lt;h3 id=&quot;does-it-affect-me&quot;&gt;Does it affect me?&lt;/h3&gt;
&lt;p&gt;Most likely not, unless:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You subscribed to us via Medium. If that’s the case, please be aware you’ll stop receiving updates. If you want to keep following us, we recommend that you subscribe to our &lt;a href=&quot;https://blog.esciencecenter.nl/rss.xml&quot;&gt;RSS feed&lt;/a&gt;, or follow our socials (&lt;a href=&quot;https://bsky.app/profile/esciencecenter.bsky.social&quot;&gt;Bluesky&lt;/a&gt;, &lt;a href=&quot;https://akademienl.social/@eScienceCenter&quot;&gt;Mastodon&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/company/netherlands-escience-center/?viewAsMember=true&quot;&gt;LinkedIn&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;You want to author a blogpost. This is actually easier than before. Now you can &lt;a href=&quot;https://github.com/NLeSC/blog/pulls&quot;&gt;submit your draft&lt;/a&gt; through a pull request.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For everyone else, the change should be automatic and painless&lt;/strong&gt;. The usual URL, &lt;a href=&quot;https://blog.esciencecenter.nl&quot;&gt;blog.esciencecenter.nl&lt;/a&gt;, now points to the new backend. We cloned all the content to the new version. The URLs of the cloned blogposts are preserved, and so is the URL of the RSS feed. To be even safer, the original old posts will remain available at &lt;a href=&quot;https://medium.com/escience-center/&quot;&gt;https://medium.com/escience-center/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To summarize, chances are that without the announcement you are currently reading, you probably wouldn’t have even noticed the change!&lt;/p&gt;
&lt;h2 id=&quot;a-call-for-help&quot;&gt;A call for help&lt;/h2&gt;
&lt;p&gt;Of course, we could have missed something. Please let us know if you notice that something is off. You can do so by opening a &lt;a href=&quot;https://github.com/NLeSC/blog/pulls&quot;&gt;pull request&lt;/a&gt; or contacting &lt;a href=&quot;mailto:editors@esciencecenter.nl&quot;&gt;editors@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy blogging!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_euevYqprJJrV2a6t.DchowK11.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>A holistic approach to professional technical digital research is possible</title><link>https://blog.esciencecenter.nl/posts/2026-07-16---a-holistic-approach-to-professional-technical-digital-research-is-possible</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-07-16---a-holistic-approach-to-professional-technical-digital-research-is-possible</guid><description>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0003-4312-2537&quot;&gt;&lt;em&gt;Jeremy Cohen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.openscience.nl/en/marta-teperek&quot;&gt;&lt;em&gt;Marta Teperek&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5301-1713&quot;&gt;&lt;em&gt;Martine de Vos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0003-1448-0917&quot;&gt;&lt;em&gt;Paula Martinez Lavanchy&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-9334-7190&quot;&gt;&lt;em&gt;Thomas Pronk&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOI&lt;/strong&gt;: &lt;a href=&quot;https://doi.org/10.61686/pyrfg72916&quot;&gt;doi.org/10.61686/pyrfg72916&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Researcher using a microscope beside an overlay of connected digital research icons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;683&quot; src=&quot;https://blog.esciencecenter.nl/_astro/holistic-digital-research.d8H2HHph_20UUh9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post has also been&lt;/em&gt; &lt;a href=&quot;https://www.openscience.nl/en/cases/a-holistic-approach-to-professional-technical-digital-research-is-possible&quot;&gt;&lt;em&gt;published&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on the Open Science NL blog.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does research look like in a world where data, software, and AI are an integral part of the research process? This post explores why closer collaboration between research software engineers, data stewards, and other digital Research Technical Professionals is essential for enabling robust, reproducible, and future-ready research.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;it-is2030&quot;&gt;It is 2030,&lt;/h2&gt;
&lt;p&gt;Meet Isabella, a first-year PhD candidate in Integrative Psychology and Sports Science. She is part of Project ADAPT — Adaptive Data-Driven Approaches to Performance and Training, a collaboration between nutritional genomics and exercise physiology.&lt;/p&gt;
&lt;p&gt;Her research aims to improve the physical and mental wellbeing of athletes by tailoring diet and training to individual needs. This involves combining genetic data, biometric data from wearable devices, and contextual information such as environmental conditions. The project integrates existing datasets with newly collected data, applies advanced algorithms to generate personalised recommendations, and ensures that all outputs are reproducible, responsibly managed and securely processed. At the end of the project, all relevant research data, software, and workflows are published with persistent identifiers with a click of a button.&lt;/p&gt;
&lt;p&gt;To a reader in 2026, the breadth of expertise required for such a project could seem overwhelming. Isabella is not expected to be a specialist in software engineering, data stewardship, artificial intelligence, and domain science all at once. What makes her work possible is the environment in which she operates.&lt;/p&gt;
&lt;p&gt;Isabella is supported by a digital competence centre at her university — a coordinated ecosystem of research software engineers, data stewards, and other &lt;a href=&quot;https://step-up.ac.uk/drtp/&quot;&gt;digital Research Technical Professionals&lt;/a&gt; (dRTPs) who work alongside researchers as collaborators. This integrated support allows her to focus on scientific questions while developing essential skills in collaboration, critical thinking, and digital research practices and reproducible research.&lt;/p&gt;
&lt;p&gt;This vision illustrates what modern research increasingly requires: holistic, coordinated collaboration with digital Research Technical Professionals who are embedded within the research process.&lt;/p&gt;
&lt;h2 id=&quot;the-current-reality-recognised-roles-fragmented-support&quot;&gt;The current reality: recognised roles, fragmented support&lt;/h2&gt;
&lt;p&gt;The scenario described above is not yet the norm. But as research becomes increasingly digital, the need for such an approach will continue to grow.&lt;/p&gt;
&lt;p&gt;Across research performing organisations, roles such as research software engineers (RSEs) and data stewards are increasingly recognised, as most contemporary projects rely simultaneously on robust data practices and well-engineered software. Artificial intelligence provides a clear example of this interconnection. Training predictive algorithms, fine-tuning large language models, or developing computer vision systems requires both advanced software engineering and data stewardship skills. Responsible AI depends on transparency in model design, documentation of data provenance, ethical compliance, bias mitigation, and reproducibility. The challenges cannot be addressed by either data stewards or RSEs alone — model behaviour depends equally on software quality and data integrity.&lt;/p&gt;
&lt;p&gt;However, despite the growing recognition of the importance of dRTPs, these professionals are often organised in fragmented ways across organisations. Expertise is distributed across libraries, IT departments, research support offices, high-performance computing units, and other organisational structures. Each operates with its own processes, priorities, and entry points.&lt;/p&gt;
&lt;p&gt;For researchers, this creates unnecessary complexity. Identifying what expertise is needed — and where to find it — can be difficult, especially in interdisciplinary projects. For dRTPs, siloed structures can limit collaboration, reduce visibility, and in some cases create competition for resources.&lt;/p&gt;
&lt;p&gt;As a result, the full potential of these roles is not realised.&lt;/p&gt;
&lt;p&gt;To enable effective and accessible support, stronger collaboration between digital Research Technical Professionals is essential — particularly between RSEs and data stewards. A more integrated, holistic approach is needed, where expertise is connected rather than compartmentalised.&lt;/p&gt;
&lt;h2 id=&quot;emerging-practices-building-collaborative-support-ecosystems&quot;&gt;Emerging practices: building collaborative support ecosystems&lt;/h2&gt;
&lt;p&gt;Encouragingly, a number of initiatives already demonstrate how such collaboration can be strengthened in practice.&lt;/p&gt;
&lt;h3 id=&quot;digital-competence-centres&quot;&gt;Digital competence centres&lt;/h3&gt;
&lt;p&gt;At Utrecht University, long-standing collaboration between the library and IT services has evolved into a coordinated approach to digital Research Technical Professional support. What began as a joint programme has developed into distributed teams of data managers and research software engineers working with researchers across faculties. Efforts are currently underway to integrate this work into a university-wide digital competence center, which will provide a network structure for collaboration and serve as a more unified point of contact for researchers.&lt;/p&gt;
&lt;p&gt;A similar model exists at Amsterdam UMC, where a digital competence centre brings together expertise in research data management, software, infrastructure, and policy. Support is adapted to the needs of different research contexts. Basic skills are strengthened through local data steward networks and contributions in nationally coordinated training such as the &lt;a href=&quot;https://www.healthdata.nl/en/services/fair-data-stewards-basics-course&quot;&gt;Health-RI FAIR Data Stewards Basics course&lt;/a&gt;. More advanced projects are supported through collaboration between research software engineers and infrastructure specialists.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Digital Competence Centre (DCC) model&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The Digital Competence Centre (DCC) model has been initially developed in the Netherlands, with DCCs set up at multiple Dutch universities. However, similar models are increasingly emerging at universities and research-performing organisations in other countries, under various names. These groups, teams and centres bring together a combination of research software, research data and research computing infrastructure professionals. They may also include technical training professionals and even research project and community managers among their staff to help enhance the support their organisation is able to offer to digital research and, ultimately, to underpin more impactful, effective and sustainable research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;collaborative-training-and-community-building&quot;&gt;Collaborative training and community building&lt;/h3&gt;
&lt;p&gt;At TU Delft, joint efforts between library staff, faculty data stewards, the digital competence centre team and other expert teams have led to coordinated training programmes in research data and software management. Collaborative delivery of workshops such as Software Carpentry, Data Carpentry and CodeRefinery has not only strengthened researchers’ skills but also fostered closer working relationships between different support roles.&lt;/p&gt;
&lt;p&gt;While a dedicated training team has since been established to meet growing demand, collaboration with data stewards and research software engineers remains central to course design and delivery.&lt;/p&gt;
&lt;h3 id=&quot;towards-integrated-professional-communities&quot;&gt;Towards integrated professional communities&lt;/h3&gt;
&lt;p&gt;In the United Kingdom, the concept of “digital Research Technical Professionals” (dRTPs) is gaining traction as a way to recognise and connect communities working across research software, research data, and research computing infrastructure. This recently developed term is growing in use, both within the UK and now internationally, helping to build shared identity, improve visibility, and encourage collaboration across traditionally separate domains.&lt;/p&gt;
&lt;h3 id=&quot;the-role-offunders&quot;&gt;The role of funders&lt;/h3&gt;
&lt;p&gt;Funders are also playing an important role. In the Netherlands, the Dutch Research Council and Open Science NL support the development of &lt;a href=&quot;https://www.nwo.nl/en/researchprogrammes/implementation-plan-investments-digital-research-infrastructure&quot;&gt;digital competence centres&lt;/a&gt; as organisational hubs. These initiatives encourage collaboration between RSEs, data stewards, and infrastructure specialists, while providing researchers with clearer access points to relevant expertise.&lt;/p&gt;
&lt;p&gt;Together, these examples show that a more integrated model is both feasible and beneficial.&lt;/p&gt;
&lt;h2 id=&quot;call-to-action-for-strengthening-holisticsupport&quot;&gt;Call to action for strengthening holistic support&lt;/h2&gt;
&lt;p&gt;A shift towards holistic, collaborative support is not simply an organisational improvement. It is a prerequisite for conducting robust, reproducible, and innovative research in an increasingly data- and AI-driven world. To move from isolated examples to common practice, coordinated action is required across research performing organisations, funders, and professional communities. Each of these players should recognise that they are part of the same ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;research-performing-organisations&quot;&gt;Research performing organisations&lt;/h3&gt;
&lt;p&gt;Research performing organisations shape the local environment where both researchers and digital Research Technical Professionals are rooted. The quality of this environment — recognition, career paths, time and space to collaborate, and sustainable investment — determines the quality of their work.&lt;/p&gt;
&lt;p&gt;Research performing organisations are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Foster holistic dRTP teams: invest in the development of local communities that connect dRTPs and provide opportunities for regular interaction, shared initiatives and collaborative projects.&lt;/li&gt;
&lt;li&gt;Map and clarify existing roles and responsibilities to reduce fragmentation and improve accessibility for researchers.&lt;/li&gt;
&lt;li&gt;Develop policies and guidance that recognise research software and data as key research outputs, and that support sustainable career paths for dRTPs.&lt;/li&gt;
&lt;li&gt;Introduce local recognition mechanisms — such as awards, fellowships, or promotion criteria — that value expert professional contributions to research.&lt;/li&gt;
&lt;li&gt;Ensure sustainable investment in and recognition of key contributions of dRTP roles to research, underpinned by joining key initiatives that recognise and advocate for shifts in approaches to research assessment, e.g. &lt;a href=&quot;https://sfdora.org/&quot;&gt;DORA&lt;/a&gt; (Declaration on Research Assessment) and &lt;a href=&quot;https://www.coara.org/&quot;&gt;COARA&lt;/a&gt; (Coalition for Advancing Research Assessment).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;research-funders&quot;&gt;Research funders&lt;/h3&gt;
&lt;p&gt;Research funders can stimulate recognition of the essential contributions of dRTPs by embedding their roles, expertise, and career development into funding policies and grant evaluation criteria.&lt;/p&gt;
&lt;p&gt;Funders are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encourage and prioritise collaborative approaches that integrate research software, data, and infrastructure expertise within research projects.&lt;/li&gt;
&lt;li&gt;Ensure that funding schemes explicitly support the inclusion of research software engineers, data stewards, and related dRTPs in grant applications.&lt;/li&gt;
&lt;li&gt;Support the development of organisational structures that provide coordinated access to digital research technical expertise.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;communities-of-digital-research-technical-professionals&quot;&gt;Communities of digital research technical professionals&lt;/h3&gt;
&lt;p&gt;Communities foster the growth of collective knowledge and expertise, and foster resilience through diversity and advocacy.&lt;/p&gt;
&lt;p&gt;Communities are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Foster mutual understanding and respect across roles, recognising the complementary expertise of Research Software Engineers, data stewards, and other dRTPs.&lt;/li&gt;
&lt;li&gt;Actively seek opportunities for collaboration where shared challenges and goals exist.&lt;/li&gt;
&lt;li&gt;Contribute to building open, inclusive communities that support knowledge exchange, shared learning, collective visibility and provide the strength to advocate for and drive change.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;The research landscape is continuing to evolve rapidly alongside the changes we are seeing in digital research infrastructure and the growing capabilities offered by technologies such as Artificial Intelligence and Large Language Models. Ensuring a professional, holistic and research-led approach to digital research technologies, skills and practices is vital if we are to be able to effectively support research in the future, keep pace with rapid technological shifts and capitalise on the opportunities that they present.&lt;/p&gt;
&lt;p&gt;In this article we began by looking ahead to the challenges that researchers are increasingly being faced with through the story of our fictional researcher, Isabella. We then looked at some examples of how research-performing institutions are developing their research environment and supporting infrastructures to meet this challenge. These developments are helping to ensure that research organisations can take advantage of the opportunities available through embracing modern digital research practices. Our call to action highlights a number of ways that different stakeholders can engage and take action to help address the challenges that digital research presents as well as the wealth of opportunities it offers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;AI statement:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;This blog post was revised with support from AI tools used for correcting grammatical issues and improving clarity.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0003-4312-2537&quot;&gt;&lt;em&gt;Jeremy Cohen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.openscience.nl/en/marta-teperek&quot;&gt;&lt;em&gt;Marta Teperek&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5301-1713&quot;&gt;&lt;em&gt;Martine de Vos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0003-1448-0917&quot;&gt;&lt;em&gt;Paula Martinez Lavanchy&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-9334-7190&quot;&gt;&lt;em&gt;Thomas Pronk&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOI&lt;/strong&gt;: &lt;a href=&quot;https://doi.org/10.61686/pyrfg72916&quot;&gt;doi.org/10.61686/pyrfg72916&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Researcher using a microscope beside an overlay of connected digital research icons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;683&quot; src=&quot;https://blog.esciencecenter.nl/_astro/holistic-digital-research.d8H2HHph_20UUh9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post has also been&lt;/em&gt; &lt;a href=&quot;https://www.openscience.nl/en/cases/a-holistic-approach-to-professional-technical-digital-research-is-possible&quot;&gt;&lt;em&gt;published&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on the Open Science NL blog.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does research look like in a world where data, software, and AI are an integral part of the research process? This post explores why closer collaboration between research software engineers, data stewards, and other digital Research Technical Professionals is essential for enabling robust, reproducible, and future-ready research.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;it-is2030&quot;&gt;It is 2030,&lt;/h2&gt;
&lt;p&gt;Meet Isabella, a first-year PhD candidate in Integrative Psychology and Sports Science. She is part of Project ADAPT — Adaptive Data-Driven Approaches to Performance and Training, a collaboration between nutritional genomics and exercise physiology.&lt;/p&gt;
&lt;p&gt;Her research aims to improve the physical and mental wellbeing of athletes by tailoring diet and training to individual needs. This involves combining genetic data, biometric data from wearable devices, and contextual information such as environmental conditions. The project integrates existing datasets with newly collected data, applies advanced algorithms to generate personalised recommendations, and ensures that all outputs are reproducible, responsibly managed and securely processed. At the end of the project, all relevant research data, software, and workflows are published with persistent identifiers with a click of a button.&lt;/p&gt;
&lt;p&gt;To a reader in 2026, the breadth of expertise required for such a project could seem overwhelming. Isabella is not expected to be a specialist in software engineering, data stewardship, artificial intelligence, and domain science all at once. What makes her work possible is the environment in which she operates.&lt;/p&gt;
&lt;p&gt;Isabella is supported by a digital competence centre at her university — a coordinated ecosystem of research software engineers, data stewards, and other &lt;a href=&quot;https://step-up.ac.uk/drtp/&quot;&gt;digital Research Technical Professionals&lt;/a&gt; (dRTPs) who work alongside researchers as collaborators. This integrated support allows her to focus on scientific questions while developing essential skills in collaboration, critical thinking, and digital research practices and reproducible research.&lt;/p&gt;
&lt;p&gt;This vision illustrates what modern research increasingly requires: holistic, coordinated collaboration with digital Research Technical Professionals who are embedded within the research process.&lt;/p&gt;
&lt;h2 id=&quot;the-current-reality-recognised-roles-fragmented-support&quot;&gt;The current reality: recognised roles, fragmented support&lt;/h2&gt;
&lt;p&gt;The scenario described above is not yet the norm. But as research becomes increasingly digital, the need for such an approach will continue to grow.&lt;/p&gt;
&lt;p&gt;Across research performing organisations, roles such as research software engineers (RSEs) and data stewards are increasingly recognised, as most contemporary projects rely simultaneously on robust data practices and well-engineered software. Artificial intelligence provides a clear example of this interconnection. Training predictive algorithms, fine-tuning large language models, or developing computer vision systems requires both advanced software engineering and data stewardship skills. Responsible AI depends on transparency in model design, documentation of data provenance, ethical compliance, bias mitigation, and reproducibility. The challenges cannot be addressed by either data stewards or RSEs alone — model behaviour depends equally on software quality and data integrity.&lt;/p&gt;
&lt;p&gt;However, despite the growing recognition of the importance of dRTPs, these professionals are often organised in fragmented ways across organisations. Expertise is distributed across libraries, IT departments, research support offices, high-performance computing units, and other organisational structures. Each operates with its own processes, priorities, and entry points.&lt;/p&gt;
&lt;p&gt;For researchers, this creates unnecessary complexity. Identifying what expertise is needed — and where to find it — can be difficult, especially in interdisciplinary projects. For dRTPs, siloed structures can limit collaboration, reduce visibility, and in some cases create competition for resources.&lt;/p&gt;
&lt;p&gt;As a result, the full potential of these roles is not realised.&lt;/p&gt;
&lt;p&gt;To enable effective and accessible support, stronger collaboration between digital Research Technical Professionals is essential — particularly between RSEs and data stewards. A more integrated, holistic approach is needed, where expertise is connected rather than compartmentalised.&lt;/p&gt;
&lt;h2 id=&quot;emerging-practices-building-collaborative-support-ecosystems&quot;&gt;Emerging practices: building collaborative support ecosystems&lt;/h2&gt;
&lt;p&gt;Encouragingly, a number of initiatives already demonstrate how such collaboration can be strengthened in practice.&lt;/p&gt;
&lt;h3 id=&quot;digital-competence-centres&quot;&gt;Digital competence centres&lt;/h3&gt;
&lt;p&gt;At Utrecht University, long-standing collaboration between the library and IT services has evolved into a coordinated approach to digital Research Technical Professional support. What began as a joint programme has developed into distributed teams of data managers and research software engineers working with researchers across faculties. Efforts are currently underway to integrate this work into a university-wide digital competence center, which will provide a network structure for collaboration and serve as a more unified point of contact for researchers.&lt;/p&gt;
&lt;p&gt;A similar model exists at Amsterdam UMC, where a digital competence centre brings together expertise in research data management, software, infrastructure, and policy. Support is adapted to the needs of different research contexts. Basic skills are strengthened through local data steward networks and contributions in nationally coordinated training such as the &lt;a href=&quot;https://www.healthdata.nl/en/services/fair-data-stewards-basics-course&quot;&gt;Health-RI FAIR Data Stewards Basics course&lt;/a&gt;. More advanced projects are supported through collaboration between research software engineers and infrastructure specialists.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Digital Competence Centre (DCC) model&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The Digital Competence Centre (DCC) model has been initially developed in the Netherlands, with DCCs set up at multiple Dutch universities. However, similar models are increasingly emerging at universities and research-performing organisations in other countries, under various names. These groups, teams and centres bring together a combination of research software, research data and research computing infrastructure professionals. They may also include technical training professionals and even research project and community managers among their staff to help enhance the support their organisation is able to offer to digital research and, ultimately, to underpin more impactful, effective and sustainable research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;collaborative-training-and-community-building&quot;&gt;Collaborative training and community building&lt;/h3&gt;
&lt;p&gt;At TU Delft, joint efforts between library staff, faculty data stewards, the digital competence centre team and other expert teams have led to coordinated training programmes in research data and software management. Collaborative delivery of workshops such as Software Carpentry, Data Carpentry and CodeRefinery has not only strengthened researchers’ skills but also fostered closer working relationships between different support roles.&lt;/p&gt;
&lt;p&gt;While a dedicated training team has since been established to meet growing demand, collaboration with data stewards and research software engineers remains central to course design and delivery.&lt;/p&gt;
&lt;h3 id=&quot;towards-integrated-professional-communities&quot;&gt;Towards integrated professional communities&lt;/h3&gt;
&lt;p&gt;In the United Kingdom, the concept of “digital Research Technical Professionals” (dRTPs) is gaining traction as a way to recognise and connect communities working across research software, research data, and research computing infrastructure. This recently developed term is growing in use, both within the UK and now internationally, helping to build shared identity, improve visibility, and encourage collaboration across traditionally separate domains.&lt;/p&gt;
&lt;h3 id=&quot;the-role-offunders&quot;&gt;The role of funders&lt;/h3&gt;
&lt;p&gt;Funders are also playing an important role. In the Netherlands, the Dutch Research Council and Open Science NL support the development of &lt;a href=&quot;https://www.nwo.nl/en/researchprogrammes/implementation-plan-investments-digital-research-infrastructure&quot;&gt;digital competence centres&lt;/a&gt; as organisational hubs. These initiatives encourage collaboration between RSEs, data stewards, and infrastructure specialists, while providing researchers with clearer access points to relevant expertise.&lt;/p&gt;
&lt;p&gt;Together, these examples show that a more integrated model is both feasible and beneficial.&lt;/p&gt;
&lt;h2 id=&quot;call-to-action-for-strengthening-holisticsupport&quot;&gt;Call to action for strengthening holistic support&lt;/h2&gt;
&lt;p&gt;A shift towards holistic, collaborative support is not simply an organisational improvement. It is a prerequisite for conducting robust, reproducible, and innovative research in an increasingly data- and AI-driven world. To move from isolated examples to common practice, coordinated action is required across research performing organisations, funders, and professional communities. Each of these players should recognise that they are part of the same ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;research-performing-organisations&quot;&gt;Research performing organisations&lt;/h3&gt;
&lt;p&gt;Research performing organisations shape the local environment where both researchers and digital Research Technical Professionals are rooted. The quality of this environment — recognition, career paths, time and space to collaborate, and sustainable investment — determines the quality of their work.&lt;/p&gt;
&lt;p&gt;Research performing organisations are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Foster holistic dRTP teams: invest in the development of local communities that connect dRTPs and provide opportunities for regular interaction, shared initiatives and collaborative projects.&lt;/li&gt;
&lt;li&gt;Map and clarify existing roles and responsibilities to reduce fragmentation and improve accessibility for researchers.&lt;/li&gt;
&lt;li&gt;Develop policies and guidance that recognise research software and data as key research outputs, and that support sustainable career paths for dRTPs.&lt;/li&gt;
&lt;li&gt;Introduce local recognition mechanisms — such as awards, fellowships, or promotion criteria — that value expert professional contributions to research.&lt;/li&gt;
&lt;li&gt;Ensure sustainable investment in and recognition of key contributions of dRTP roles to research, underpinned by joining key initiatives that recognise and advocate for shifts in approaches to research assessment, e.g. &lt;a href=&quot;https://sfdora.org/&quot;&gt;DORA&lt;/a&gt; (Declaration on Research Assessment) and &lt;a href=&quot;https://www.coara.org/&quot;&gt;COARA&lt;/a&gt; (Coalition for Advancing Research Assessment).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;research-funders&quot;&gt;Research funders&lt;/h3&gt;
&lt;p&gt;Research funders can stimulate recognition of the essential contributions of dRTPs by embedding their roles, expertise, and career development into funding policies and grant evaluation criteria.&lt;/p&gt;
&lt;p&gt;Funders are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encourage and prioritise collaborative approaches that integrate research software, data, and infrastructure expertise within research projects.&lt;/li&gt;
&lt;li&gt;Ensure that funding schemes explicitly support the inclusion of research software engineers, data stewards, and related dRTPs in grant applications.&lt;/li&gt;
&lt;li&gt;Support the development of organisational structures that provide coordinated access to digital research technical expertise.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;communities-of-digital-research-technical-professionals&quot;&gt;Communities of digital research technical professionals&lt;/h3&gt;
&lt;p&gt;Communities foster the growth of collective knowledge and expertise, and foster resilience through diversity and advocacy.&lt;/p&gt;
&lt;p&gt;Communities are called to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Foster mutual understanding and respect across roles, recognising the complementary expertise of Research Software Engineers, data stewards, and other dRTPs.&lt;/li&gt;
&lt;li&gt;Actively seek opportunities for collaboration where shared challenges and goals exist.&lt;/li&gt;
&lt;li&gt;Contribute to building open, inclusive communities that support knowledge exchange, shared learning, collective visibility and provide the strength to advocate for and drive change.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;The research landscape is continuing to evolve rapidly alongside the changes we are seeing in digital research infrastructure and the growing capabilities offered by technologies such as Artificial Intelligence and Large Language Models. Ensuring a professional, holistic and research-led approach to digital research technologies, skills and practices is vital if we are to be able to effectively support research in the future, keep pace with rapid technological shifts and capitalise on the opportunities that they present.&lt;/p&gt;
&lt;p&gt;In this article we began by looking ahead to the challenges that researchers are increasingly being faced with through the story of our fictional researcher, Isabella. We then looked at some examples of how research-performing institutions are developing their research environment and supporting infrastructures to meet this challenge. These developments are helping to ensure that research organisations can take advantage of the opportunities available through embracing modern digital research practices. Our call to action highlights a number of ways that different stakeholders can engage and take action to help address the challenges that digital research presents as well as the wealth of opportunities it offers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;AI statement:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;This blog post was revised with support from AI tools used for correcting grammatical issues and improving clarity.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/holistic-digital-research.d8H2HHph.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>How to Maximize your Science per Watt: Energy-Efficient GPU Computing at ISC 2026</title><link>https://blog.esciencecenter.nl/posts/2026-07-09---how-to-maximize-your-science-per-watt-energy-efficient-gpu-computing-at-isc-2026</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-07-09---how-to-maximize-your-science-per-watt-energy-efficient-gpu-computing-at-isc-2026</guid><description>&lt;blockquote&gt;
&lt;p&gt;GPUs power many of today’s large-scale scientific simulations, data analysis workflows, and AI applications. However, all that computing power comes at a huge cost: &lt;strong&gt;energy usage&lt;/strong&gt;. As demand for compute continues to grow, energy efficiency is becoming just as important as performance. That makes a practical question increasingly important for the HPC community: how can we maximise the scientific output from every watt spent?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each year around June, researchers, developers, vendors, and computing centres from across the HPC community gather in Hamburg for &lt;em&gt;ISC High Performance&lt;/em&gt;, Europe’s leading conference and exhibition for high-performance computing, AI, and quantum technologies.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Four presenters standing beneath the Energy-Efficient Computing for GPU Applications tutorial screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;850&quot; height=&quot;850&quot; src=&quot;https://blog.esciencecenter.nl/_astro/isc-2026-tutorial-team.RE1xVj2O_Z2rn2zC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: From left to right: Ben van Werkhoven (Leiden University), Skip Thijssen (Leiden University), Alessio Sclocco (NLeSC), Stijn Heldens (NLeSC)&lt;/p&gt;
&lt;p&gt;This year, a team from the Netherlands eScience Center also made the trip to Germany for the 41st edition of ISC. Our goal was to deliver, in close collaboration with the &lt;a href=&quot;https://ac.liacs.nl/&quot;&gt;Accelerated Computing group from Leiden University&lt;/a&gt;, a half-day tutorial on Energy-Efficient Computing for GPU Applications on the opening day of the conference week. Our tutorial focused on one simple question: how can you make GPU applications both faster and more energy efficient?&lt;/p&gt;
&lt;p&gt;The tutorial was built around teaching several practical skills, combining short talks with hands-on sessions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code optimisation&lt;/strong&gt;: software-level techniques that directly improve the energy efficiency of GPU code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-tuning&lt;/strong&gt;: automatically exploring the space of implementation choices to find the best trade-off between performance and energy, using our open-source tool &lt;a href=&quot;http://github.com/KernelTuner&quot;&gt;Kernel Tuner&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mixed precision&lt;/strong&gt;: how to write reduced-precision GPU kernels using &lt;a href=&quot;https://ac.liacs.nl/&quot;&gt;Kernel Float&lt;/a&gt; to get more results per joule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardware tuning&lt;/strong&gt;: measuring power consumption and finding the optimal range of GPU core clock frequencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Stijn Heldens presenting auto-tuning results to tutorial attendees&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/stijn-heldens-auto-tuning.BCC4vAP3_ZQBwXC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Stijn Heldens presenting on auto-tuning for energy efficiency.&lt;/p&gt;
&lt;p&gt;The key message of the day was: &lt;strong&gt;measure, don’t assume&lt;/strong&gt;. The fastest configuration is not always the most energy efficient. The optimal choice depends on a delicate balance between the application, the hardware, and the accuracy requirements. Whether you are a research software engineer, an HPC specialist, a systems administrator, or a domain researcher, there are always opportunities to use less energy while getting more science out of your GPU.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Modern glass facade of Congress Center Hamburg beneath a blue sky&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/congress-center-hamburg.BWK3moPa_2gd2rp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Congress Center Hamburg (CCH), yearly venue of ISC-HPC.&lt;/p&gt;
&lt;p&gt;Beyond the tutorial, ISC 2026 showed that energy efficiency has become a central topic in HPC. The headline news of the conference was &lt;em&gt;LineShine&lt;/em&gt;, a CPU-only Chinese system that debuted at number one on the &lt;a href=&quot;https://www.top500.org/&quot;&gt;TOP500&lt;/a&gt;, the list of the world’s 500 most powerful supercomputers. LineShine reached 2.2 exaflops (2.2 × 10¹⁸ floating-point operations per second) of sustained double-precision performance at 42.2 megawatts, giving it an energy efficiency of 52.07 gigaflops per watt. &lt;em&gt;JUPITER Booster&lt;/em&gt; remained the fastest system in Europe, reaching exactly 1 exaflop with an efficiency of about 63.3 gigaflops per watt.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Professor Wu Geng presenting Green500 results on the ISC main stage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/green500-presentation.COGC6tQp_ZXGleO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: Prof. Wu Geng (Virginia Tech) introducing this year’s Green500 list.&lt;/p&gt;
&lt;p&gt;Another announcement came from the &lt;a href=&quot;https://www.top500.org/lists/green500/green500-june-2026/&quot;&gt;&lt;em&gt;Green500&lt;/em&gt;&lt;/a&gt;, the list of the most energy-efficient systems in the world: for the first time in its history, the &lt;strong&gt;top ten systems were unchanged&lt;/strong&gt; from the previous edition, with the leading system achieving 73.3 gigaflops per watt. This is another sign that future gains will have to come not only from new hardware, but also from how we program and operate the systems we already have.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Anders Dam Jensen presenting a map of European AI factories at ISC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/eurohpc-strategy.DpbDj61l_Z233aS3.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Anders Dam Jensen (Executive director EuroHPC) on Europe’s future HPC and AI strategy.&lt;/p&gt;
&lt;p&gt;AI was as prominent a theme at ISC as energy efficiency. Europe is betting big on artificial intelligence through the EuroHPC Joint Undertaking, with the EU and participating countries committing to a network of 19 &lt;em&gt;AI factories&lt;/em&gt; across the continent (including one here in the Netherlands!), plus even larger &lt;em&gt;AI gigafactories&lt;/em&gt; are in the works. But training the largest AI models demands enormous amounts of electricity, and increasingly it’s power, not chips, that limits how big these systems can grow.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Professor Jack Dongarra presenting a slide about mixed precision on the ISC main stage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;663&quot; src=&quot;https://blog.esciencecenter.nl/_astro/jack-dongarra-keynote.Bn1-xOnw_Z1Yo1e2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 6: Prof. Jack Dongarra (University of Tennessee) closing the main conference program.&lt;/p&gt;
&lt;p&gt;The main conference program closed with an inspiring keynote by &lt;em&gt;Jack Dongarra&lt;/em&gt;, Turing Award winner and one of the most influential figures in numerical linear algebra software, which has shaped much of modern HPC. His message was clear: &lt;strong&gt;HPC is changing&lt;/strong&gt;. The field is moving beyond peak double-precision performance alone, toward systems and workflows that balance time, energy, accuracy, and scientific impact. Mixed precision, AI-assisted simulation, and better software will all play a critical role in this transition.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Hamburg skyline at dusk viewed from the Elbphilharmonie&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/hamburg-at-night.B94S-r-u_ZQLuMF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 7: Hamburg at night, taken from the top of the &lt;em&gt;Elbphilharmonie.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Overall, ISC 2026 made one thing clear: sustainable high-performance computing will require not only better hardware, but also better software, better tools, and close collaboration between researchers, research software engineers, and HPC experts. Energy-efficient GPU programming is not only a hardware challenge. It is also a software engineering challenge.&lt;/p&gt;
&lt;p&gt;Want to try the tutorial yourself? All materials, including the hands-on notebooks, are freely available at: &lt;a href=&quot;https://github.com/KernelTuner/energy_efficiency_tutorial/&quot;&gt;github.com/KernelTuner/energy_efficiency_tutorial/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This work was funded by the Netherlands eScience Center through SUNBEAM (OESC-25–1/4) and by the EuroHPC Joint Undertaking and national co-funding bodies through ESiWACE3 (grant agreement №101093054).&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;GPUs power many of today’s large-scale scientific simulations, data analysis workflows, and AI applications. However, all that computing power comes at a huge cost: &lt;strong&gt;energy usage&lt;/strong&gt;. As demand for compute continues to grow, energy efficiency is becoming just as important as performance. That makes a practical question increasingly important for the HPC community: how can we maximise the scientific output from every watt spent?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each year around June, researchers, developers, vendors, and computing centres from across the HPC community gather in Hamburg for &lt;em&gt;ISC High Performance&lt;/em&gt;, Europe’s leading conference and exhibition for high-performance computing, AI, and quantum technologies.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Four presenters standing beneath the Energy-Efficient Computing for GPU Applications tutorial screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;850&quot; height=&quot;850&quot; src=&quot;https://blog.esciencecenter.nl/_astro/isc-2026-tutorial-team.RE1xVj2O_Z2rn2zC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: From left to right: Ben van Werkhoven (Leiden University), Skip Thijssen (Leiden University), Alessio Sclocco (NLeSC), Stijn Heldens (NLeSC)&lt;/p&gt;
&lt;p&gt;This year, a team from the Netherlands eScience Center also made the trip to Germany for the 41st edition of ISC. Our goal was to deliver, in close collaboration with the &lt;a href=&quot;https://ac.liacs.nl/&quot;&gt;Accelerated Computing group from Leiden University&lt;/a&gt;, a half-day tutorial on Energy-Efficient Computing for GPU Applications on the opening day of the conference week. Our tutorial focused on one simple question: how can you make GPU applications both faster and more energy efficient?&lt;/p&gt;
&lt;p&gt;The tutorial was built around teaching several practical skills, combining short talks with hands-on sessions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code optimisation&lt;/strong&gt;: software-level techniques that directly improve the energy efficiency of GPU code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-tuning&lt;/strong&gt;: automatically exploring the space of implementation choices to find the best trade-off between performance and energy, using our open-source tool &lt;a href=&quot;http://github.com/KernelTuner&quot;&gt;Kernel Tuner&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mixed precision&lt;/strong&gt;: how to write reduced-precision GPU kernels using &lt;a href=&quot;https://ac.liacs.nl/&quot;&gt;Kernel Float&lt;/a&gt; to get more results per joule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardware tuning&lt;/strong&gt;: measuring power consumption and finding the optimal range of GPU core clock frequencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Stijn Heldens presenting auto-tuning results to tutorial attendees&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/stijn-heldens-auto-tuning.BCC4vAP3_ZQBwXC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Stijn Heldens presenting on auto-tuning for energy efficiency.&lt;/p&gt;
&lt;p&gt;The key message of the day was: &lt;strong&gt;measure, don’t assume&lt;/strong&gt;. The fastest configuration is not always the most energy efficient. The optimal choice depends on a delicate balance between the application, the hardware, and the accuracy requirements. Whether you are a research software engineer, an HPC specialist, a systems administrator, or a domain researcher, there are always opportunities to use less energy while getting more science out of your GPU.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Modern glass facade of Congress Center Hamburg beneath a blue sky&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/congress-center-hamburg.BWK3moPa_2gd2rp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Congress Center Hamburg (CCH), yearly venue of ISC-HPC.&lt;/p&gt;
&lt;p&gt;Beyond the tutorial, ISC 2026 showed that energy efficiency has become a central topic in HPC. The headline news of the conference was &lt;em&gt;LineShine&lt;/em&gt;, a CPU-only Chinese system that debuted at number one on the &lt;a href=&quot;https://www.top500.org/&quot;&gt;TOP500&lt;/a&gt;, the list of the world’s 500 most powerful supercomputers. LineShine reached 2.2 exaflops (2.2 × 10¹⁸ floating-point operations per second) of sustained double-precision performance at 42.2 megawatts, giving it an energy efficiency of 52.07 gigaflops per watt. &lt;em&gt;JUPITER Booster&lt;/em&gt; remained the fastest system in Europe, reaching exactly 1 exaflop with an efficiency of about 63.3 gigaflops per watt.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Professor Wu Geng presenting Green500 results on the ISC main stage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/green500-presentation.COGC6tQp_ZXGleO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: Prof. Wu Geng (Virginia Tech) introducing this year’s Green500 list.&lt;/p&gt;
&lt;p&gt;Another announcement came from the &lt;a href=&quot;https://www.top500.org/lists/green500/green500-june-2026/&quot;&gt;&lt;em&gt;Green500&lt;/em&gt;&lt;/a&gt;, the list of the most energy-efficient systems in the world: for the first time in its history, the &lt;strong&gt;top ten systems were unchanged&lt;/strong&gt; from the previous edition, with the leading system achieving 73.3 gigaflops per watt. This is another sign that future gains will have to come not only from new hardware, but also from how we program and operate the systems we already have.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Anders Dam Jensen presenting a map of European AI factories at ISC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/eurohpc-strategy.DpbDj61l_Z233aS3.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Anders Dam Jensen (Executive director EuroHPC) on Europe’s future HPC and AI strategy.&lt;/p&gt;
&lt;p&gt;AI was as prominent a theme at ISC as energy efficiency. Europe is betting big on artificial intelligence through the EuroHPC Joint Undertaking, with the EU and participating countries committing to a network of 19 &lt;em&gt;AI factories&lt;/em&gt; across the continent (including one here in the Netherlands!), plus even larger &lt;em&gt;AI gigafactories&lt;/em&gt; are in the works. But training the largest AI models demands enormous amounts of electricity, and increasingly it’s power, not chips, that limits how big these systems can grow.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Professor Jack Dongarra presenting a slide about mixed precision on the ISC main stage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;663&quot; src=&quot;https://blog.esciencecenter.nl/_astro/jack-dongarra-keynote.Bn1-xOnw_Z1Yo1e2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 6: Prof. Jack Dongarra (University of Tennessee) closing the main conference program.&lt;/p&gt;
&lt;p&gt;The main conference program closed with an inspiring keynote by &lt;em&gt;Jack Dongarra&lt;/em&gt;, Turing Award winner and one of the most influential figures in numerical linear algebra software, which has shaped much of modern HPC. His message was clear: &lt;strong&gt;HPC is changing&lt;/strong&gt;. The field is moving beyond peak double-precision performance alone, toward systems and workflows that balance time, energy, accuracy, and scientific impact. Mixed precision, AI-assisted simulation, and better software will all play a critical role in this transition.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Hamburg skyline at dusk viewed from the Elbphilharmonie&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/hamburg-at-night.B94S-r-u_ZQLuMF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 7: Hamburg at night, taken from the top of the &lt;em&gt;Elbphilharmonie.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Overall, ISC 2026 made one thing clear: sustainable high-performance computing will require not only better hardware, but also better software, better tools, and close collaboration between researchers, research software engineers, and HPC experts. Energy-efficient GPU programming is not only a hardware challenge. It is also a software engineering challenge.&lt;/p&gt;
&lt;p&gt;Want to try the tutorial yourself? All materials, including the hands-on notebooks, are freely available at: &lt;a href=&quot;https://github.com/KernelTuner/energy_efficiency_tutorial/&quot;&gt;github.com/KernelTuner/energy_efficiency_tutorial/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This work was funded by the Netherlands eScience Center through SUNBEAM (OESC-25–1/4) and by the EuroHPC Joint Undertaking and national co-funding bodies through ESiWACE3 (grant agreement №101093054).&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/isc-2026-tutorial-team.RE1xVj2O.png" medium="image"/><author>Stijn Heldens</author></item><item><title>Making 3D Real: How 3DLab Is Bringing Scientific Data to Life</title><link>https://blog.esciencecenter.nl/posts/2026-06-25---making-3d-real-how-3dlab-is-bringing-scientific-data-to-life</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-06-25---making-3d-real-how-3dlab-is-bringing-scientific-data-to-life</guid><description>&lt;p&gt;&lt;img alt=&quot;3D Gaussian Splatting visualization&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;628&quot; height=&quot;599&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_mAnikgybC6AM9aFcDx5Oxg.DR0rUdzV_Z11NQQ4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Imagine trying to understand the structural integrity of a Roman ruin, or the complex vascular network of a biological organ, by looking at a flat map or static 2D photographs. You might get the general idea, but the depth, the context, and the reality are lost in translation.&lt;/p&gt;
&lt;p&gt;We live in a three-dimensional world, yet so much of our scientific data remains trapped on two-dimensional screens. For researchers in fields ranging from digital humanities to environmental science, this is not just an aesthetic issue. It’s a barrier to discovery.&lt;/p&gt;
&lt;p&gt;Luckily, there is research software to overcome this barrier and get more insight by intuitive and photo-realistic 3D visualization. However, this software comes with another barrier: ease of use. This is where &lt;strong&gt;3DLab&lt;/strong&gt; can help you: to easily access this powerful technology.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge-capturing-the-world-around-you&quot;&gt;The Challenge: Capturing the World Around You&lt;/h2&gt;
&lt;p&gt;There is an active field of computer vision research trying to tackle how we explore new places. In simultaneous localization and mapping (SLAM), a camera with location sensors (e.g. GPS and IMU) has to both accurately track its location while simultaneously creating a digital representation of the surroundings.&lt;/p&gt;
&lt;p&gt;In recent years, SLAM has seen a huge boom in interest with the application of novel machine learning techniques. Novel scene representations like neural radiance fields have made the resulting digital models photo-realistic. In turn, 3D Gaussian Splatting has made it possible to create such photo-realistic models in under an hour and render them at high frame-rates.&lt;/p&gt;
&lt;h2 id=&quot;the-approach-gaussian-splatting&quot;&gt;The Approach: Gaussian Splatting&lt;/h2&gt;
&lt;video controls width=&quot;560&quot; height=&quot;315&quot; style=&quot;display: block; max-width: 100%; height: auto; margin: 0 auto;&quot;&gt;
  &lt;source src=&quot;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/content/videos/bicycle.mp4&quot; type=&quot;video/mp4&quot;&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p class=&quot;caption&quot;&gt;Source: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/&lt;/p&gt;
&lt;p&gt;If traditional 3D models (meshes) are like origami sculptures, Gaussian Splatting is like 3D impressionist painting. It represents a scene using millions of fuzzy 3D ellipses (“splats”). These splats can overlap and blend, allowing for incredibly realistic rendering of complex scenes, like the fuzzy texture of moss on a stone or the reflective sheen of polished marble, that traditional methods struggle to capture.&lt;/p&gt;
&lt;p&gt;However, Gaussian Splatting is complex to set up and use. It requires very specific software dependencies and careful manual workflows. 3DLab focuses on removing these hurdles, allowing researchers to input raw data and receive a high-fidelity 3D visualization without needing a second PhD in computer science.&lt;/p&gt;
&lt;p&gt;Key features of the 3DLab approach include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accessibility:&lt;/strong&gt; ease of installation through detailed step-by-step installation instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation:&lt;/strong&gt; scripts that handle the heavy lifting of pre-processing your data and training the 3D models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organization:&lt;/strong&gt; guided by a single configuration file that organizes your data and parameter settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;impact-from-artifacts-to-algorithms&quot;&gt;Impact: From Artifacts to Algorithms&lt;/h2&gt;
&lt;video controls width=&quot;560&quot; height=&quot;315&quot; style=&quot;display: block; max-width: 100%; height: auto; margin: 0 auto;&quot;&gt;
  &lt;source src=&quot;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/content/videos/garden.mp4&quot; type=&quot;video/mp4&quot;&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p class=&quot;caption&quot;&gt;Source: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/&lt;/p&gt;
&lt;p&gt;While the project has applications in medicine and engineering, its potential in the &lt;strong&gt;Social Sciences and Humanities (SH)&lt;/strong&gt; is particularly exciting.&lt;/p&gt;
&lt;p&gt;Consider the field of art history. Capturing and preserving historical sites is a meticulous process. By using the tools developed in 3DLab, researchers can create “digital twins” of heritage sites with unprecedented photo-realism. This preserves the site digitally for remote or future study. It also allows an immersive way to present this history to the public.&lt;/p&gt;
&lt;p&gt;The impact of 3DLab goes beyond just pretty pictures. It aligns with the &lt;strong&gt;FAIR principles&lt;/strong&gt; (Findable, Accessible, Interoperable, Reusable). By providing open-source automation tools, the project ensures that 3D visualizations are not just one-off artistic projects, but reproducible scientific outputs.&lt;/p&gt;
&lt;h2 id=&quot;building-a-community-of-visualizers&quot;&gt;Building a Community of Visualizers&lt;/h2&gt;
&lt;p&gt;3DLab is not developed in a vacuum. It represents a strategic effort to embed 3D expertise into the Dutch research ecosystem. The project aims to leverage the vibrant &lt;strong&gt;NL-RSE (Research Software Engineers in the Netherlands)&lt;/strong&gt; community, sharing knowledge and code to ensure these tools survive beyond the initial funding cycle.&lt;/p&gt;
&lt;p&gt;The project also highlights the collaborative nature of modern science. It sits at the intersection of computer vision, software engineering, and domain-specific research. By making the code open source on GitHub, the eScience Center invites contributions from developers and researchers worldwide, fostering a culture of shared innovation.&lt;/p&gt;
&lt;h2 id=&quot;looking-ahead&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;The work on 3DLab is just the beginning. As techniques like Gaussian Splatting mature, we gaze at the branching possibilities, like integrating these visualizations into virtual reality (VR) and augmented reality (AR) environments. Imagine a medical student walking inside a simulation of a patient’s heart, or a historian walking through a digital reconstruction of 17th-century Amsterdam.&lt;/p&gt;
&lt;p&gt;By lowering the barrier to entry, 3DLab is ensuring that the future of science isn’t just data-driven but it’s immersive, interactive, and accessible to all.&lt;/p&gt;
&lt;h2 id=&quot;get-involved&quot;&gt;Get Involved&lt;/h2&gt;
&lt;p&gt;Are you a researcher struggling to visualize high-dimensional data? Or an RSE interested in the bleeding edge of computer graphics?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explore the Code:&lt;/strong&gt; Check out the &lt;a href=&quot;https://github.com/NLeSC/3dgs_automation&quot;&gt;3D Gaussian Splatting automation repository on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the Report:&lt;/strong&gt; Dive deeper into the technical details in the &lt;a href=&quot;https://nlesc-my.sharepoint.com/:w:/g/personal/t_vanlankveld_esciencecenter_nl/IQDcC5wodS0xTYJHQKD2wM1NAZ6h-z-12IevTwMOFfgEUp0?e=3oC24W&quot;&gt;3D Lab project report&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect:&lt;/strong&gt; Reach out to &lt;em&gt;Thijs van Lankveld&lt;/em&gt; or the &lt;em&gt;eScience Center&lt;/em&gt; team to discuss how 3D visualization can transform your research.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;3D Gaussian Splatting visualization&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;628&quot; height=&quot;599&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_mAnikgybC6AM9aFcDx5Oxg.DR0rUdzV_Z11NQQ4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Imagine trying to understand the structural integrity of a Roman ruin, or the complex vascular network of a biological organ, by looking at a flat map or static 2D photographs. You might get the general idea, but the depth, the context, and the reality are lost in translation.&lt;/p&gt;
&lt;p&gt;We live in a three-dimensional world, yet so much of our scientific data remains trapped on two-dimensional screens. For researchers in fields ranging from digital humanities to environmental science, this is not just an aesthetic issue. It’s a barrier to discovery.&lt;/p&gt;
&lt;p&gt;Luckily, there is research software to overcome this barrier and get more insight by intuitive and photo-realistic 3D visualization. However, this software comes with another barrier: ease of use. This is where &lt;strong&gt;3DLab&lt;/strong&gt; can help you: to easily access this powerful technology.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge-capturing-the-world-around-you&quot;&gt;The Challenge: Capturing the World Around You&lt;/h2&gt;
&lt;p&gt;There is an active field of computer vision research trying to tackle how we explore new places. In simultaneous localization and mapping (SLAM), a camera with location sensors (e.g. GPS and IMU) has to both accurately track its location while simultaneously creating a digital representation of the surroundings.&lt;/p&gt;
&lt;p&gt;In recent years, SLAM has seen a huge boom in interest with the application of novel machine learning techniques. Novel scene representations like neural radiance fields have made the resulting digital models photo-realistic. In turn, 3D Gaussian Splatting has made it possible to create such photo-realistic models in under an hour and render them at high frame-rates.&lt;/p&gt;
&lt;h2 id=&quot;the-approach-gaussian-splatting&quot;&gt;The Approach: Gaussian Splatting&lt;/h2&gt;
&lt;video controls width=&quot;560&quot; height=&quot;315&quot; style=&quot;display: block; max-width: 100%; height: auto; margin: 0 auto;&quot;&gt;
  &lt;source src=&quot;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/content/videos/bicycle.mp4&quot; type=&quot;video/mp4&quot;&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p class=&quot;caption&quot;&gt;Source: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/&lt;/p&gt;
&lt;p&gt;If traditional 3D models (meshes) are like origami sculptures, Gaussian Splatting is like 3D impressionist painting. It represents a scene using millions of fuzzy 3D ellipses (“splats”). These splats can overlap and blend, allowing for incredibly realistic rendering of complex scenes, like the fuzzy texture of moss on a stone or the reflective sheen of polished marble, that traditional methods struggle to capture.&lt;/p&gt;
&lt;p&gt;However, Gaussian Splatting is complex to set up and use. It requires very specific software dependencies and careful manual workflows. 3DLab focuses on removing these hurdles, allowing researchers to input raw data and receive a high-fidelity 3D visualization without needing a second PhD in computer science.&lt;/p&gt;
&lt;p&gt;Key features of the 3DLab approach include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accessibility:&lt;/strong&gt; ease of installation through detailed step-by-step installation instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation:&lt;/strong&gt; scripts that handle the heavy lifting of pre-processing your data and training the 3D models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organization:&lt;/strong&gt; guided by a single configuration file that organizes your data and parameter settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;impact-from-artifacts-to-algorithms&quot;&gt;Impact: From Artifacts to Algorithms&lt;/h2&gt;
&lt;video controls width=&quot;560&quot; height=&quot;315&quot; style=&quot;display: block; max-width: 100%; height: auto; margin: 0 auto;&quot;&gt;
  &lt;source src=&quot;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/content/videos/garden.mp4&quot; type=&quot;video/mp4&quot;&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p class=&quot;caption&quot;&gt;Source: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/&lt;/p&gt;
&lt;p&gt;While the project has applications in medicine and engineering, its potential in the &lt;strong&gt;Social Sciences and Humanities (SH)&lt;/strong&gt; is particularly exciting.&lt;/p&gt;
&lt;p&gt;Consider the field of art history. Capturing and preserving historical sites is a meticulous process. By using the tools developed in 3DLab, researchers can create “digital twins” of heritage sites with unprecedented photo-realism. This preserves the site digitally for remote or future study. It also allows an immersive way to present this history to the public.&lt;/p&gt;
&lt;p&gt;The impact of 3DLab goes beyond just pretty pictures. It aligns with the &lt;strong&gt;FAIR principles&lt;/strong&gt; (Findable, Accessible, Interoperable, Reusable). By providing open-source automation tools, the project ensures that 3D visualizations are not just one-off artistic projects, but reproducible scientific outputs.&lt;/p&gt;
&lt;h2 id=&quot;building-a-community-of-visualizers&quot;&gt;Building a Community of Visualizers&lt;/h2&gt;
&lt;p&gt;3DLab is not developed in a vacuum. It represents a strategic effort to embed 3D expertise into the Dutch research ecosystem. The project aims to leverage the vibrant &lt;strong&gt;NL-RSE (Research Software Engineers in the Netherlands)&lt;/strong&gt; community, sharing knowledge and code to ensure these tools survive beyond the initial funding cycle.&lt;/p&gt;
&lt;p&gt;The project also highlights the collaborative nature of modern science. It sits at the intersection of computer vision, software engineering, and domain-specific research. By making the code open source on GitHub, the eScience Center invites contributions from developers and researchers worldwide, fostering a culture of shared innovation.&lt;/p&gt;
&lt;h2 id=&quot;looking-ahead&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;The work on 3DLab is just the beginning. As techniques like Gaussian Splatting mature, we gaze at the branching possibilities, like integrating these visualizations into virtual reality (VR) and augmented reality (AR) environments. Imagine a medical student walking inside a simulation of a patient’s heart, or a historian walking through a digital reconstruction of 17th-century Amsterdam.&lt;/p&gt;
&lt;p&gt;By lowering the barrier to entry, 3DLab is ensuring that the future of science isn’t just data-driven but it’s immersive, interactive, and accessible to all.&lt;/p&gt;
&lt;h2 id=&quot;get-involved&quot;&gt;Get Involved&lt;/h2&gt;
&lt;p&gt;Are you a researcher struggling to visualize high-dimensional data? Or an RSE interested in the bleeding edge of computer graphics?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explore the Code:&lt;/strong&gt; Check out the &lt;a href=&quot;https://github.com/NLeSC/3dgs_automation&quot;&gt;3D Gaussian Splatting automation repository on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the Report:&lt;/strong&gt; Dive deeper into the technical details in the &lt;a href=&quot;https://nlesc-my.sharepoint.com/:w:/g/personal/t_vanlankveld_esciencecenter_nl/IQDcC5wodS0xTYJHQKD2wM1NAZ6h-z-12IevTwMOFfgEUp0?e=3oC24W&quot;&gt;3D Lab project report&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect:&lt;/strong&gt; Reach out to &lt;em&gt;Thijs van Lankveld&lt;/em&gt; or the &lt;em&gt;eScience Center&lt;/em&gt; team to discuss how 3D visualization can transform your research.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_mAnikgybC6AM9aFcDx5Oxg.DR0rUdzV.webp" medium="image"/><author>Thijs van Lankveld</author></item><item><title>Research Software Engineers in the Age of GenAI: Same Value, Changing Practice</title><link>https://blog.esciencecenter.nl/posts/2026-05-28---research-software-engineers-in-the-age-of-genai-same-value-c</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-05-28---research-software-engineers-in-the-age-of-genai-same-value-c</guid><description>&lt;p&gt;&lt;em&gt;Stephan Druskat, Michelle Barker, Ian Cosden, Cunliang Geng, Robert Haines, Daniel S. Katz, Joseph Shingleton, Ben van Werkhoven&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-e2e2857a.DtjkNNeC_1OdOGE.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;This blog post is being cross-posted by the &lt;em&gt;&lt;a href=&quot;https://www.researchsoft.org/blog/&quot;&gt;&lt;em&gt;Research Software Alliance&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (ReSA), &lt;em&gt;&lt;a href=&quot;https://bssw.io/blog_posts&quot;&gt;&lt;em&gt;Better Scientific Software&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (BSSw), the &lt;em&gt;&lt;a href=&quot;https://everse.software/news/&quot;&gt;&lt;em&gt;European Virtual Institute for Research Software Excellence&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;(EVERSE) and the &lt;em&gt;&lt;a href=&quot;https://www.software.ac.uk/news-and-blogs-hub&quot;&gt;&lt;em&gt;Software Sustainability Institute&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (SSI).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;DOI: &lt;a href=&quot;https://zenodo.org/records/20320179&quot;&gt;10.5281/zenodo.20320179&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Research software and its creators have long played a critical role in the advancement of research worldwide. This role is changing in the age of “generative AI” (GenAI), but both the software and the people remain of key importance. Understanding these changes is essential in enabling Research Software Engineers (RSEs) to continue contributing the same high value to the research process and its outputs.&lt;/p&gt;
&lt;p&gt;Before GenAI, the RSE movement had learned to clearly articulate the value proposition of embedding expert software engineering in research to its stakeholders. This blog post highlights how RSEs use GenAI to increase their capacity in both software engineering and research, and visualize this evolution. While GenAI is changing — perhaps considerably — how RSEs work in practice, their value and the value of their work for research remains steady and likely to increase.&lt;/p&gt;
&lt;p&gt;Generative AI, specifically Large Language Models (LLMs) and coding agents, is rapidly changing software engineering. The practice of software engineering is shifting away from writing lines of code to specifying requirements, implementations, designs and verification strategies in higher-level abstractions, including natural language specifications, that are then enacted by an AI coding agent. This lowers the barrier to entry for producing code and reduces the development time for new solutions.&lt;/p&gt;
&lt;p&gt;Generative AI is not only impacting software development in industry, but is understandably also seeing rapid adoption in academia to accelerate software development processes. Its application enables researchers to produce their own research software, including those who would not have done so previously. Software solutions, once beyond the reach of researchers lacking programming and software engineering knowledge, are now accessible with these new GenAI tools. If researchers can write more — and better — code, themselves, it begs the question: where do RSEs fit in this new paradigm?&lt;/p&gt;
&lt;p&gt;In March 2026, 36 members of the research software community came together to discuss this at a workshop entitled “&lt;a href=&quot;https://www.researchsoft.org/events/rse-ai-workshop/&quot;&gt;Research Software Engineering in the Age of Generative AI: Building a Community Vision&lt;/a&gt;”, held in Edinburgh, UK. The Research Software Alliance co-led this event and was supported to undertake this work as part of a Schmidt Sciences grant. Whilst the impact of GenAI on research is being discussed in many forums and publications, this workshop provided an opportunity for a range of early adopters, innovators, and RSE leads to come together to discuss how the ecosystem was changing, and to chart constructive ways to shape and support this change.&lt;/p&gt;
&lt;p&gt;The workshop included multiple rounds of focused working groups, one of which discussed the value of research software engineering in the age of GenAI. This blog post is an outcome of that working group. Its authors brought together their experience as leaders of different types of RSE initiatives across the ecosystem to provide an accessible way to show both how the roles of research software personnel are evolving in line with GenAI, and how these roles remain key to enabling research impact.&lt;/p&gt;
&lt;p&gt;There are costs, concerns and risks associated with the creation and use of AI models generally [1], [2], and in a multitude of more focused areas, including skills [3], [4], [5], [6], community culture and motivation [7], [8], as well as equity and ethics [9], [10], [11]. However, while many of these risks also apply to the use of GenAI in coding tasks, there are also many immediate benefits for coding [12], [13], [14], [15]. AI tools are accelerating routine coding tasks, such as creating working scripts for data analysis, generating boilerplate code, tests and documentation, all from high-level natural language prompts. Coding agents represent a more autonomous evolution of prompt-based coding, enabling systems built around LLMs to access and operate on existing codebases to handle more complex tasks, such as refactoring or porting. They can even be used to build an entire codebase from scratch, given sufficient information such as specifications or implementation plans.&lt;/p&gt;
&lt;p&gt;As software has become one of the primary research tools across all disciplines, a significant majority of scientific results rely on the quality of that software. RSEs emerged as a result: by combining professional software engineering expertise with an intimate understanding of the research discipline, partnerships between RSEs and researchers allowed software to evolve along with research, with RSEs guiding the productive application of methods and technologies and ensuring that software meets the reliability and reproducibility standards that are expected from scientific instruments. This unique position of RSEs bridging software engineering and research was often depicted in diagrams similar to Figure 1, which shows that RSEs vary in their skills and knowledge of both software engineering and research activities. It also shows RSE-adjacent roles (such as software engineer, researcher, and researcher who codes) to provide context, illustrating that RSEs have more software engineering experience than researchers, while also possessing a deeper understanding of research practices than software engineers. Diagrams like these have been very important tools in achieving (pre-GenAI) understanding of the value provided by RSEs, to the extent that RSEs are supported by national initiatives such as those in the UK, the Netherlands and Germany [16], [17], [18].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;680&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-4c402b8d.DHWN-me0_Z101yE7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: RSEs bring both software engineering and research expertise.With the advent of GenAI, two questions arise: Is this partnership between RSEs and researchers still needed and still valuable? And, how do these roles change? In the age of GenAI, both researchers and RSEs have access to LLMs and coding agents to accelerate their work. Researchers are able to prototype and explore ideas faster and more freely than before. Meanwhile, RSEs are able to use these GenAI tools to greater effect and impact, due to their expertise in software engineering, particularly in requirements engineering and specification, software architecture, testing and verification, validation, performance, and long-term sustainability. This enables them to frame problems more precisely, to evaluate tradeoffs and verify internal correctness and consistency more effectively, and to better address longstanding challenges in research software. Moreover, their continued and frequent practice with these tools compounds their advantages, allowing them to better anticipate failure modes, enforce quality standards, and integrate tooling into complex, evolving research environments.&lt;/p&gt;
&lt;p&gt;RSEs who maintain GenAI literacy and the ability to critically evaluate complex software stacks are especially indispensable in view of the risks associated with the increasing adoption of GenAI in research software development. In particular, when researchers use agentic coding tools without sufficient expertise and experience to write increasingly complex software, over-reliance on these tools risks generating a significant disconnect between the coder and the code. This disconnect can lead to the introduction of unintended errors and inaccuracies, and could pose serious risk to the robustness of related scientific outputs and research results. In this situation, RSEs are well positioned to provide the guidance and oversight that is necessary to ensure the safe adoption of AI in research software engineering.&lt;/p&gt;
&lt;p&gt;Taken together, the value of an RSE remains significant, as the RSE role evolves to integrate expert knowledge in the application of GenAI for software engineering in research contexts. This viewpoint is similarly articulated in the &lt;a href=&quot;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&quot;&gt;Position Statement on Generative AI in the RSE Workplace&lt;/a&gt;[19], which is led by US-RSE and the Alliance for Data Science and AI. The Edinburgh workshop built upon this position statement, and it is also being shared in other conversations[20], [21]. As such, the value of RSEs in relation to researchers and other stakeholders will remain unchanged as their role as a research software professional evolves to also integrate expert knowledge in the application of GenAI in research contexts. This blog post seeks to move one step further in clearly articulating that value in a way that is easy to understand.&lt;/p&gt;
&lt;p&gt;Overall, the value of the RSE role shifts upward as AI enhances it and amplifies its impact. While the practice may change and shift focus to higher levels of abstraction, including specification and verification, the value proposition remains the same**. This is depicted in Figure 2, which shows how the use of GenAI enables the value of RSEs to increase along both the software engineering and research activity axes. It is critical for the research community to understand and acknowledge this increased potential for research impact, and to ensure that going forward, RSE expertise is appropriately supported, funded and integrated into research ecosystems.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-e2e2857a.DtjkNNeC_1OdOGE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: AI can enable RSEs to increase their capacity for both research and software engineering, irrespective of specializations.Figure 3 highlights the unique position of RSEs in the research ecosystem. RSEs and other roles in the research sector (software engineers, researchers who code, and researchers) all evolve in response to leveraging GenAI tools, which affects all groups along the software engineering capacity axis to varying degrees. Researchers who have not previously done any programming can now generate their own code, but for all non-RSE roles these shifts largely reinforce strengths within their established areas of expertise. For RSEs, however, this evolution plays to their dual focus on both software engineering and research, so that the effective value of RSEs and their work is amplified, as GenAI enables them to provide (even) more and better software to support (even) more and better research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;589&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-6f0e3f69.Cs5ozV6X_ZRCakM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: How various roles are evolving in response to GenAI.&lt;strong&gt;Acknowledgements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MB and DSK were supported to undertake this work as part of Schmidt Sciences grant G-25–69965.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author biographies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/michelledbarker/&quot;&gt;Michelle Barker&lt;/a&gt; is Director of the Research Software Alliance and has extensive expertise in open science, the research software community, digital skills, and digital research infrastructure. As a sociologist, Michelle is passionate about building collaborative partnerships to achieve system change. She is a former Director of the Australian Research Data Commons, where she led the national research software infrastructure investment program.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cosden&quot;&gt;Ian Cosden&lt;/a&gt; is the Senior Director of Research Software Engineering at Princeton University. He leads a team of research software engineers who complement multiple traditional academic research groups by offering embedded, long-term software development expertise. He spearheaded the formation of the RSE group in 2016 and has grown the group from an initial size of two FTEs, to a total of 37 FTEs as of May 2026. Ian is the current and founding chair of the steering committee for the United States Research Software Engineer (US-RSE) Association. Additionally, he is the principal investigator for Innovative Training Enabled by a Research Software Engineering Community of Trainers (INTERSECT), an NSF-funded project to develop and deliver RSE-led training events for current researchers interested in careers in research software engineering.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sdruskat.net&quot;&gt;Stephan Druskat&lt;/a&gt; is a (Research) Software Engineering Researcher based in Berlin. His research focuses on requirements, constraints, policies and practices of software engineering in academic research contexts, such as software publication, citation and sustainability, as well as software metadata and software supply chains. He is a Fellow of the Software Sustainability Institute, co-founder of the Society for Research Software in Germany (de-RSE), and lead of the Citation File Format project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/hainesr&quot;&gt;Robert Haines&lt;/a&gt; is Director of Research IT and an Honorary Lecturer at the University of Manchester, and a Fellow of the Software Sustainability Institute. He is one of the originators of the term “Research Software Engineer”, served for six years as an elected representative of the UK RSE Association, chaired the First Conference of Research Software Engineers in 2016, and was a founding trustee of the Society of Research Software Engineering. Robert’s research interests include software engineering, software sustainability, software use in open and reproducible research, software citation and credit, and career paths for software engineers and data scientists.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt; is Chief Scientist at the National Center for Supercomputing Applications, Research Professor in the Siebel School of Computing and Data Science, and Research Professor in the School of Information Sciences at the University of Illinois Urbana-Champaign. He works at the triple point of research software, people, and policy. He is a co-founder and current Associate Editor-in-Chief of the Journal of Open Source Software, co-founder of the US Research Software Engineer Association (US-RSE), and co-founder and steering committee chair of the Research Software Alliance (ReSA).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jshng-glasgow&quot;&gt;Joseph Shingleton&lt;/a&gt; is a Research Software Engineer at the University of Glasgow. His research explores how artificial intelligence can be safely and effectively applied to tasks in geospatial data science and research software engineering. He is the recipient of a UKRI Metascience AI Fellowship, focusing on how generative AI is shaping RSE practice and its consequences for the scientific process. He is also a Software Sustainability Institute Fellow and leads the SSI study group on responsible AI in RSE.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/benvanwerkhoven&quot;&gt;Ben van Werkhoven&lt;/a&gt; is assistant professor at Leiden University, where he heads the Accelerated Computing research group, focusing on making high-performance computing more energy-efficient and sustainable. He holds a PhD from VU Amsterdam on GPU-accelerated scientific computing (2014) and spent nearly a decade at the Netherlands eScience Center before joining Leiden in 2023. With over 15 years of GPU programming and optimization experience, Ben has worked on scientific applications ranging from microscopy and climate modeling to radio astronomy. He is also a co-founder of the Netherlands Research Software Engineers community (NL-RSE), advocating for the recognition of research software engineering as a professional discipline. At Leiden, he teaches High Performance Computing and Multiprocessor Programming, and serves as principal investigator on several research projects. He participates in major European and national consortia, including CORTEX and ESiWACE, advancing large-scale computing infrastructure for science.&lt;/p&gt;
&lt;p&gt;References**&lt;/p&gt;
&lt;p&gt;[1] M. Hosseini, S. P. J. M. Horbach, K. L. Holmes, and T. Ross-Hellauer, ‘Open Science at the Generative AI Turn: An Exploratory Analysis of Challenges and Opportunities’, May 24, 2024, SocArXiv*. doi: 10.31235/osf.io/zns7g.&lt;/p&gt;
&lt;p&gt;[2] G. O’Brien, ‘Threats to scientific software from over-reliance on AI code assistants’, &lt;em&gt;Nat Comput Sci&lt;/em&gt;, vol. 5, no. 9, pp. 701–703, Jul. 2025, doi: 10.1038/s43588–025–00845–2.&lt;/p&gt;
&lt;p&gt;[3] S. Andleeb, B. Kantorski, and J. C. Carver, ‘ChatGPT in Introductory Programming: Counterbalanced Evaluation of Code Quality, Conceptual Learning, and Student Perceptions’, 2025, &lt;em&gt;arXiv&lt;/em&gt;. doi: 10.48550/ARXIV.2510.00946.&lt;/p&gt;
&lt;p&gt;[4] G. O’Brien, A. Parker, N. Eisty, and J. Carver, ‘A survey of generative AI adoption and perceived productivity among scientists who program’, Apr. 09, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2512.19644. doi: 10.48550/arXiv.2512.19644.&lt;/p&gt;
&lt;p&gt;[5] SAPEA, ‘Successful and timely uptake of artificial intelligence in science in the EU: evidence review report’, SAPEA, Apr. 2024. doi: 10.5281/ZENODO.10977676.&lt;/p&gt;
&lt;p&gt;[6] M.-A. Storey, ‘From Technical Debt to Cognitive and Intent Debt: Rethinking Software Health in the Age of AI’, Apr. 06, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2603.22106. doi: 10.48550/arXiv.2603.22106.&lt;/p&gt;
&lt;p&gt;[7] R. Choudhuri, D. Liu, I. Steinmacher, M. Gerosa, and A. Sarma, ‘How Far Are We? The Triumphs and Trials of Generative AI in Learning Software Engineering’, in &lt;em&gt;Proceedings of the IEEE/ACM 46th International Conference on Software Engineering&lt;/em&gt;, Lisbon Portugal: ACM, Apr. 2024, pp. 1–13. doi: 10.1145/3597503.3639201.&lt;/p&gt;
&lt;p&gt;[8] M. Koren, G. Békés, J. Hinz, and A. Lohmann, ‘Vibe Coding Kills Open Source’, Jan. 21, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2601.15494. doi: 10.48550/arXiv.2601.15494.&lt;/p&gt;
&lt;p&gt;[9] S. A. Besser, E. A. Jensen, and D. S. Katz, ‘How generative AI is shaping research software development and maintenance at a research-intensive university’, &lt;em&gt;Open Res Europe&lt;/em&gt;, vol. 6, p. 56, Feb. 2026, doi: 10.12688/openreseurope.22009.1.&lt;/p&gt;
&lt;p&gt;[10] D. R. Newman-Griffis, ‘AI thinking and the enterprise of science’, Jun. 25, 2023, &lt;em&gt;Open Science Framework&lt;/em&gt;. doi: 10.31219/osf.io/wb83e.&lt;/p&gt;
&lt;p&gt;[11] D. Salah, ‘Invisible Risks, Visible Code: A Vision for Understanding Ethical Debt in AI-Based Coding’, in &lt;em&gt;2025 ACM/IEEE International Symposium on Empirical Software Engineering and Measurement (ESEM)&lt;/em&gt;, Honolulu, HI, USA: IEEE, Oct. 2025, pp. 442–446. doi: 10.1109/ESEM64174.2025.00074.&lt;/p&gt;
&lt;p&gt;[12] E. W. Bridgeford &lt;em&gt;et al.&lt;/em&gt;, ‘Ten Simple Rules for AI-Assisted Coding in Science’, Oct. 31, 2025, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2510.22254. doi: 10.48550/arXiv.2510.22254.&lt;/p&gt;
&lt;p&gt;[13] L. C. McInnes &lt;em&gt;et al.&lt;/em&gt;, ‘Report of the 2025 Workshop on Next-Generation Ecosystems for Scientific Computing: Harnessing Community, Software, and AI for Cross-Disciplinary Team Science’, 2025, &lt;em&gt;arXiv&lt;/em&gt;. doi: 10.48550/ARXIV.2510.03413.&lt;/p&gt;
&lt;p&gt;[14] L. Nordling, ‘How ChatGPT is transforming the postdoc experience’, &lt;em&gt;Nature&lt;/em&gt;, vol. 622, no. 7983, pp. 655–657, Oct. 2023, doi: 10.1038/d41586–023–03235–8.&lt;/p&gt;
&lt;p&gt;[15] G. O’Brien, ‘How Scientists Use Large Language Models to Program’, in &lt;em&gt;Proceedings of the 2025 CHI Conference on Human Factors in Computing Systems&lt;/em&gt;, Yokohama Japan: ACM, Apr. 2025, pp. 1–16. doi: 10.1145/3706598.3713668.&lt;/p&gt;
&lt;p&gt;[16] M. Barker &lt;em&gt;et al.&lt;/em&gt;, ‘Software and skills for research computing in the UK’, Zenodo, Jan. 2024. doi: 10.5281/ZENODO.10473186.&lt;/p&gt;
&lt;p&gt;[17] D. Kempf &lt;em&gt;et al.&lt;/em&gt;, ‘Establishing central Research Software Engineering units in German research institutions’, 2025, [Online]. Available: &lt;a href=&quot;https://de-rse.org/2023_paper-RSE-groups/paper.pdf&quot;&gt;https://de-rse.org/2023_paper-RSE-groups/paper.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[18] LCRDM, ‘Professionalizing the role of Research Software Engineers in the Netherlands’, Zenodo, Mar. 2025. doi: 10.5281/ZENODO.15019998.&lt;/p&gt;
&lt;p&gt;[19] ADSA and US-RSE, ‘Position Statement on Generative AI in the RSE Workplace’. Accessed: Apr. 28, 2026. [Online]. Available: &lt;a href=&quot;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&quot;&gt;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[20] S. Gesing, ‘RSEs 2035: Surviving or Thriving in the Age of AI’, in &lt;em&gt;2025 IEEE International Conference on eScience (eScience)&lt;/em&gt;, Chicago, IL, USA: IEEE, Sep. 2025, pp. 381–382. doi: 10.1109/eScience65000.2025.00081.&lt;/p&gt;
&lt;p&gt;[21] P. Leather, D. Silver, and S. Frezza, ‘Software engineering role archetypes’, presented at the IEEE SWEBOK Summit 2026, Apr. 2026. [Online]. Available: &lt;a href=&quot;https://conf.researchr.org/details/icse-2026/swebok-2026/5/Talk-Software-engineering-role-archetypes-mapping-knowledge-skills-and-competenci&quot;&gt;https://conf.researchr.org/details/icse-2026/swebok-2026/5/Talk-Software-engineering-role-archetypes-mapping-knowledge-skills-and-competenci&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Stephan Druskat, Michelle Barker, Ian Cosden, Cunliang Geng, Robert Haines, Daniel S. Katz, Joseph Shingleton, Ben van Werkhoven&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-e2e2857a.DtjkNNeC_1OdOGE.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;This blog post is being cross-posted by the &lt;em&gt;&lt;a href=&quot;https://www.researchsoft.org/blog/&quot;&gt;&lt;em&gt;Research Software Alliance&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (ReSA), &lt;em&gt;&lt;a href=&quot;https://bssw.io/blog_posts&quot;&gt;&lt;em&gt;Better Scientific Software&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (BSSw), the &lt;em&gt;&lt;a href=&quot;https://everse.software/news/&quot;&gt;&lt;em&gt;European Virtual Institute for Research Software Excellence&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;(EVERSE) and the &lt;em&gt;&lt;a href=&quot;https://www.software.ac.uk/news-and-blogs-hub&quot;&gt;&lt;em&gt;Software Sustainability Institute&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (SSI).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;DOI: &lt;a href=&quot;https://zenodo.org/records/20320179&quot;&gt;10.5281/zenodo.20320179&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Research software and its creators have long played a critical role in the advancement of research worldwide. This role is changing in the age of “generative AI” (GenAI), but both the software and the people remain of key importance. Understanding these changes is essential in enabling Research Software Engineers (RSEs) to continue contributing the same high value to the research process and its outputs.&lt;/p&gt;
&lt;p&gt;Before GenAI, the RSE movement had learned to clearly articulate the value proposition of embedding expert software engineering in research to its stakeholders. This blog post highlights how RSEs use GenAI to increase their capacity in both software engineering and research, and visualize this evolution. While GenAI is changing — perhaps considerably — how RSEs work in practice, their value and the value of their work for research remains steady and likely to increase.&lt;/p&gt;
&lt;p&gt;Generative AI, specifically Large Language Models (LLMs) and coding agents, is rapidly changing software engineering. The practice of software engineering is shifting away from writing lines of code to specifying requirements, implementations, designs and verification strategies in higher-level abstractions, including natural language specifications, that are then enacted by an AI coding agent. This lowers the barrier to entry for producing code and reduces the development time for new solutions.&lt;/p&gt;
&lt;p&gt;Generative AI is not only impacting software development in industry, but is understandably also seeing rapid adoption in academia to accelerate software development processes. Its application enables researchers to produce their own research software, including those who would not have done so previously. Software solutions, once beyond the reach of researchers lacking programming and software engineering knowledge, are now accessible with these new GenAI tools. If researchers can write more — and better — code, themselves, it begs the question: where do RSEs fit in this new paradigm?&lt;/p&gt;
&lt;p&gt;In March 2026, 36 members of the research software community came together to discuss this at a workshop entitled “&lt;a href=&quot;https://www.researchsoft.org/events/rse-ai-workshop/&quot;&gt;Research Software Engineering in the Age of Generative AI: Building a Community Vision&lt;/a&gt;”, held in Edinburgh, UK. The Research Software Alliance co-led this event and was supported to undertake this work as part of a Schmidt Sciences grant. Whilst the impact of GenAI on research is being discussed in many forums and publications, this workshop provided an opportunity for a range of early adopters, innovators, and RSE leads to come together to discuss how the ecosystem was changing, and to chart constructive ways to shape and support this change.&lt;/p&gt;
&lt;p&gt;The workshop included multiple rounds of focused working groups, one of which discussed the value of research software engineering in the age of GenAI. This blog post is an outcome of that working group. Its authors brought together their experience as leaders of different types of RSE initiatives across the ecosystem to provide an accessible way to show both how the roles of research software personnel are evolving in line with GenAI, and how these roles remain key to enabling research impact.&lt;/p&gt;
&lt;p&gt;There are costs, concerns and risks associated with the creation and use of AI models generally [1], [2], and in a multitude of more focused areas, including skills [3], [4], [5], [6], community culture and motivation [7], [8], as well as equity and ethics [9], [10], [11]. However, while many of these risks also apply to the use of GenAI in coding tasks, there are also many immediate benefits for coding [12], [13], [14], [15]. AI tools are accelerating routine coding tasks, such as creating working scripts for data analysis, generating boilerplate code, tests and documentation, all from high-level natural language prompts. Coding agents represent a more autonomous evolution of prompt-based coding, enabling systems built around LLMs to access and operate on existing codebases to handle more complex tasks, such as refactoring or porting. They can even be used to build an entire codebase from scratch, given sufficient information such as specifications or implementation plans.&lt;/p&gt;
&lt;p&gt;As software has become one of the primary research tools across all disciplines, a significant majority of scientific results rely on the quality of that software. RSEs emerged as a result: by combining professional software engineering expertise with an intimate understanding of the research discipline, partnerships between RSEs and researchers allowed software to evolve along with research, with RSEs guiding the productive application of methods and technologies and ensuring that software meets the reliability and reproducibility standards that are expected from scientific instruments. This unique position of RSEs bridging software engineering and research was often depicted in diagrams similar to Figure 1, which shows that RSEs vary in their skills and knowledge of both software engineering and research activities. It also shows RSE-adjacent roles (such as software engineer, researcher, and researcher who codes) to provide context, illustrating that RSEs have more software engineering experience than researchers, while also possessing a deeper understanding of research practices than software engineers. Diagrams like these have been very important tools in achieving (pre-GenAI) understanding of the value provided by RSEs, to the extent that RSEs are supported by national initiatives such as those in the UK, the Netherlands and Germany [16], [17], [18].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;680&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-4c402b8d.DHWN-me0_Z101yE7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: RSEs bring both software engineering and research expertise.With the advent of GenAI, two questions arise: Is this partnership between RSEs and researchers still needed and still valuable? And, how do these roles change? In the age of GenAI, both researchers and RSEs have access to LLMs and coding agents to accelerate their work. Researchers are able to prototype and explore ideas faster and more freely than before. Meanwhile, RSEs are able to use these GenAI tools to greater effect and impact, due to their expertise in software engineering, particularly in requirements engineering and specification, software architecture, testing and verification, validation, performance, and long-term sustainability. This enables them to frame problems more precisely, to evaluate tradeoffs and verify internal correctness and consistency more effectively, and to better address longstanding challenges in research software. Moreover, their continued and frequent practice with these tools compounds their advantages, allowing them to better anticipate failure modes, enforce quality standards, and integrate tooling into complex, evolving research environments.&lt;/p&gt;
&lt;p&gt;RSEs who maintain GenAI literacy and the ability to critically evaluate complex software stacks are especially indispensable in view of the risks associated with the increasing adoption of GenAI in research software development. In particular, when researchers use agentic coding tools without sufficient expertise and experience to write increasingly complex software, over-reliance on these tools risks generating a significant disconnect between the coder and the code. This disconnect can lead to the introduction of unintended errors and inaccuracies, and could pose serious risk to the robustness of related scientific outputs and research results. In this situation, RSEs are well positioned to provide the guidance and oversight that is necessary to ensure the safe adoption of AI in research software engineering.&lt;/p&gt;
&lt;p&gt;Taken together, the value of an RSE remains significant, as the RSE role evolves to integrate expert knowledge in the application of GenAI for software engineering in research contexts. This viewpoint is similarly articulated in the &lt;a href=&quot;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&quot;&gt;Position Statement on Generative AI in the RSE Workplace&lt;/a&gt;[19], which is led by US-RSE and the Alliance for Data Science and AI. The Edinburgh workshop built upon this position statement, and it is also being shared in other conversations[20], [21]. As such, the value of RSEs in relation to researchers and other stakeholders will remain unchanged as their role as a research software professional evolves to also integrate expert knowledge in the application of GenAI in research contexts. This blog post seeks to move one step further in clearly articulating that value in a way that is easy to understand.&lt;/p&gt;
&lt;p&gt;Overall, the value of the RSE role shifts upward as AI enhances it and amplifies its impact. While the practice may change and shift focus to higher levels of abstraction, including specification and verification, the value proposition remains the same**. This is depicted in Figure 2, which shows how the use of GenAI enables the value of RSEs to increase along both the software engineering and research activity axes. It is critical for the research community to understand and acknowledge this increased potential for research impact, and to ensure that going forward, RSE expertise is appropriately supported, funded and integrated into research ecosystems.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-e2e2857a.DtjkNNeC_1OdOGE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: AI can enable RSEs to increase their capacity for both research and software engineering, irrespective of specializations.Figure 3 highlights the unique position of RSEs in the research ecosystem. RSEs and other roles in the research sector (software engineers, researchers who code, and researchers) all evolve in response to leveraging GenAI tools, which affects all groups along the software engineering capacity axis to varying degrees. Researchers who have not previously done any programming can now generate their own code, but for all non-RSE roles these shifts largely reinforce strengths within their established areas of expertise. For RSEs, however, this evolution plays to their dual focus on both software engineering and research, so that the effective value of RSEs and their work is amplified, as GenAI enables them to provide (even) more and better software to support (even) more and better research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research Software Engineers in the Age of GenAI: Same Value, Changing Practice&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;589&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-6f0e3f69.Cs5ozV6X_ZRCakM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: How various roles are evolving in response to GenAI.&lt;strong&gt;Acknowledgements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MB and DSK were supported to undertake this work as part of Schmidt Sciences grant G-25–69965.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author biographies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/michelledbarker/&quot;&gt;Michelle Barker&lt;/a&gt; is Director of the Research Software Alliance and has extensive expertise in open science, the research software community, digital skills, and digital research infrastructure. As a sociologist, Michelle is passionate about building collaborative partnerships to achieve system change. She is a former Director of the Australian Research Data Commons, where she led the national research software infrastructure investment program.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cosden&quot;&gt;Ian Cosden&lt;/a&gt; is the Senior Director of Research Software Engineering at Princeton University. He leads a team of research software engineers who complement multiple traditional academic research groups by offering embedded, long-term software development expertise. He spearheaded the formation of the RSE group in 2016 and has grown the group from an initial size of two FTEs, to a total of 37 FTEs as of May 2026. Ian is the current and founding chair of the steering committee for the United States Research Software Engineer (US-RSE) Association. Additionally, he is the principal investigator for Innovative Training Enabled by a Research Software Engineering Community of Trainers (INTERSECT), an NSF-funded project to develop and deliver RSE-led training events for current researchers interested in careers in research software engineering.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sdruskat.net&quot;&gt;Stephan Druskat&lt;/a&gt; is a (Research) Software Engineering Researcher based in Berlin. His research focuses on requirements, constraints, policies and practices of software engineering in academic research contexts, such as software publication, citation and sustainability, as well as software metadata and software supply chains. He is a Fellow of the Software Sustainability Institute, co-founder of the Society for Research Software in Germany (de-RSE), and lead of the Citation File Format project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/hainesr&quot;&gt;Robert Haines&lt;/a&gt; is Director of Research IT and an Honorary Lecturer at the University of Manchester, and a Fellow of the Software Sustainability Institute. He is one of the originators of the term “Research Software Engineer”, served for six years as an elected representative of the UK RSE Association, chaired the First Conference of Research Software Engineers in 2016, and was a founding trustee of the Society of Research Software Engineering. Robert’s research interests include software engineering, software sustainability, software use in open and reproducible research, software citation and credit, and career paths for software engineers and data scientists.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt; is Chief Scientist at the National Center for Supercomputing Applications, Research Professor in the Siebel School of Computing and Data Science, and Research Professor in the School of Information Sciences at the University of Illinois Urbana-Champaign. He works at the triple point of research software, people, and policy. He is a co-founder and current Associate Editor-in-Chief of the Journal of Open Source Software, co-founder of the US Research Software Engineer Association (US-RSE), and co-founder and steering committee chair of the Research Software Alliance (ReSA).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jshng-glasgow&quot;&gt;Joseph Shingleton&lt;/a&gt; is a Research Software Engineer at the University of Glasgow. His research explores how artificial intelligence can be safely and effectively applied to tasks in geospatial data science and research software engineering. He is the recipient of a UKRI Metascience AI Fellowship, focusing on how generative AI is shaping RSE practice and its consequences for the scientific process. He is also a Software Sustainability Institute Fellow and leads the SSI study group on responsible AI in RSE.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/benvanwerkhoven&quot;&gt;Ben van Werkhoven&lt;/a&gt; is assistant professor at Leiden University, where he heads the Accelerated Computing research group, focusing on making high-performance computing more energy-efficient and sustainable. He holds a PhD from VU Amsterdam on GPU-accelerated scientific computing (2014) and spent nearly a decade at the Netherlands eScience Center before joining Leiden in 2023. With over 15 years of GPU programming and optimization experience, Ben has worked on scientific applications ranging from microscopy and climate modeling to radio astronomy. He is also a co-founder of the Netherlands Research Software Engineers community (NL-RSE), advocating for the recognition of research software engineering as a professional discipline. At Leiden, he teaches High Performance Computing and Multiprocessor Programming, and serves as principal investigator on several research projects. He participates in major European and national consortia, including CORTEX and ESiWACE, advancing large-scale computing infrastructure for science.&lt;/p&gt;
&lt;p&gt;References**&lt;/p&gt;
&lt;p&gt;[1] M. Hosseini, S. P. J. M. Horbach, K. L. Holmes, and T. Ross-Hellauer, ‘Open Science at the Generative AI Turn: An Exploratory Analysis of Challenges and Opportunities’, May 24, 2024, SocArXiv*. doi: 10.31235/osf.io/zns7g.&lt;/p&gt;
&lt;p&gt;[2] G. O’Brien, ‘Threats to scientific software from over-reliance on AI code assistants’, &lt;em&gt;Nat Comput Sci&lt;/em&gt;, vol. 5, no. 9, pp. 701–703, Jul. 2025, doi: 10.1038/s43588–025–00845–2.&lt;/p&gt;
&lt;p&gt;[3] S. Andleeb, B. Kantorski, and J. C. Carver, ‘ChatGPT in Introductory Programming: Counterbalanced Evaluation of Code Quality, Conceptual Learning, and Student Perceptions’, 2025, &lt;em&gt;arXiv&lt;/em&gt;. doi: 10.48550/ARXIV.2510.00946.&lt;/p&gt;
&lt;p&gt;[4] G. O’Brien, A. Parker, N. Eisty, and J. Carver, ‘A survey of generative AI adoption and perceived productivity among scientists who program’, Apr. 09, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2512.19644. doi: 10.48550/arXiv.2512.19644.&lt;/p&gt;
&lt;p&gt;[5] SAPEA, ‘Successful and timely uptake of artificial intelligence in science in the EU: evidence review report’, SAPEA, Apr. 2024. doi: 10.5281/ZENODO.10977676.&lt;/p&gt;
&lt;p&gt;[6] M.-A. Storey, ‘From Technical Debt to Cognitive and Intent Debt: Rethinking Software Health in the Age of AI’, Apr. 06, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2603.22106. doi: 10.48550/arXiv.2603.22106.&lt;/p&gt;
&lt;p&gt;[7] R. Choudhuri, D. Liu, I. Steinmacher, M. Gerosa, and A. Sarma, ‘How Far Are We? The Triumphs and Trials of Generative AI in Learning Software Engineering’, in &lt;em&gt;Proceedings of the IEEE/ACM 46th International Conference on Software Engineering&lt;/em&gt;, Lisbon Portugal: ACM, Apr. 2024, pp. 1–13. doi: 10.1145/3597503.3639201.&lt;/p&gt;
&lt;p&gt;[8] M. Koren, G. Békés, J. Hinz, and A. Lohmann, ‘Vibe Coding Kills Open Source’, Jan. 21, 2026, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2601.15494. doi: 10.48550/arXiv.2601.15494.&lt;/p&gt;
&lt;p&gt;[9] S. A. Besser, E. A. Jensen, and D. S. Katz, ‘How generative AI is shaping research software development and maintenance at a research-intensive university’, &lt;em&gt;Open Res Europe&lt;/em&gt;, vol. 6, p. 56, Feb. 2026, doi: 10.12688/openreseurope.22009.1.&lt;/p&gt;
&lt;p&gt;[10] D. R. Newman-Griffis, ‘AI thinking and the enterprise of science’, Jun. 25, 2023, &lt;em&gt;Open Science Framework&lt;/em&gt;. doi: 10.31219/osf.io/wb83e.&lt;/p&gt;
&lt;p&gt;[11] D. Salah, ‘Invisible Risks, Visible Code: A Vision for Understanding Ethical Debt in AI-Based Coding’, in &lt;em&gt;2025 ACM/IEEE International Symposium on Empirical Software Engineering and Measurement (ESEM)&lt;/em&gt;, Honolulu, HI, USA: IEEE, Oct. 2025, pp. 442–446. doi: 10.1109/ESEM64174.2025.00074.&lt;/p&gt;
&lt;p&gt;[12] E. W. Bridgeford &lt;em&gt;et al.&lt;/em&gt;, ‘Ten Simple Rules for AI-Assisted Coding in Science’, Oct. 31, 2025, &lt;em&gt;arXiv&lt;/em&gt;: arXiv:2510.22254. doi: 10.48550/arXiv.2510.22254.&lt;/p&gt;
&lt;p&gt;[13] L. C. McInnes &lt;em&gt;et al.&lt;/em&gt;, ‘Report of the 2025 Workshop on Next-Generation Ecosystems for Scientific Computing: Harnessing Community, Software, and AI for Cross-Disciplinary Team Science’, 2025, &lt;em&gt;arXiv&lt;/em&gt;. doi: 10.48550/ARXIV.2510.03413.&lt;/p&gt;
&lt;p&gt;[14] L. Nordling, ‘How ChatGPT is transforming the postdoc experience’, &lt;em&gt;Nature&lt;/em&gt;, vol. 622, no. 7983, pp. 655–657, Oct. 2023, doi: 10.1038/d41586–023–03235–8.&lt;/p&gt;
&lt;p&gt;[15] G. O’Brien, ‘How Scientists Use Large Language Models to Program’, in &lt;em&gt;Proceedings of the 2025 CHI Conference on Human Factors in Computing Systems&lt;/em&gt;, Yokohama Japan: ACM, Apr. 2025, pp. 1–16. doi: 10.1145/3706598.3713668.&lt;/p&gt;
&lt;p&gt;[16] M. Barker &lt;em&gt;et al.&lt;/em&gt;, ‘Software and skills for research computing in the UK’, Zenodo, Jan. 2024. doi: 10.5281/ZENODO.10473186.&lt;/p&gt;
&lt;p&gt;[17] D. Kempf &lt;em&gt;et al.&lt;/em&gt;, ‘Establishing central Research Software Engineering units in German research institutions’, 2025, [Online]. Available: &lt;a href=&quot;https://de-rse.org/2023_paper-RSE-groups/paper.pdf&quot;&gt;https://de-rse.org/2023_paper-RSE-groups/paper.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[18] LCRDM, ‘Professionalizing the role of Research Software Engineers in the Netherlands’, Zenodo, Mar. 2025. doi: 10.5281/ZENODO.15019998.&lt;/p&gt;
&lt;p&gt;[19] ADSA and US-RSE, ‘Position Statement on Generative AI in the RSE Workplace’. Accessed: Apr. 28, 2026. [Online]. Available: &lt;a href=&quot;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&quot;&gt;https://github.com/Academic-Data-Science-Alliance/rse-ai-position-statement/blob/main/RSE-AI-Final_Statement.md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[20] S. Gesing, ‘RSEs 2035: Surviving or Thriving in the Age of AI’, in &lt;em&gt;2025 IEEE International Conference on eScience (eScience)&lt;/em&gt;, Chicago, IL, USA: IEEE, Sep. 2025, pp. 381–382. doi: 10.1109/eScience65000.2025.00081.&lt;/p&gt;
&lt;p&gt;[21] P. Leather, D. Silver, and S. Frezza, ‘Software engineering role archetypes’, presented at the IEEE SWEBOK Summit 2026, Apr. 2026. [Online]. Available: &lt;a href=&quot;https://conf.researchr.org/details/icse-2026/swebok-2026/5/Talk-Software-engineering-role-archetypes-mapping-knowledge-skills-and-competenci&quot;&gt;https://conf.researchr.org/details/icse-2026/swebok-2026/5/Talk-Software-engineering-role-archetypes-mapping-knowledge-skills-and-competenci&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/research-software-engineers-in-the-age-o-4c402b8d.DHWN-me0.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing</title><link>https://blog.esciencecenter.nl/posts/2026-05-15---co-designing-a-roadmap-for-training-on-research-software-tem</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-05-15---co-designing-a-roadmap-for-training-on-research-software-tem</guid><description>&lt;p&gt;Training materials are most effective when they are created hand-in-hand with the communities who will actually use them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-789c85ed.Ci1stTDr_ZSnt3j.webp&quot; srcset=&quot;&quot;&gt;
Photo of the eventBy &lt;a href=&quot;https://www.tudelft.nl/en/staff/m.g.garciaalvarez/&quot;&gt;Manuel G. Garcia&lt;/a&gt; and &lt;a href=&quot;https://people.utwente.nl/s.girgin&quot;&gt;Serkan Gigin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Training materials are most effective when they are created with the communities who will actually use them. Co-design brings together lived experience, local knowledge, and technical expertise, ensuring that learning resources are relevant, accessible, and grounded in real needs. During the Research Software Training Day 2026, we engaged with research software trainers from across the Netherlands to explore how training materials for &lt;a href=&quot;https://ss-nes.github.io/meta-template/&quot;&gt;Meta-Template&lt;/a&gt; and &lt;a href=&quot;https://github.com/SS-NES/code-auditor&quot;&gt;Code Auditor&lt;/a&gt; should be developed and delivered.&lt;/p&gt;
&lt;p&gt;This the story of our experience and the lessons we learned along the way:&lt;/p&gt;
&lt;p&gt;Meta-Template** is a tool for aligning software best practices across teams, groups, and organisations through software templates. These templates provide structure and boilerplate code for software projects, offering several key advantages for research software development: they reduce the time and barriers involved in setting up a new project, encourage the adoption of best practices such as the FAIR principles for software, and promote standardisation and consistency across projects within a research team, group, or organisation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-11fafa6b.TwqUPDLO_Z2uxTPU.webp&quot; srcset=&quot;&quot;&gt;
&lt;strong&gt;Code Auditor&lt;/strong&gt; is a conformity checking tool that provides insights into the structure and content of a research software project. When applied to a code base, such as a code repository, Code Auditor can identify missing or conflicting best practices, suggest solutions to the issues it detects, and generate conformity reports in both machine- and human-friendly formats. It can also be used to verify compliance with software management plans and, when integrated with software templating tools, enables automated corrections.&lt;/p&gt;
&lt;p&gt;These two tools complement each other. Meta-Template facilitates the adoption of software best practices from the very inception of a research software project, while Code Auditor helps monitor compliance with those practices at key points throughout the software lifecycle.&lt;/p&gt;
&lt;p&gt;To promote the adoption of these tools, we need training materials, such as tutorials, that introduce them to potential users, demonstrate their value, and attract collaborators to the open-source projects that maintain them. With this goal in mind, we consulted the Research Software Training community about which directions and approaches to follow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact Sheet&lt;/strong&gt;** Participants: 16
Experience as trainners: beginners (1 year) to proficient (&gt; 5 years)
Location: Utrecht
Duration: 1.5 hours&lt;/p&gt;
&lt;h2 id=&quot;directions-for-training-tutorials&quot;&gt;Directions for Training Tutorials&lt;/h2&gt;
&lt;p&gt;Training tutorials can be developed in several directions. During our engagement with software trainers, we focused on understanding their preferences and opinions regarding two key questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How independent should training materials be from other training materials and initiatives?** Independent materials might be easier to develop and maintain, but risk being too niche to reach a broad pool of potential users. On the other hand, integrating materials with existing training programmes could provide good leverage to reach a wider audience, though it requires more coordination and effort.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Should training materials focus on the tools themselves, or on the research software development topics they relate to?&lt;/strong&gt; Tool-focused materials would have a narrower scope but highlight the capabilities of the tools in detail, while topic-focused materials would cover broader software topics, such as publishing research software, and introduce the tools as mechanisms to ease the workload.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;independence-vs-integration&quot;&gt;Independence vs Integration&lt;/h2&gt;
&lt;p&gt;Most trainers agreed that training materials for &lt;strong&gt;Meta-Template&lt;/strong&gt; and &lt;strong&gt;Code Auditor&lt;/strong&gt; should be developed as part of existing training programmes, taking advantage of established initiatives and institutional structures. However, some arguments in favour of &lt;em&gt;independent&lt;/em&gt; training highlighted that standalone materials could be shorter and use-case oriented, requiring less time investment from potential users. A few others acknowledged these arguments but felt that choosing a single direction might not be necessary, since both approaches offer advantages and drawbacks.&lt;/p&gt;
&lt;p&gt;Despite the differences in opinion, the discussion concluded with trainers agreeing that a good starting point would be to explore integrating materials into existing and related training initiatives.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;381&quot; height=&quot;690&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-a675afcf.D6VzIWth_1DSoT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;tool-focus-vs-topic-focus&quot;&gt;Tool Focus vs Topic Focus&lt;/h2&gt;
&lt;p&gt;A large majority of trainers agreed that training materials should be topic-focused. The strongest argument in favour was that topic-focused materials would emphasise the value of the tools within a particular use case or research domain, demonstrating how useful they can be in a specific context and therefore serving as a better strategy to attract users. The argument for tool-focused materials, on the other hand, emphasised that such materials could be shorter and concentrate on demonstrating the how-to of each tool. Those who favoured neither direction raised arguments similar to those in the discussion about independence vs integration.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;381&quot; height=&quot;690&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-b6184d88.CyNJMPeB_Z1quADR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;audiences-formats-and-collaborations&quot;&gt;Audiences, Formats, and Collaborations&lt;/h2&gt;
&lt;p&gt;In the final part of the workshop, trainers proposed ideas on three topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which audiences should the training materials target?&lt;/li&gt;
&lt;li&gt;Which formats would be most suitable?&lt;/li&gt;
&lt;li&gt;How can we attract collaborators to help develop materials?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most favoured ideas pointed towards targeting PhD candidates, MSc students, data support staff, and data repository managers, through on-site training sessions such as workshops. However, a wide range of ideas were proposed for each aspect — see Table 1.&lt;/p&gt;
&lt;p&gt;Regarding collaboration, the preferred approach was to organise on-site events, such as content-a-thons, where trainers work together on developing materials.&lt;/p&gt;
&lt;p&gt;Table 1. Ideas for addressing topics related to audiences, formats and collaborations for developing training materials for &lt;em&gt;&lt;a href=&quot;https://ss-nes.github.io/meta-template/&quot;&gt;&lt;em&gt;Meta-Template&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://github.com/SS-NES/code-auditor&quot;&gt;&lt;em&gt;Code Auditor&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1114&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-487b1948.BsSiTcH3_uDqG9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;p&gt;The main takeaways from the workshop were as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work towards integrating training materials for the tools into existing initiatives, such as data and software training programmes, to leverage the opportunities they offer for reaching a wider audience.&lt;/li&gt;
&lt;li&gt;Topic-focused materials offer a strategic advantage in demonstrating the value of new tools such as Meta-Template and Code Auditor, which in turn helps attract new users.&lt;/li&gt;
&lt;li&gt;Prioritise PhD candidates, MSc students, and data/software support staff as target audiences, delivering training through on-site formats such as hands-on workshops.&lt;/li&gt;
&lt;li&gt;Trainers prefer collective efforts during on-site events, such as content-a-thons, for contributing to the development of training materials.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contact&quot;&gt;Contact&lt;/h2&gt;
&lt;p&gt;If you would like to learn more about Meta-Template** and &lt;strong&gt;Code Auditor&lt;/strong&gt;, or explore how to use them in your own training activities, we would love to hear from you. We also warmly invite contributions from the community — whether by improving the existing materials, sharing feedback, or helping co-develop new training resources together.&lt;/p&gt;
&lt;p&gt;Dr. Manuel Garcia Alvarez
Research Software Engineer
TU Delft DCC
&lt;a href=&quot;mailto:m.g.garciaalvarez@tudelft.nl&quot;&gt;m.g.garciaalvarez@tudelft.nl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dr. Serkan Girgin
Associate Professor
University of Twente, Faculty ITC
&lt;a href=&quot;mailto:s.girgin@utwente.nl&quot;&gt;s.girgin@utwente.nl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The project “Best Practices for Sustainable Software” with file number ICT.TDCC.002.001 of the research programme NWO Implementation Plan for ICT Infrastructure for TDCC Bottleneck Projects is financed by the Dutch Research Council (NWO).&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 15 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Training materials are most effective when they are created hand-in-hand with the communities who will actually use them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-789c85ed.Ci1stTDr_ZSnt3j.webp&quot; srcset=&quot;&quot;&gt;
Photo of the eventBy &lt;a href=&quot;https://www.tudelft.nl/en/staff/m.g.garciaalvarez/&quot;&gt;Manuel G. Garcia&lt;/a&gt; and &lt;a href=&quot;https://people.utwente.nl/s.girgin&quot;&gt;Serkan Gigin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Training materials are most effective when they are created with the communities who will actually use them. Co-design brings together lived experience, local knowledge, and technical expertise, ensuring that learning resources are relevant, accessible, and grounded in real needs. During the Research Software Training Day 2026, we engaged with research software trainers from across the Netherlands to explore how training materials for &lt;a href=&quot;https://ss-nes.github.io/meta-template/&quot;&gt;Meta-Template&lt;/a&gt; and &lt;a href=&quot;https://github.com/SS-NES/code-auditor&quot;&gt;Code Auditor&lt;/a&gt; should be developed and delivered.&lt;/p&gt;
&lt;p&gt;This the story of our experience and the lessons we learned along the way:&lt;/p&gt;
&lt;p&gt;Meta-Template** is a tool for aligning software best practices across teams, groups, and organisations through software templates. These templates provide structure and boilerplate code for software projects, offering several key advantages for research software development: they reduce the time and barriers involved in setting up a new project, encourage the adoption of best practices such as the FAIR principles for software, and promote standardisation and consistency across projects within a research team, group, or organisation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-11fafa6b.TwqUPDLO_Z2uxTPU.webp&quot; srcset=&quot;&quot;&gt;
&lt;strong&gt;Code Auditor&lt;/strong&gt; is a conformity checking tool that provides insights into the structure and content of a research software project. When applied to a code base, such as a code repository, Code Auditor can identify missing or conflicting best practices, suggest solutions to the issues it detects, and generate conformity reports in both machine- and human-friendly formats. It can also be used to verify compliance with software management plans and, when integrated with software templating tools, enables automated corrections.&lt;/p&gt;
&lt;p&gt;These two tools complement each other. Meta-Template facilitates the adoption of software best practices from the very inception of a research software project, while Code Auditor helps monitor compliance with those practices at key points throughout the software lifecycle.&lt;/p&gt;
&lt;p&gt;To promote the adoption of these tools, we need training materials, such as tutorials, that introduce them to potential users, demonstrate their value, and attract collaborators to the open-source projects that maintain them. With this goal in mind, we consulted the Research Software Training community about which directions and approaches to follow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact Sheet&lt;/strong&gt;** Participants: 16
Experience as trainners: beginners (1 year) to proficient (&gt; 5 years)
Location: Utrecht
Duration: 1.5 hours&lt;/p&gt;
&lt;h2 id=&quot;directions-for-training-tutorials&quot;&gt;Directions for Training Tutorials&lt;/h2&gt;
&lt;p&gt;Training tutorials can be developed in several directions. During our engagement with software trainers, we focused on understanding their preferences and opinions regarding two key questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How independent should training materials be from other training materials and initiatives?** Independent materials might be easier to develop and maintain, but risk being too niche to reach a broad pool of potential users. On the other hand, integrating materials with existing training programmes could provide good leverage to reach a wider audience, though it requires more coordination and effort.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Should training materials focus on the tools themselves, or on the research software development topics they relate to?&lt;/strong&gt; Tool-focused materials would have a narrower scope but highlight the capabilities of the tools in detail, while topic-focused materials would cover broader software topics, such as publishing research software, and introduce the tools as mechanisms to ease the workload.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;independence-vs-integration&quot;&gt;Independence vs Integration&lt;/h2&gt;
&lt;p&gt;Most trainers agreed that training materials for &lt;strong&gt;Meta-Template&lt;/strong&gt; and &lt;strong&gt;Code Auditor&lt;/strong&gt; should be developed as part of existing training programmes, taking advantage of established initiatives and institutional structures. However, some arguments in favour of &lt;em&gt;independent&lt;/em&gt; training highlighted that standalone materials could be shorter and use-case oriented, requiring less time investment from potential users. A few others acknowledged these arguments but felt that choosing a single direction might not be necessary, since both approaches offer advantages and drawbacks.&lt;/p&gt;
&lt;p&gt;Despite the differences in opinion, the discussion concluded with trainers agreeing that a good starting point would be to explore integrating materials into existing and related training initiatives.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;381&quot; height=&quot;690&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-a675afcf.D6VzIWth_1DSoT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;tool-focus-vs-topic-focus&quot;&gt;Tool Focus vs Topic Focus&lt;/h2&gt;
&lt;p&gt;A large majority of trainers agreed that training materials should be topic-focused. The strongest argument in favour was that topic-focused materials would emphasise the value of the tools within a particular use case or research domain, demonstrating how useful they can be in a specific context and therefore serving as a better strategy to attract users. The argument for tool-focused materials, on the other hand, emphasised that such materials could be shorter and concentrate on demonstrating the how-to of each tool. Those who favoured neither direction raised arguments similar to those in the discussion about independence vs integration.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;381&quot; height=&quot;690&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-b6184d88.CyNJMPeB_Z1quADR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;audiences-formats-and-collaborations&quot;&gt;Audiences, Formats, and Collaborations&lt;/h2&gt;
&lt;p&gt;In the final part of the workshop, trainers proposed ideas on three topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which audiences should the training materials target?&lt;/li&gt;
&lt;li&gt;Which formats would be most suitable?&lt;/li&gt;
&lt;li&gt;How can we attract collaborators to help develop materials?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most favoured ideas pointed towards targeting PhD candidates, MSc students, data support staff, and data repository managers, through on-site training sessions such as workshops. However, a wide range of ideas were proposed for each aspect — see Table 1.&lt;/p&gt;
&lt;p&gt;Regarding collaboration, the preferred approach was to organise on-site events, such as content-a-thons, where trainers work together on developing materials.&lt;/p&gt;
&lt;p&gt;Table 1. Ideas for addressing topics related to audiences, formats and collaborations for developing training materials for &lt;em&gt;&lt;a href=&quot;https://ss-nes.github.io/meta-template/&quot;&gt;&lt;em&gt;Meta-Template&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://github.com/SS-NES/code-auditor&quot;&gt;&lt;em&gt;Code Auditor&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Co-Designing a Roadmap for Training on Research Software Templates and Code Auditing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1114&quot; src=&quot;https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-487b1948.BsSiTcH3_uDqG9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;p&gt;The main takeaways from the workshop were as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work towards integrating training materials for the tools into existing initiatives, such as data and software training programmes, to leverage the opportunities they offer for reaching a wider audience.&lt;/li&gt;
&lt;li&gt;Topic-focused materials offer a strategic advantage in demonstrating the value of new tools such as Meta-Template and Code Auditor, which in turn helps attract new users.&lt;/li&gt;
&lt;li&gt;Prioritise PhD candidates, MSc students, and data/software support staff as target audiences, delivering training through on-site formats such as hands-on workshops.&lt;/li&gt;
&lt;li&gt;Trainers prefer collective efforts during on-site events, such as content-a-thons, for contributing to the development of training materials.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contact&quot;&gt;Contact&lt;/h2&gt;
&lt;p&gt;If you would like to learn more about Meta-Template** and &lt;strong&gt;Code Auditor&lt;/strong&gt;, or explore how to use them in your own training activities, we would love to hear from you. We also warmly invite contributions from the community — whether by improving the existing materials, sharing feedback, or helping co-develop new training resources together.&lt;/p&gt;
&lt;p&gt;Dr. Manuel Garcia Alvarez
Research Software Engineer
TU Delft DCC
&lt;a href=&quot;mailto:m.g.garciaalvarez@tudelft.nl&quot;&gt;m.g.garciaalvarez@tudelft.nl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dr. Serkan Girgin
Associate Professor
University of Twente, Faculty ITC
&lt;a href=&quot;mailto:s.girgin@utwente.nl&quot;&gt;s.girgin@utwente.nl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The project “Best Practices for Sustainable Software” with file number ICT.TDCC.002.001 of the research programme NWO Implementation Plan for ICT Infrastructure for TDCC Bottleneck Projects is financed by the Dutch Research Council (NWO).&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/co-designing-a-roadmap-for-training-on-r-11fafa6b.TwqUPDLO.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Provenance in the age of AI: Why we need AI Declarations for more transparency</title><link>https://blog.esciencecenter.nl/posts/2026-04-23---provenance-in-the-age-of-ai-why-we-need-ai-declarations-for-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-04-23---provenance-in-the-age-of-ai-why-we-need-ai-declarations-for-</guid><description>&lt;p&gt;&lt;em&gt;In research, if our methodology is not transparent, our results are not verifiable. Using AI to help generate code or synthesize data is dramatically affecting transparency, sustainability and maintenance. But how can we make the AI involvement more transparent and traceable?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Provenance in the age of AI: Why we need AI Declarations for more transparency&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;382&quot; src=&quot;https://blog.esciencecenter.nl/_astro/provenance-in-the-age-of-ai-why-we-need--4b349da1.BX8llyxo_Z1yry4i.webp&quot; srcset=&quot;&quot;&gt;
This image was generated using Google Gemini 3.1. See the declaration file at the end of this blog post for more details.Before I started as a Research Software Engineer, I worked in a physical lab where the culture of provenance was absolute. You documented everything: the materials, the hardware, the exact version of the software you used to process the data, and so forth. Without that trail, the results were meaningless. You could not trust them, and you certainly could not reproduce them.&lt;/p&gt;
&lt;p&gt;Today, my “lab” is entirely digital, but the need for that same precision remains.&lt;/p&gt;
&lt;p&gt;Over the last two years, a new variable has entered our work. We are using Generative AI to suggest code refactors, autonomous agents to synthesize datasets, and generative models to draft technical reports. AI is no longer a separate tool we are experimenting with; it is already becoming a standard part of our daily routine.&lt;/p&gt;
&lt;p&gt;Today, when I download a dataset or review a colleague’s pull request, I have no way to know where the human logic ends and the model’s output begins. This ambiguity is a problem for scientific reliability. If we cannot trace the logic of an algorithm or the origin of a dataset, we lose reproducibility. If we cannot identify which parts of a codebase were generated by a model, we are building up a “maintenance debt” that will eventually come due. And if we ignore the compute cost of these models, we are ignoring the sustainability of our field.&lt;/p&gt;
&lt;p&gt;We built the &lt;a href=&quot;https://ai-declaration.org/&quot;&gt;AI Declaration Format**&lt;/a&gt;** (&lt;strong&gt;&lt;a href=&quot;https://ai-declaration.org/&quot;&gt;https://ai-declaration.org&lt;/a&gt;&lt;/strong&gt;)** to address this. Our goal is to make structured documentation of AI usage a standard, routine part of professional work.&lt;/p&gt;
&lt;h2 id=&quot;the-foundation-a-machine-readable-file-format&quot;&gt;The foundation: A machine-readable file format&lt;/h2&gt;
&lt;p&gt;The AI Declaration Format is the foundation: a machine-readable, general-purpose file format designed to describe AI involvement in any digital artifact. It does not matter if you are publishing software, a research paper, a dataset, or media; you can use the same structured approach to say how AI was involved.&lt;/p&gt;
&lt;p&gt;We designed the schema to be modular, so you can focus on the parts that matter for your project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintainability and Security:&lt;/strong&gt; You can track which modules were AI-assisted and document security reviews. Knowing which blocks of code were generated helps future maintainers understand the intent behind them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environmental Impact:&lt;/strong&gt; You can record compute hours and estimated carbon footprints. This turns “sustainability” into a measurable metric.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explainability and Governance:&lt;/strong&gt; For systems that interact with users, you can document technical decision logic or interpretability methods. You can also name responsible officers and link to internal ethics reviews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regulations (not just the EU Act):&lt;/strong&gt; With the EU AI Act, the US Executive Order, and other global frameworks, transparency is becoming a legal requirement. The AI Declaration Format lets you map your project to risk categories and link to the technical documentation these laws demand.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-another-format&quot;&gt;Why another format?&lt;/h2&gt;
&lt;p&gt;A common question is why we need a new format when standards like &lt;a href=&quot;https://spdx.github.io/spdx-spec/v3.0.1/model/AI/AI/&quot;&gt;SPDX 3.0 (AI Profile)&lt;/a&gt; and &lt;a href=&quot;https://cyclonedx.org/capabilities/mlbom&quot;&gt;CycloneDX (ML-BOM)&lt;/a&gt; already exist. The answer lies in the scope and the audience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SPDX and CycloneDX are “Bill of Materials” (SBoM) standards. They are designed for legal teams and security auditors to track every sub-component and vulnerability in a supply chain. They are powerful but often complex for an individual researcher or a small dev team.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codemeta.github.io/&quot;&gt;CodeMeta&lt;/a&gt; and &lt;a href=&quot;https://citation-file-format.github.io/&quot;&gt;CITATION.cff&lt;/a&gt; are useful for general project metadata and academic citations. However, they lack the specialized fields needed for AI transparency — such as risk classification, model versions, and human oversight.&lt;/li&gt;
&lt;li&gt;The AI Declaration Format is a declaration format, not a full inventory. It is designed to be human-writable and project-focused. It answers the specific question of &lt;em&gt;“How did the humans on this project use AI?”.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The AI Declaration Format sits alongside these standards: it is the missing piece of the metadata puzzle that captures the usage and methodology of Generative AI.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-get-started&quot;&gt;How do I get started?&lt;/h2&gt;
&lt;p&gt;A standard is only useful if it is easy to adopt. We have built an ecosystem of tools and automation around the AI Declaration Format to ensure it fits into your existing workflow. We are also working on improving and extending this tooling, including GitHub/GitLab Actions and workflows to automate validation and updating as part of your CI/CD pipelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://app.ai-declaration.org&quot;&gt;The Web App**&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; If you want a guided interface, we built a web app specifically to create these declaration files. It runs entirely in your browser, so your project data never hits our servers. You can generate an &lt;code&gt;aidecl.yaml&lt;/code&gt;, validate it, or look at examples from other fields.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ai-declaration/cli&quot;&gt;&lt;strong&gt;The CLI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; For those of us who live in the terminal, the &lt;code&gt;aidecl&lt;/code&gt; tool lets you initialize and validate declarations as part of your git workflow. It runs semantic checks to make sure your claims actually make sense—like flagging if you claim no AI was used but then list three models in your inventory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;scientific-and-technical-standards&quot;&gt;Scientific and Technical Standards&lt;/h2&gt;
&lt;p&gt;In research, we document our hardware and our data sources because that is how we maintain the standard of our work. This is the bedrock of Open Science: if our methodology is not transparent, our results are not verifiable. Using AI to help generate code or synthesize data is simply another part of that methodology. It belongs in the formal record.&lt;/p&gt;
&lt;p&gt;Adding an &lt;code&gt;aidecl.yaml&lt;/code&gt; to your repository shows a commitment to open science principles. It is a way to make sure that the things we are building today will be MORE understandable, maintainable, and reproducible in future.&lt;/p&gt;
&lt;h2 id=&quot;join-the-effort&quot;&gt;Join the effort&lt;/h2&gt;
&lt;p&gt;We are in the early stages of this, and we need a community to make it a standard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adopt:&lt;/strong&gt; Add an &lt;code&gt;aidecl.yaml&lt;/code&gt; to your next project. It takes about five minutes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Endorse:&lt;/strong&gt; If your lab or organization values AI transparency, we need early adopters to help build credibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribute:&lt;/strong&gt; The schema and tools are open-source. Help us improve the validation rules or the web interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback:&lt;/strong&gt; We need to know how this works (or does not) for your specific field — whether that is genomics, legal tech, or creative media.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are all figuring this out as we go. As the technology changes and we get more feedback, the file format and the tools will evolve to keep up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project page:&lt;/strong&gt; &lt;a href=&quot;https://ai-declaration.org&quot;&gt;ai-declaration.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub organization:&lt;/strong&gt; &lt;a href=&quot;https://github.com/ai-declaration&quot;&gt;github.com/ai-declaration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ai-declaration-aideclyaml-for-this-post&quot;&gt;AI Declaration (aidecl.yaml) for this post&lt;/h2&gt;
&lt;p&gt;schema_version: “1.0.0”
project:
name: “Provenance in the age of LLMs: Why we need AI Declarations”
version: “1.0.0”
content_type: “document”
license: “CC BY 4.0”
ai_usage:
used: true
summary: “Structured and refined by Gemini (LLM) based on human-provided themes, constraints, and source documentation.”
level: “moderate”
activities:
- content_drafting
- content_editing
tools:
- name: “Gemini”
vendor: “Google”
type: “assistant”
model: “gemini-3.1”
purpose:
- content_refining
- structural_organization
- image_generation
ai_proportion:
qualitative: mostly_human
method: self_reported
governance:
responsible_officer: “Faruk Diblen”
ethics_review_status: “not_applicable”
environmental:
compute_hours: 0.05
estimation_method: self_estimated
security:
review_performed: true
review_type:
- human_in_the_loop
declaration:
date: “2026-04-07”
declared_by: “Faruk Diblen”
organization: “Resoft Labs”&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to [Flavio Hafner], [Carlos Martinez-Ortiz] and [Elena Ranguelova] for their feedback on the text and [Pablo Rodríguez-Sánchez] and [Alexander Hadjiivanov] for their editorial support.&lt;/p&gt;</description><pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;In research, if our methodology is not transparent, our results are not verifiable. Using AI to help generate code or synthesize data is dramatically affecting transparency, sustainability and maintenance. But how can we make the AI involvement more transparent and traceable?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Provenance in the age of AI: Why we need AI Declarations for more transparency&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;382&quot; src=&quot;https://blog.esciencecenter.nl/_astro/provenance-in-the-age-of-ai-why-we-need--4b349da1.BX8llyxo_Z1yry4i.webp&quot; srcset=&quot;&quot;&gt;
This image was generated using Google Gemini 3.1. See the declaration file at the end of this blog post for more details.Before I started as a Research Software Engineer, I worked in a physical lab where the culture of provenance was absolute. You documented everything: the materials, the hardware, the exact version of the software you used to process the data, and so forth. Without that trail, the results were meaningless. You could not trust them, and you certainly could not reproduce them.&lt;/p&gt;
&lt;p&gt;Today, my “lab” is entirely digital, but the need for that same precision remains.&lt;/p&gt;
&lt;p&gt;Over the last two years, a new variable has entered our work. We are using Generative AI to suggest code refactors, autonomous agents to synthesize datasets, and generative models to draft technical reports. AI is no longer a separate tool we are experimenting with; it is already becoming a standard part of our daily routine.&lt;/p&gt;
&lt;p&gt;Today, when I download a dataset or review a colleague’s pull request, I have no way to know where the human logic ends and the model’s output begins. This ambiguity is a problem for scientific reliability. If we cannot trace the logic of an algorithm or the origin of a dataset, we lose reproducibility. If we cannot identify which parts of a codebase were generated by a model, we are building up a “maintenance debt” that will eventually come due. And if we ignore the compute cost of these models, we are ignoring the sustainability of our field.&lt;/p&gt;
&lt;p&gt;We built the &lt;a href=&quot;https://ai-declaration.org/&quot;&gt;AI Declaration Format**&lt;/a&gt;** (&lt;strong&gt;&lt;a href=&quot;https://ai-declaration.org/&quot;&gt;https://ai-declaration.org&lt;/a&gt;&lt;/strong&gt;)** to address this. Our goal is to make structured documentation of AI usage a standard, routine part of professional work.&lt;/p&gt;
&lt;h2 id=&quot;the-foundation-a-machine-readable-file-format&quot;&gt;The foundation: A machine-readable file format&lt;/h2&gt;
&lt;p&gt;The AI Declaration Format is the foundation: a machine-readable, general-purpose file format designed to describe AI involvement in any digital artifact. It does not matter if you are publishing software, a research paper, a dataset, or media; you can use the same structured approach to say how AI was involved.&lt;/p&gt;
&lt;p&gt;We designed the schema to be modular, so you can focus on the parts that matter for your project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintainability and Security:&lt;/strong&gt; You can track which modules were AI-assisted and document security reviews. Knowing which blocks of code were generated helps future maintainers understand the intent behind them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environmental Impact:&lt;/strong&gt; You can record compute hours and estimated carbon footprints. This turns “sustainability” into a measurable metric.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explainability and Governance:&lt;/strong&gt; For systems that interact with users, you can document technical decision logic or interpretability methods. You can also name responsible officers and link to internal ethics reviews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regulations (not just the EU Act):&lt;/strong&gt; With the EU AI Act, the US Executive Order, and other global frameworks, transparency is becoming a legal requirement. The AI Declaration Format lets you map your project to risk categories and link to the technical documentation these laws demand.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-another-format&quot;&gt;Why another format?&lt;/h2&gt;
&lt;p&gt;A common question is why we need a new format when standards like &lt;a href=&quot;https://spdx.github.io/spdx-spec/v3.0.1/model/AI/AI/&quot;&gt;SPDX 3.0 (AI Profile)&lt;/a&gt; and &lt;a href=&quot;https://cyclonedx.org/capabilities/mlbom&quot;&gt;CycloneDX (ML-BOM)&lt;/a&gt; already exist. The answer lies in the scope and the audience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SPDX and CycloneDX are “Bill of Materials” (SBoM) standards. They are designed for legal teams and security auditors to track every sub-component and vulnerability in a supply chain. They are powerful but often complex for an individual researcher or a small dev team.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codemeta.github.io/&quot;&gt;CodeMeta&lt;/a&gt; and &lt;a href=&quot;https://citation-file-format.github.io/&quot;&gt;CITATION.cff&lt;/a&gt; are useful for general project metadata and academic citations. However, they lack the specialized fields needed for AI transparency — such as risk classification, model versions, and human oversight.&lt;/li&gt;
&lt;li&gt;The AI Declaration Format is a declaration format, not a full inventory. It is designed to be human-writable and project-focused. It answers the specific question of &lt;em&gt;“How did the humans on this project use AI?”.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The AI Declaration Format sits alongside these standards: it is the missing piece of the metadata puzzle that captures the usage and methodology of Generative AI.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-get-started&quot;&gt;How do I get started?&lt;/h2&gt;
&lt;p&gt;A standard is only useful if it is easy to adopt. We have built an ecosystem of tools and automation around the AI Declaration Format to ensure it fits into your existing workflow. We are also working on improving and extending this tooling, including GitHub/GitLab Actions and workflows to automate validation and updating as part of your CI/CD pipelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://app.ai-declaration.org&quot;&gt;The Web App**&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; If you want a guided interface, we built a web app specifically to create these declaration files. It runs entirely in your browser, so your project data never hits our servers. You can generate an &lt;code&gt;aidecl.yaml&lt;/code&gt;, validate it, or look at examples from other fields.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ai-declaration/cli&quot;&gt;&lt;strong&gt;The CLI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; For those of us who live in the terminal, the &lt;code&gt;aidecl&lt;/code&gt; tool lets you initialize and validate declarations as part of your git workflow. It runs semantic checks to make sure your claims actually make sense—like flagging if you claim no AI was used but then list three models in your inventory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;scientific-and-technical-standards&quot;&gt;Scientific and Technical Standards&lt;/h2&gt;
&lt;p&gt;In research, we document our hardware and our data sources because that is how we maintain the standard of our work. This is the bedrock of Open Science: if our methodology is not transparent, our results are not verifiable. Using AI to help generate code or synthesize data is simply another part of that methodology. It belongs in the formal record.&lt;/p&gt;
&lt;p&gt;Adding an &lt;code&gt;aidecl.yaml&lt;/code&gt; to your repository shows a commitment to open science principles. It is a way to make sure that the things we are building today will be MORE understandable, maintainable, and reproducible in future.&lt;/p&gt;
&lt;h2 id=&quot;join-the-effort&quot;&gt;Join the effort&lt;/h2&gt;
&lt;p&gt;We are in the early stages of this, and we need a community to make it a standard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adopt:&lt;/strong&gt; Add an &lt;code&gt;aidecl.yaml&lt;/code&gt; to your next project. It takes about five minutes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Endorse:&lt;/strong&gt; If your lab or organization values AI transparency, we need early adopters to help build credibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribute:&lt;/strong&gt; The schema and tools are open-source. Help us improve the validation rules or the web interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback:&lt;/strong&gt; We need to know how this works (or does not) for your specific field — whether that is genomics, legal tech, or creative media.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are all figuring this out as we go. As the technology changes and we get more feedback, the file format and the tools will evolve to keep up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project page:&lt;/strong&gt; &lt;a href=&quot;https://ai-declaration.org&quot;&gt;ai-declaration.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub organization:&lt;/strong&gt; &lt;a href=&quot;https://github.com/ai-declaration&quot;&gt;github.com/ai-declaration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ai-declaration-aideclyaml-for-this-post&quot;&gt;AI Declaration (aidecl.yaml) for this post&lt;/h2&gt;
&lt;p&gt;schema_version: “1.0.0”
project:
name: “Provenance in the age of LLMs: Why we need AI Declarations”
version: “1.0.0”
content_type: “document”
license: “CC BY 4.0”
ai_usage:
used: true
summary: “Structured and refined by Gemini (LLM) based on human-provided themes, constraints, and source documentation.”
level: “moderate”
activities:
- content_drafting
- content_editing
tools:
- name: “Gemini”
vendor: “Google”
type: “assistant”
model: “gemini-3.1”
purpose:
- content_refining
- structural_organization
- image_generation
ai_proportion:
qualitative: mostly_human
method: self_reported
governance:
responsible_officer: “Faruk Diblen”
ethics_review_status: “not_applicable”
environmental:
compute_hours: 0.05
estimation_method: self_estimated
security:
review_performed: true
review_type:
- human_in_the_loop
declaration:
date: “2026-04-07”
declared_by: “Faruk Diblen”
organization: “Resoft Labs”&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to [Flavio Hafner], [Carlos Martinez-Ortiz] and [Elena Ranguelova] for their feedback on the text and [Pablo Rodríguez-Sánchez] and [Alexander Hadjiivanov] for their editorial support.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/provenance-in-the-age-of-ai-why-we-need--4b349da1.BX8llyxo.png" medium="image"/><author>Faruk Diblen</author></item><item><title>FOSDEM 2026: Observations and key takeaways</title><link>https://blog.esciencecenter.nl/posts/2026-04-09---fosdem-2026-observations-and-key-takeaways</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-04-09---fosdem-2026-observations-and-key-takeaways</guid><description>&lt;p&gt;&lt;img alt=&quot;FOSDEM 2026: Observations and key takeaways&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/fosdem-2026-observations-and-key-takeawa-55dcce06.l9YVToEZ_ZsYfBF.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;If you missed FOSDEM 2026 — the largest conference dedicated to open-source software — you can still absorb some of the experience as shared by NLeSC RSEs &lt;strong&gt;Flavio Hafner&lt;/strong&gt;&lt;/em&gt;*, &lt;strong&gt;&lt;strong&gt;Ole Mussmann&lt;/strong&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;strong&gt;Faruk Diblen&lt;/strong&gt;&lt;/strong&gt;.*&lt;/p&gt;
&lt;h2 id=&quot;flavio-hafner-on-fosdem-2026-security-llms-and-software-performance&quot;&gt;Flavio Hafner on FOSDEM 2026: Security, LLMs, and Software Performance&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is a version of the &lt;em&gt;&lt;a href=&quot;https://f-hafner.github.io/fosdem-2026/&quot;&gt;&lt;em&gt;original post by Flavio&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; adapted for Medium.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My highlights from this year’s FOSDEM are in the areas of LLM/security/open source, in machine learning/software performance, and in databases/search.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-features-in-git&quot;&gt;Upcoming features in git&lt;/h2&gt;
&lt;p&gt;Patrick Steinhardt from GitLab, and git contributor, &lt;a href=&quot;https://fosdem.org/2026/schedule/event/HTJK33-evolving_git_for_the_next_decade/&quot;&gt;presented&lt;/a&gt; about some upcoming changes, planned for the major 3.0 release towards mid-2026.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Under the hood, git changes the hashing algorithm from SHA-1 to SHA-256&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is because SHA-1 is not secure — a paper from around 2017 showed that it does not create unique hashes.&lt;/li&gt;
&lt;li&gt;While git itself does not rely on uniqueness of hashes, the ecosystem implicitly does — for instance, by pinning software dependencies to git hashes.&lt;/li&gt;
&lt;li&gt;At the same time, large parts of the ecosystem (GitHub for instance) currently do not support SHA-256 hashes.&lt;/li&gt;
&lt;li&gt;By moving the default in git, the contributors want to solve the chicken-and-egg problem of “no-one wanting to use the feature because no-one supports it” and vice versa.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;New command: git history for easier rewriting of history&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In git, rewriting history through an interactive rebase is cumbersome and takes several steps.&lt;/li&gt;
&lt;li&gt;Another limitation is that it leads to orphaned branches because other branches depending on the changed commits are not updated. For instance, this makes is tedious to use workflows with stacked branches.&lt;/li&gt;
&lt;li&gt;The new &lt;code&gt;git history&lt;/code&gt; command, inspired by other version control systems such as Jujutsu and Mercurial, provides some functionality that makes such workflows easier. For instance, &lt;code&gt;git history reword &amp;#x26;lt;commit&amp;#x26;gt;&lt;/code&gt; allows to amend the commit message of a specific commit; &lt;code&gt;git history split &amp;#x26;lt;commit&amp;#x26;gt;&lt;/code&gt; allows to split a specific commit.&lt;/li&gt;
&lt;li&gt;The new commands &lt;em&gt;also&lt;/em&gt; rebase other branches that depend on respective commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;open-source-llms-and-security&quot;&gt;Open Source, LLMs, and security&lt;/h3&gt;
&lt;p&gt;This was a major topic in this year’s conference and featured in two keynotes: Michael Leenaars &lt;a href=&quot;https://fosdem.org/2026/schedule/event/FE7ULY-foss-in-times-of-war-scarcity-and-ai/&quot;&gt;(talk)&lt;/a&gt; from NLnet, and Daniel Stenberg, founder and lead developer of cURL &lt;a href=&quot;https://fosdem.org/2026/schedule/event/B7YKQ7-oss-in-spite-of-ai/&quot;&gt;(talk)&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Both speakers highlighted that LLMs can help malicious actors find and exploit vulnerabilities in open-source code, and thus open-source will become more vulnerable to supply-chain attacks.&lt;/li&gt;
&lt;li&gt;Stenberg further detailed how LLMs bring out the worst and best at the same time. On one hand, the cURL project is bombarded by AI-generated security reports. This has led cURL to stop their bug bounty program. On the other hand, they use LLMs selectively to find security issues and review code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Several talks in the security devroom addressed the same problem.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Updated governance model for open-weight LLMs&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href=&quot;https://fosdem.org/2026/schedule/event/VGMUYA-the-open-weight-dilemma/&quot;&gt;talk&lt;/a&gt; about LLMs and cyber risks argued for an updated governance model for open-source (and maybe open-weight) LLMs.&lt;/li&gt;
&lt;li&gt;While closed LLMs are easily controllable, safeguards in open models can easily be fine-tuned away.&lt;/li&gt;
&lt;li&gt;Therefore, open LLMs cannot be regulated like an API, and closed LLMs may even have an advantage because they are easier to regulate — a “mitigation gap”.&lt;/li&gt;
&lt;li&gt;The proposed solution is to define fine-tuned models as “substantial modification”, and shift the liability burden from the issuer of the original model to the fine-tuner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Auditing and securing supply chains&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Open Source Technology Improvement Fund (OSTIF) presented their work on providing security audits to open-source software &lt;a href=&quot;https://fosdem.org/2026/schedule/event/Z7D3MW-security_audits_and_security/&quot;&gt;(talk)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aboutcode.org/&quot;&gt;AboutCode&lt;/a&gt; presented their tool for detecting LLM-generated code &lt;a href=&quot;https://fosdem.org/2026/schedule/event/XGLP7J-ai-generated-code/&quot;&gt;(talk)&lt;/a&gt;. If I understood correctly, the tool finds parts of a codebase that have been regurgitated from another source, and can pinpoint to the source. One challenge was that LLMs often create similar control flow, but different variable names from the original. In their &lt;code&gt;scancode.io&lt;/code&gt; &lt;a href=&quot;https://github.com/aboutcode-org/scancode.io/&quot;&gt;tool&lt;/a&gt;, they solve this problem with code stemming, a method also used by &lt;code&gt;treesitter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;data-search-and-llms&quot;&gt;Data, Search and LLMs&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Vector search&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In a RAG pipeline, the hard part is data engineering: one has to understand the data and the context &lt;a href=&quot;https://fosdem.org/2026/schedule/event/DHTAXQ-prevent-ai-garbage/&quot;&gt;(talk)&lt;/a&gt;. For instance, the chunking strategy is crucial for the retrieved the results.&lt;/li&gt;
&lt;li&gt;Weaviate &lt;a href=&quot;https://fosdem.org/2026/schedule/event/3AWMQZ-multi-vector-embeddings-revolution-or-evolution/&quot;&gt;presented and demonstrated&lt;/a&gt; multi-vector retrieval. This is particularly useful for search on PDFs that include images. Their &lt;a href=&quot;https://github.com/weaviate/weaviate&quot;&gt;tool&lt;/a&gt; implements the MUVERA algorithm &lt;a href=&quot;https://arxiv.org/abs/2405.19504&quot;&gt;(paper)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Speeding up LLM inference&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The vLLM project &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/eldar_kurtic/&quot;&gt;explained&lt;/a&gt; how they speed up LLM inference with quantization and speculative decoding.&lt;/li&gt;
&lt;li&gt;Quantization compresses the network weights into buckets. This leads to a smaller footprint in memory and to faster transfer of the weights from the GPU’s high-bandwidth memory to the SRAM and Tensor cores that do the matrix multiplications.&lt;/li&gt;
&lt;li&gt;Their benchmarks show that the ideal strategy (4-bit integer quantization vs. 8-bit integer quantization vs. no quantization) depends on the number of queries per second.&lt;/li&gt;
&lt;li&gt;For speculative decoding, one trains a light-weight “speculator” model that generates tokens at inference time, and the main model approves or rejects the generated tokens.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;machine-learning-performance-and-observability&quot;&gt;Machine learning, performance, and observability&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Performance engineering&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two talks discussed best practices for performance engineering: to reliably capture performance regressions, benchmarks should be repeatable and representative, and setting them up for this requires some thought. Challenges include isolating the benchmark environments and avoiding too many false positives.&lt;/li&gt;
&lt;li&gt;The first talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/8AS3XD-how-to-reliably-measure-software-performance/&quot;&gt;outlined&lt;/a&gt; a statistical testing approach based on increasing the signal-to-noise ratio and deciding when to reject the null hypothesis of no performance regression. Further, running benchmarks in the cloud poses challenges, and they recommend avoiding virtualized environments. The slides of the talk are &lt;a href=&quot;https://github.com/igoragoli/fosdem-2026-software-performance&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The second talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/YNB7KR-continuous-perf-engineering/&quot;&gt;focused&lt;/a&gt; on change point detection. I also liked the idea of using canaries to track the performance of the benchmark infrastructure itself — you want to know when the problem is with the infrastructure and when it is with your software.&lt;/li&gt;
&lt;li&gt;Both talks argued for continuous performance monitoring and presented some tools for this.&lt;code&gt;nyrkio&lt;/code&gt;provides CI runners for change point detection; the runners are not free but according to the provider, they are of better quality than other runners (such as &lt;code&gt;github-action-benchmark&lt;/code&gt;). &lt;a href=&quot;https://github.com/sharkdp/hyperfine&quot;&gt;hyperfine&lt;/a&gt; is a command-line benchmarking tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Performance monitoring of deep learning workloads on HPC&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Two talks addressed performance monitoring for deep learning workloads on HPC systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/BBYZLU-gpu-performance-monitoring/&quot;&gt;highlighted&lt;/a&gt; the shortcomings of &lt;code&gt;nvidia-smi&lt;/code&gt; compared to &lt;code&gt;dcgmi&lt;/code&gt;. In short, the former only tells us &lt;em&gt;whether&lt;/em&gt; the GPUs are busy, but not &lt;em&gt;how efficiently&lt;/em&gt; they are being used (tensor cores, streaming multiprocessors, DRAM). One example was that using 32-bit and 16-bit precision on a H100 shows the same utilization on &lt;code&gt;nvidia-smi&lt;/code&gt;, even though FP32 is less efficient because H100s do not support tensor core computations with this precision.&lt;/li&gt;
&lt;li&gt;The same talk also suggested that running &lt;code&gt;dcgmi&lt;/code&gt; incurs no overhead because it is reading data that is already being tracked. I found useful docs from SURF &lt;a href=&quot;https://servicedesk.surf.nl/wiki/spaces/WIKI/pages/92668151/dcgmi+dmon&quot;&gt;here&lt;/a&gt;, and they are more cautious, mentioning that &lt;code&gt;dcgmi&lt;/code&gt; may slightly slow down your code. I guess one has to test and see it for themselves. The NVIDIA docs for &lt;code&gt;dcgmi&lt;/code&gt; are &lt;a href=&quot;https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/feature-overview.html#profiling-metrics&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The second talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/FYLDFE-observability_for_ai_workloads_on_hpc_beyond_gpu_utilization_metrics/&quot;&gt;presented&lt;/a&gt; an open-source observability dashboard for deep learning on HPC. It covers hardware, workload, and model health (such as gradient tracking). The &lt;a href=&quot;https://github.com/erythix4/HPCOBS&quot;&gt;tool&lt;/a&gt; was just released during the conference. I’m curious to see how it evolves and how it compares to other tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ole-mussmann-on-fosdem-2026-nix-international-oss-accessibility-and-collaboration&quot;&gt;Ole Mussmann on FOSDEM 2026: Nix, International OSS, Accessibility and Collaboration&lt;/h2&gt;
&lt;h3 id=&quot;opening&quot;&gt;Opening&lt;/h3&gt;
&lt;p&gt;A quote that hit hard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If we lose our democracies, Open Source is irrelevant and goes away.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nothing to add here.&lt;/p&gt;
&lt;h3 id=&quot;nix-and-nixos&quot;&gt;Nix and NixOS&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt; &lt;em&gt;&lt;strong&gt;for Determinism&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/bruce_gain/&quot;&gt;Bruce Gain&lt;/a&gt; discussed using &lt;code&gt;nix&lt;/code&gt; for “deterministic distributed-system benchmarking”. Without special care, library versions and kernel versions will drift over time. The low-hanging fruit &lt;code&gt;docker&lt;/code&gt; is not helping here. It solves packaging, not reproducibility, for two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker&lt;/code&gt; uses the host’s kernel, and&lt;/li&gt;
&lt;li&gt;it is &lt;em&gt;really&lt;/em&gt; hard to make a container deterministic. &lt;code&gt;apt-get update&lt;/code&gt; is not reproducible, any unpinned library will drift over time. You could distribute the &lt;em&gt;images&lt;/em&gt; instead of &lt;code&gt;Dockerfile&lt;/code&gt;s, but those are huge and not meant to be changed (only appended).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt; solves those issues by treating hashing and pinning every input of a project. Infrastructure is treated as a pure function. For identical inputs, the output &lt;em&gt;must&lt;/em&gt; be identical as well.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Software Bill of Materials (SBOM) Tools for &lt;code&gt;nix&lt;/code&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What’s inside your software package? Which dependencies do you use, and what’s &lt;em&gt;their&lt;/em&gt; dependencies? This surprisingly hard question is relevant for license compliance (did you obey the licenses of all libraries that you used?) as well as cybersecurity. If there’s a vulnerable package somewhere in the stack, you’d like to know, right? There’s a few tools that can help you out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nikstur/bombon&quot;&gt;https://github.com/nikstur/bombon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tiiuae/sbomnix&quot;&gt;https://github.com/tiiuae/sbomnix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anchore/syft&quot;&gt;https://github.com/anchore/syft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/determinatesystems&quot;&gt;Determinate Systems&lt;/a&gt; seem to have their own tool as well, but it does not seem to be public (yet?).&lt;/p&gt;
&lt;p&gt;Thanks for the heads up from &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/thecomputerguy&quot;&gt;Tristan “TheComputerGuy” Ross&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sphinx&lt;/code&gt; &lt;em&gt;&lt;strong&gt;Documentation for &lt;code&gt;nix&lt;/code&gt; Code&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sphinx&lt;/code&gt; was originally created as a documentation tool for &lt;code&gt;Python&lt;/code&gt; code, but it has since become a generic tool targeting all sorts of projects. &lt;a href=&quot;#7b6c&quot;&gt;[1]&lt;/a&gt; With &lt;a href=&quot;https://github.com/minijackson&quot;&gt;Rémi “minijackson”&lt;/a&gt; project &lt;code&gt;[sphinxcontrib-nixdomain](https://github.com/minijackson/sphinxcontrib-nixdomain)&lt;/code&gt; (rolls right off the tongue, doesn’t it?), one can document &lt;code&gt;nix&lt;/code&gt; options, modules, functions, package sets…&lt;/p&gt;
&lt;p&gt;This is the first time I see a structured approach to documenting a &lt;code&gt;nix&lt;/code&gt; project. Well done!&lt;/p&gt;
&lt;h3 id=&quot;international-open-source&quot;&gt;International Open Source&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Open Source in China&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Open Source looks different in China, says &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/richard_lin/&quot;&gt;Richard Lin&lt;/a&gt;. There are several factors at play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;FLOSS is seen as a market capture tool in three easy steps:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Turn standards into de facto rules,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rules into monopoly, and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monopoly into profits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Going global is not expansion, it’s survival.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The market in China is dry, so branching out is a necessity.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;FLOSS is a declaration, not procurement. The goal is to nurture industries that will enlarge future tax revenue, not buying a working product. The process for companies is:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Self-declare a directional FLOSS project,&lt;/li&gt;
&lt;li&gt;Build it,&lt;/li&gt;
&lt;li&gt;Pass inspection, and&lt;/li&gt;
&lt;li&gt;Receive cash.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Software development, even FLOSS, is a cathedral, not a bazaar.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Development is top-down.&lt;/li&gt;
&lt;li&gt;Pressure from the FLOSS community is slowly changing that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might notice a lack of FLOSS culture. Instead of “software wants to be free”, this looks very market-driven. And yet, even through this lens, this flavor of open source looks better to me than closed source. It will be interesting to watch how FLOSS develops in China, and how the different viewpoints will evolve.&lt;/p&gt;
&lt;h3 id=&quot;accessibility&quot;&gt;Accessibility&lt;/h3&gt;
&lt;p&gt;I arrived late to &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/mike_gifford/&quot;&gt;Mike Gifford&lt;/a&gt;’s talk “Accessible Sovereignty: Why the Four Freedoms Depend on Inclusion”, so I can’t say much about the actual content. What &lt;em&gt;did&lt;/em&gt; impress me was that he had a live-transcription of his voice underneath the slides. That is not only terrific for the hard-of-hearing, but also a very comforting addition for everyone else.&lt;/p&gt;
&lt;p&gt;Lessons at the eScience Center often use web slides made with &lt;code&gt;[reveal.js](https://revealjs.com/)&lt;/code&gt;. Modern browsers have a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API&quot;&gt;Web Speech API&lt;/a&gt; which can be used for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition&quot;&gt;speech recognition&lt;/a&gt;. Do you see where this is going…? Would it not be great to have a plugin for &lt;code&gt;reveal.js&lt;/code&gt; presentations that display speech-to-text below the slides? Any volunteers to build this? Anyone?&lt;/p&gt;
&lt;p&gt;Ok, fine. I’ll do it myself.&lt;/p&gt;
&lt;p&gt;P.S.: Here it is: &lt;a href=&quot;https://github.com/OleMussmann/RevealSubtitles&quot;&gt;https://github.com/OleMussmann/RevealSubtitles&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;collaboration&quot;&gt;Collaboration&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tdpauw&quot;&gt;Thierry de Pauw&lt;/a&gt; makes an argument that pull requests are useful for open-source work, but are more of a hindrance in the corporate world. They were coaching a novice team of developers and, to make things simple, they introduced trunk-based development with Non-Blocking Continuous Code Reviews. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everything happens on the &lt;code&gt;main&lt;/code&gt; branch, there are no other branches.&lt;/li&gt;
&lt;li&gt;Changes are (automatically) tested before deployment.&lt;/li&gt;
&lt;li&gt;Every morning, developers review some commits.&lt;/li&gt;
&lt;li&gt;In the end, every commit will be reviewed, after* being deployed(!).&lt;/li&gt;
&lt;li&gt;Fixes are applied, if needed, though this is rare.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Woah.&lt;/p&gt;
&lt;p&gt;I can see this working for a very specific developer situation while having absolutely rock-solid tests. Distributed development? Difficult. Working on features, while keeping the &lt;code&gt;main&lt;/code&gt; branch stable? Impossible. Troubleshooting bugs, bisecting a commit history? Tough.&lt;/p&gt;
&lt;p&gt;This is probably not a good fit for research-software-engineering. But I have to say, kudos for trying something weird &lt;em&gt;and making it work&lt;/em&gt;. And as a side effect, I realize that I have to be more flexible with my assumptions about how to develop software. That alone is already worthwhile.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://documentation.help/Sphinx/index.html&quot;&gt;https://documentation.help/Sphinx/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;faruk-diblen-on-fosdem-2026-sovereignty-burnout-and-the-ai-reality-check&quot;&gt;Faruk Diblen on FOSDEM 2026: Sovereignty, Burnout, and the AI Reality Check&lt;/h2&gt;
&lt;p&gt;I hope that by providing this short summary, I can convince you to participate in the next FOSDEM. It remains the biggest and most awesome open-source conference in Europe — and it is still free. It is so large that it reminds me of certain free open-source software projects: it is full of a specific kind of chaos. This is not due to the organization, but rather the scale of the conference and the range of topics and talks happening simultaneously. I must give kudos to the organizers for doing an amazing job.&lt;/p&gt;
&lt;h3 id=&quot;reflections-on-ai-and-the-community&quot;&gt;Reflections on AI and the Community&lt;/h3&gt;
&lt;p&gt;As I do every year, I was expecting amazing talks from people who are very passionate about open source and “geeky” topics. However, this time I also expected to hear more about how AI is supporting software development. Instead, most talks focused on how AI is dangerous and toxic for open source.&lt;/p&gt;
&lt;p&gt;I think I partly agree with that sentiment, but it may still be useful for certain tasks as a supporting tool. There were many interesting talks and discussions regarding the cultural, ethical, legal, and technological effects of recent developments in AI.&lt;/p&gt;
&lt;p&gt;The infamous &lt;a href=&quot;https://xkcd.com/2347/&quot;&gt;xkcd comic about infrastructure&lt;/a&gt; was also compulsory for all speakers to show. Perhaps the organizers were checking presentations beforehand, and if you did not have this comic, they were not allowing you to present. Jokes aside, I also agree now that this comic represents the current reality; it is perhaps even too modest.&lt;/p&gt;
&lt;h3 id=&quot;networking-and-the-research-track&quot;&gt;Networking and the Research Track&lt;/h3&gt;
&lt;p&gt;One of the other fun parts of FOSDEM is the chance to meet and have conversations with great minds, contributors, and initiators of very impactful open-source projects. Like previous years, I gathered new ideas and identified new potential collaboration opportunities. I should not skip the “fun stands”; you can talk to the amazing groups of people who made your favorite Linux distribution or who are working on drone development.&lt;/p&gt;
&lt;p&gt;As a researcher, I also had a chance to follow some of the &lt;a href=&quot;https://fosdem.org/2026/schedule/track/open-research/&quot;&gt;Open Research&lt;/a&gt; track. Although the research community was under-represented, it had a great variety of interesting topics, some of which are relevant to my own work. My positive experience has made me think about submitting a proposal for next year. For the other talks I followed or found interesting but could not attend in person, please see the &lt;a href=&quot;#72d3&quot;&gt;Highlights**&lt;/a&gt; section below.&lt;/p&gt;
&lt;p&gt;After leaving the conference, I had three things in my mind: sovereignty now, sovereignty in the near future, and sovereignty in the far future. I also deeply felt the messages of “AI is killing Open Source,” “Even if AI gets better, we, the developers, will be needed,” and “Everything will collapse if we do not support open source.” These messages were sometimes subliminal and sometimes mentioned openly.&lt;/p&gt;
&lt;h3 id=&quot;keynotes&quot;&gt;Keynotes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-foss-in-times-of-war%2F&quot;&gt;&lt;strong&gt;FOSDEM 2026 — FOSS in times of war, scarcity and (adversarial) AI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Given by Michiel Leenaards, our neighbor next door. I was expecting him to talk about how NLnet supports open-source software, but he focused on the threats caused by geopolitics. Given the recent political changes in many countries, I think it was a wisely chosen topic that forces us to think about upcoming challenges.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-free-as-in-burned-out%2F&quot;&gt;&lt;strong&gt;FOSDEM 2026 — Free as in Burned Out: Who Really Pays for Open Source?&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Marga Manterola, a long-time Debian developer, talked about why the “donations and sponsorships” model is failing maintainers. She listed common funding sources including a sort of “Open Source tax.” This talk may help us find solutions for software maintenance and sustainability funds.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-security-in-spite-of-ai%2F&quot;&gt;&lt;strong&gt;Open Source Security in spite of AI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; This was the most fun keynote, given by Daniel Stenberg. He told the story of the cURL project and his fight with issues and pull requests created by LLMs. Eventually, they decided to stop their Bug Bounty program. You can download the talk by using the &lt;code&gt;curl&lt;/code&gt; command below:** &lt;code&gt;curl https://ftp.belnet.be/mirror/FOSDEM/video/2026/janson/B7YKQ7-oss-in-spite-of-ai.av1.webm --output curl_keynote.webm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;highlights&quot;&gt;Highlights&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(The talks I liked the most)&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Frrp-reproducible-research-platform%2F&quot;&gt;RRP: Reproducible Research Platform for FAIR Open Research**&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Andreas Cuny showcased the RRP: a heavyweight solution combining openBIS (RDMS), Git, Docker, and Kubernetes. It allows users to mount datasets into Jupyter/VS Code environments instantly. It is a bit complex to set up, but powerful for institutions. I had a very pleasant conversation with Andreas regarding potential collaborations, such as adding actual FAIR software checks (via &lt;code&gt;howfairis&lt;/code&gt;) to their platform.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwho-funds-the-egg%2F&quot;&gt;&lt;strong&gt;Who Funds the Egg? Cracking the FOSS Funding Paradox&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Deborah Udoh highlighted the “chicken and egg” problem: you need impact to get funding, but you need funding to create impact. The “Pre-seeds” concept — non-monetary investments like visibility and mentorship — seems like a viable bridge for early-stage projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fmultimodal-support-in-llamacpp%2F&quot;&gt;&lt;strong&gt;Multimodal support in llama.cpp — Achievements and Future Directions&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Huge updates for local AI. &lt;code&gt;libmtmd&lt;/code&gt; finally standardizes multimodal support. They showed &lt;code&gt;llama-mtmd-cli&lt;/code&gt; doing low-latency OCR and experimental audio input with Ultravox.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fits-time-to-audit-open-source%2F&quot;&gt;&lt;strong&gt;It’s Time to Audit Open Source: Success Stories with OSTIF&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; OSTIF has now facilitated over 100 security audits for projects like git, cURL, and Kubernetes. The data shows that independent code review works.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fsupply-chain-security-meets-ai%2F&quot;&gt;&lt;strong&gt;Supply chain security meets AI: Detecting AI-generated code&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Philippe Ombredanne introduced a new tool for “fuzzy matching” code snippets to detect AI-generated content. With bots writing billions of lines of code, exact hashing does not work any more.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fthe-ai-shockwave%2F&quot;&gt;&lt;strong&gt;The AI Shockwave in Open Source Communities: How AI Is Reshaping the Foundations of Open Source Communities&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; A worrying trend where newbie questions are dropping because people ask ChatGPT instead. This breaks the “contributor pipeline.”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fburnout-in-open-source%2F&quot;&gt;&lt;strong&gt;Burnout in Open Source: A Structural Problem We Can Fix Together&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Miranda Heath identified “hyper-responsibility” and “toxic entitlement” as key burnout drivers. We need structural changes in how we value maintenance work.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fintroducing-jupyter-book-2%2F&quot;&gt;&lt;strong&gt;Introducing Jupyter Book 2: Next-generation Tools for Creating Computational Narratives&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; A complete rewrite based on the MyST (Markedly Structured Text) engine. It produces semantic, machine-readable content that is much easier to cross-reference.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fparticleos-from-fedora-to-feast%2F&quot;&gt;&lt;strong&gt;ParticleOS, from Fedora to Feast: Stirring Traditional Distros into Immutable Delights&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Luca Boccassi showed how &lt;code&gt;systemd&lt;/code&gt; and &lt;code&gt;mkosi&lt;/code&gt; are changing OS building, creating a fully immutable, signed, and verifiable image.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwhat-do-we-mean-sovereign-ai%2F&quot;&gt;&lt;strong&gt;What do we mean when we say Sovereign AI?&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Katharine Jarmul explained that true “Sovereign AI” is not just about where the model is hosted, but having the full training data and code available to inspect.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-notable-tracks-and-talks&quot;&gt;Other Notable Tracks and Talks&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Research &amp;#x26; Science&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Frse-movement-uiuc%2F&quot;&gt;Research software engineering: a movement and its instantiation at the University of Illinois Urbana-Champaign&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fresearch-software-funding-models%2F&quot;&gt;Research software grant funding models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fbuilding-open-research-infrastructure%2F&quot;&gt;Building Open Research Infrastructure: Connecting the Lab Bench to Computational Analysis with RSpace &amp;#x26; Galaxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fharnessing-nix-for-bioinformatics%2F&quot;&gt;Building Everything with Nothing — Harnessing Nix for Bioinformatics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fgems-high-level-language%2F&quot;&gt;From Code to Models-as-Data: GEMS, a High-Level Language for Energy System Modelling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fopen-reproducible-ai-lmics%2F&quot;&gt;Building Open and Reproducible AI Practices for LMICs (and Beyond)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fcern-adaptyst%2F&quot;&gt;Towards unified full-stack performance analysis and automated computer system design at CERN with Adaptyst&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Foqtopus-quantum-toolchain%2F&quot;&gt;OQTOPUS: Open Quantum Toolchain for OPerators and USers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fskills-floss-developer%2F&quot;&gt;The Skills of a FLOSS Developer and Why They Are Important in Open Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Ftrusted-by-design%2F&quot;&gt;Trusted by design: set up your research software for community adoption&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Main Track &amp;#x26; Community&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fefficient-git-workflow%2F&quot;&gt;An Efficient Git Workflow For High-Stakes Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeep-open-source-open%2F&quot;&gt;How to keep Open Source open without leaving our communities open to threats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fstrategy-trusting-employer%2F&quot;&gt;Strategy for Trusting your Employer in Open Source: a Historical Approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwho-pays-your-bills%2F&quot;&gt;Who Pays Your Bills? Sustainability, Community and Business: The Open Source Triangle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fnext-gen-postgres-contributors%2F&quot;&gt;Building the next generation of open source contributors — Lessons from 30 years of Postgres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Ffunding-europe-digital-infra%2F&quot;&gt;Funding Europe’s Open Digital Infrastructure: A Detailed Case for an EU Sovereign Tech Fund&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2F32-years-debian%2F&quot;&gt;32 years of Debian: how a do-ocracy keeps evolving&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;AI &amp;#x26; Machine Learning&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Flow-code-ai-agents%2F&quot;&gt;Drag, Drop, and Deploy: Low-Code AI Agents for Network Ops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fself-hosted-llms%2F&quot;&gt;From Infrastructure to Production: A Year of Self-Hosted LLMs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fai-security-monitoring%2F&quot;&gt;AI Security Monitoring: Detecting Threats Against Production ML Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fprevent-ai-garbage%2F&quot;&gt;How to Prevent Your AI from Returning Garbage: It Starts and Ends with Data Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fdeep-learning-snap%2F&quot;&gt;Deep Learning Demystified — Having Fun with Neural Networks in Snap!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Security, Databases &amp;#x26; Infrastructure&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fpost-quantum-cryptography%2F&quot;&gt;Demystifying Post-Quantum Cryptography: The Hybrid Approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Flook-ma-no-secrets%2F&quot;&gt;Look ma, no secrets! — bootstrapping cryptographic trust in my homelab using NixOS, UKIs, TPMs and SPIFFE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Freal-time-ai-rondb%2F&quot;&gt;Real-Time AI Powered by RonDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fduckdb-bike-share%2F&quot;&gt;Exploring time series bike share data with duckdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fopensearch-v3%2F&quot;&gt;OpenSearch v3: A New Era of Search Innovation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fsurf-research-cloud-oss%2F&quot;&gt;SURF Research Cloud is going OSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fguix-container-images%2F&quot;&gt;Guix Container Images — and what you can do with them&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;booths-and-extra-notes&quot;&gt;Booths and Extra Notes&lt;/h3&gt;
&lt;p&gt;After hearing about sovereignty everywhere, I had lengthy chats with the folks from &lt;strong&gt;GitLab, NextCloud, LibreOffice, Forgejo&lt;/strong&gt;, and &lt;strong&gt;Codeberg&lt;/strong&gt; to learn about open-source office solutions and infrastructure. I also talked to someone from Germany who explained the government migration to Linux (see: &lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Fwww.zdnet.com%2Farticle%2Fanother-european-government-is-ditching-microsoft-for-linux%2F&quot;&gt;Yet another European government is ditching Microsoft for Linux&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I visited the &lt;strong&gt;Tor&lt;/strong&gt; stand, where you could get fancy stickers if you donated to help them fight censorship. The &lt;strong&gt;Free Software Foundation Europe (FSFE)&lt;/strong&gt; is also worth following closely as their goals are related to our own. Finally, I learned about &lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffundingjs.org%2F&quot;&gt;&lt;strong&gt;funding.json&lt;/strong&gt;&lt;/a&gt;, a format to declare financial needs of projects in a machine-readable format.&lt;/p&gt;</description><pubDate>Thu, 09 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;FOSDEM 2026: Observations and key takeaways&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/fosdem-2026-observations-and-key-takeawa-55dcce06.l9YVToEZ_ZsYfBF.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;If you missed FOSDEM 2026 — the largest conference dedicated to open-source software — you can still absorb some of the experience as shared by NLeSC RSEs &lt;strong&gt;Flavio Hafner&lt;/strong&gt;&lt;/em&gt;*, &lt;strong&gt;&lt;strong&gt;Ole Mussmann&lt;/strong&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;strong&gt;Faruk Diblen&lt;/strong&gt;&lt;/strong&gt;.*&lt;/p&gt;
&lt;h2 id=&quot;flavio-hafner-on-fosdem-2026-security-llms-and-software-performance&quot;&gt;Flavio Hafner on FOSDEM 2026: Security, LLMs, and Software Performance&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is a version of the &lt;em&gt;&lt;a href=&quot;https://f-hafner.github.io/fosdem-2026/&quot;&gt;&lt;em&gt;original post by Flavio&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; adapted for Medium.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My highlights from this year’s FOSDEM are in the areas of LLM/security/open source, in machine learning/software performance, and in databases/search.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-features-in-git&quot;&gt;Upcoming features in git&lt;/h2&gt;
&lt;p&gt;Patrick Steinhardt from GitLab, and git contributor, &lt;a href=&quot;https://fosdem.org/2026/schedule/event/HTJK33-evolving_git_for_the_next_decade/&quot;&gt;presented&lt;/a&gt; about some upcoming changes, planned for the major 3.0 release towards mid-2026.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Under the hood, git changes the hashing algorithm from SHA-1 to SHA-256&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is because SHA-1 is not secure — a paper from around 2017 showed that it does not create unique hashes.&lt;/li&gt;
&lt;li&gt;While git itself does not rely on uniqueness of hashes, the ecosystem implicitly does — for instance, by pinning software dependencies to git hashes.&lt;/li&gt;
&lt;li&gt;At the same time, large parts of the ecosystem (GitHub for instance) currently do not support SHA-256 hashes.&lt;/li&gt;
&lt;li&gt;By moving the default in git, the contributors want to solve the chicken-and-egg problem of “no-one wanting to use the feature because no-one supports it” and vice versa.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;New command: git history for easier rewriting of history&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In git, rewriting history through an interactive rebase is cumbersome and takes several steps.&lt;/li&gt;
&lt;li&gt;Another limitation is that it leads to orphaned branches because other branches depending on the changed commits are not updated. For instance, this makes is tedious to use workflows with stacked branches.&lt;/li&gt;
&lt;li&gt;The new &lt;code&gt;git history&lt;/code&gt; command, inspired by other version control systems such as Jujutsu and Mercurial, provides some functionality that makes such workflows easier. For instance, &lt;code&gt;git history reword &amp;#x26;lt;commit&amp;#x26;gt;&lt;/code&gt; allows to amend the commit message of a specific commit; &lt;code&gt;git history split &amp;#x26;lt;commit&amp;#x26;gt;&lt;/code&gt; allows to split a specific commit.&lt;/li&gt;
&lt;li&gt;The new commands &lt;em&gt;also&lt;/em&gt; rebase other branches that depend on respective commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;open-source-llms-and-security&quot;&gt;Open Source, LLMs, and security&lt;/h3&gt;
&lt;p&gt;This was a major topic in this year’s conference and featured in two keynotes: Michael Leenaars &lt;a href=&quot;https://fosdem.org/2026/schedule/event/FE7ULY-foss-in-times-of-war-scarcity-and-ai/&quot;&gt;(talk)&lt;/a&gt; from NLnet, and Daniel Stenberg, founder and lead developer of cURL &lt;a href=&quot;https://fosdem.org/2026/schedule/event/B7YKQ7-oss-in-spite-of-ai/&quot;&gt;(talk)&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Both speakers highlighted that LLMs can help malicious actors find and exploit vulnerabilities in open-source code, and thus open-source will become more vulnerable to supply-chain attacks.&lt;/li&gt;
&lt;li&gt;Stenberg further detailed how LLMs bring out the worst and best at the same time. On one hand, the cURL project is bombarded by AI-generated security reports. This has led cURL to stop their bug bounty program. On the other hand, they use LLMs selectively to find security issues and review code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Several talks in the security devroom addressed the same problem.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Updated governance model for open-weight LLMs&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href=&quot;https://fosdem.org/2026/schedule/event/VGMUYA-the-open-weight-dilemma/&quot;&gt;talk&lt;/a&gt; about LLMs and cyber risks argued for an updated governance model for open-source (and maybe open-weight) LLMs.&lt;/li&gt;
&lt;li&gt;While closed LLMs are easily controllable, safeguards in open models can easily be fine-tuned away.&lt;/li&gt;
&lt;li&gt;Therefore, open LLMs cannot be regulated like an API, and closed LLMs may even have an advantage because they are easier to regulate — a “mitigation gap”.&lt;/li&gt;
&lt;li&gt;The proposed solution is to define fine-tuned models as “substantial modification”, and shift the liability burden from the issuer of the original model to the fine-tuner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Auditing and securing supply chains&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Open Source Technology Improvement Fund (OSTIF) presented their work on providing security audits to open-source software &lt;a href=&quot;https://fosdem.org/2026/schedule/event/Z7D3MW-security_audits_and_security/&quot;&gt;(talk)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aboutcode.org/&quot;&gt;AboutCode&lt;/a&gt; presented their tool for detecting LLM-generated code &lt;a href=&quot;https://fosdem.org/2026/schedule/event/XGLP7J-ai-generated-code/&quot;&gt;(talk)&lt;/a&gt;. If I understood correctly, the tool finds parts of a codebase that have been regurgitated from another source, and can pinpoint to the source. One challenge was that LLMs often create similar control flow, but different variable names from the original. In their &lt;code&gt;scancode.io&lt;/code&gt; &lt;a href=&quot;https://github.com/aboutcode-org/scancode.io/&quot;&gt;tool&lt;/a&gt;, they solve this problem with code stemming, a method also used by &lt;code&gt;treesitter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;data-search-and-llms&quot;&gt;Data, Search and LLMs&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Vector search&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In a RAG pipeline, the hard part is data engineering: one has to understand the data and the context &lt;a href=&quot;https://fosdem.org/2026/schedule/event/DHTAXQ-prevent-ai-garbage/&quot;&gt;(talk)&lt;/a&gt;. For instance, the chunking strategy is crucial for the retrieved the results.&lt;/li&gt;
&lt;li&gt;Weaviate &lt;a href=&quot;https://fosdem.org/2026/schedule/event/3AWMQZ-multi-vector-embeddings-revolution-or-evolution/&quot;&gt;presented and demonstrated&lt;/a&gt; multi-vector retrieval. This is particularly useful for search on PDFs that include images. Their &lt;a href=&quot;https://github.com/weaviate/weaviate&quot;&gt;tool&lt;/a&gt; implements the MUVERA algorithm &lt;a href=&quot;https://arxiv.org/abs/2405.19504&quot;&gt;(paper)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Speeding up LLM inference&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The vLLM project &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/eldar_kurtic/&quot;&gt;explained&lt;/a&gt; how they speed up LLM inference with quantization and speculative decoding.&lt;/li&gt;
&lt;li&gt;Quantization compresses the network weights into buckets. This leads to a smaller footprint in memory and to faster transfer of the weights from the GPU’s high-bandwidth memory to the SRAM and Tensor cores that do the matrix multiplications.&lt;/li&gt;
&lt;li&gt;Their benchmarks show that the ideal strategy (4-bit integer quantization vs. 8-bit integer quantization vs. no quantization) depends on the number of queries per second.&lt;/li&gt;
&lt;li&gt;For speculative decoding, one trains a light-weight “speculator” model that generates tokens at inference time, and the main model approves or rejects the generated tokens.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;machine-learning-performance-and-observability&quot;&gt;Machine learning, performance, and observability&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Performance engineering&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two talks discussed best practices for performance engineering: to reliably capture performance regressions, benchmarks should be repeatable and representative, and setting them up for this requires some thought. Challenges include isolating the benchmark environments and avoiding too many false positives.&lt;/li&gt;
&lt;li&gt;The first talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/8AS3XD-how-to-reliably-measure-software-performance/&quot;&gt;outlined&lt;/a&gt; a statistical testing approach based on increasing the signal-to-noise ratio and deciding when to reject the null hypothesis of no performance regression. Further, running benchmarks in the cloud poses challenges, and they recommend avoiding virtualized environments. The slides of the talk are &lt;a href=&quot;https://github.com/igoragoli/fosdem-2026-software-performance&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The second talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/YNB7KR-continuous-perf-engineering/&quot;&gt;focused&lt;/a&gt; on change point detection. I also liked the idea of using canaries to track the performance of the benchmark infrastructure itself — you want to know when the problem is with the infrastructure and when it is with your software.&lt;/li&gt;
&lt;li&gt;Both talks argued for continuous performance monitoring and presented some tools for this.&lt;code&gt;nyrkio&lt;/code&gt;provides CI runners for change point detection; the runners are not free but according to the provider, they are of better quality than other runners (such as &lt;code&gt;github-action-benchmark&lt;/code&gt;). &lt;a href=&quot;https://github.com/sharkdp/hyperfine&quot;&gt;hyperfine&lt;/a&gt; is a command-line benchmarking tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Performance monitoring of deep learning workloads on HPC&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Two talks addressed performance monitoring for deep learning workloads on HPC systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/BBYZLU-gpu-performance-monitoring/&quot;&gt;highlighted&lt;/a&gt; the shortcomings of &lt;code&gt;nvidia-smi&lt;/code&gt; compared to &lt;code&gt;dcgmi&lt;/code&gt;. In short, the former only tells us &lt;em&gt;whether&lt;/em&gt; the GPUs are busy, but not &lt;em&gt;how efficiently&lt;/em&gt; they are being used (tensor cores, streaming multiprocessors, DRAM). One example was that using 32-bit and 16-bit precision on a H100 shows the same utilization on &lt;code&gt;nvidia-smi&lt;/code&gt;, even though FP32 is less efficient because H100s do not support tensor core computations with this precision.&lt;/li&gt;
&lt;li&gt;The same talk also suggested that running &lt;code&gt;dcgmi&lt;/code&gt; incurs no overhead because it is reading data that is already being tracked. I found useful docs from SURF &lt;a href=&quot;https://servicedesk.surf.nl/wiki/spaces/WIKI/pages/92668151/dcgmi+dmon&quot;&gt;here&lt;/a&gt;, and they are more cautious, mentioning that &lt;code&gt;dcgmi&lt;/code&gt; may slightly slow down your code. I guess one has to test and see it for themselves. The NVIDIA docs for &lt;code&gt;dcgmi&lt;/code&gt; are &lt;a href=&quot;https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/feature-overview.html#profiling-metrics&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The second talk &lt;a href=&quot;https://fosdem.org/2026/schedule/event/FYLDFE-observability_for_ai_workloads_on_hpc_beyond_gpu_utilization_metrics/&quot;&gt;presented&lt;/a&gt; an open-source observability dashboard for deep learning on HPC. It covers hardware, workload, and model health (such as gradient tracking). The &lt;a href=&quot;https://github.com/erythix4/HPCOBS&quot;&gt;tool&lt;/a&gt; was just released during the conference. I’m curious to see how it evolves and how it compares to other tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ole-mussmann-on-fosdem-2026-nix-international-oss-accessibility-and-collaboration&quot;&gt;Ole Mussmann on FOSDEM 2026: Nix, International OSS, Accessibility and Collaboration&lt;/h2&gt;
&lt;h3 id=&quot;opening&quot;&gt;Opening&lt;/h3&gt;
&lt;p&gt;A quote that hit hard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If we lose our democracies, Open Source is irrelevant and goes away.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nothing to add here.&lt;/p&gt;
&lt;h3 id=&quot;nix-and-nixos&quot;&gt;Nix and NixOS&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt; &lt;em&gt;&lt;strong&gt;for Determinism&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/bruce_gain/&quot;&gt;Bruce Gain&lt;/a&gt; discussed using &lt;code&gt;nix&lt;/code&gt; for “deterministic distributed-system benchmarking”. Without special care, library versions and kernel versions will drift over time. The low-hanging fruit &lt;code&gt;docker&lt;/code&gt; is not helping here. It solves packaging, not reproducibility, for two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker&lt;/code&gt; uses the host’s kernel, and&lt;/li&gt;
&lt;li&gt;it is &lt;em&gt;really&lt;/em&gt; hard to make a container deterministic. &lt;code&gt;apt-get update&lt;/code&gt; is not reproducible, any unpinned library will drift over time. You could distribute the &lt;em&gt;images&lt;/em&gt; instead of &lt;code&gt;Dockerfile&lt;/code&gt;s, but those are huge and not meant to be changed (only appended).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt; solves those issues by treating hashing and pinning every input of a project. Infrastructure is treated as a pure function. For identical inputs, the output &lt;em&gt;must&lt;/em&gt; be identical as well.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Software Bill of Materials (SBOM) Tools for &lt;code&gt;nix&lt;/code&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What’s inside your software package? Which dependencies do you use, and what’s &lt;em&gt;their&lt;/em&gt; dependencies? This surprisingly hard question is relevant for license compliance (did you obey the licenses of all libraries that you used?) as well as cybersecurity. If there’s a vulnerable package somewhere in the stack, you’d like to know, right? There’s a few tools that can help you out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nikstur/bombon&quot;&gt;https://github.com/nikstur/bombon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tiiuae/sbomnix&quot;&gt;https://github.com/tiiuae/sbomnix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anchore/syft&quot;&gt;https://github.com/anchore/syft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/determinatesystems&quot;&gt;Determinate Systems&lt;/a&gt; seem to have their own tool as well, but it does not seem to be public (yet?).&lt;/p&gt;
&lt;p&gt;Thanks for the heads up from &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/thecomputerguy&quot;&gt;Tristan “TheComputerGuy” Ross&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sphinx&lt;/code&gt; &lt;em&gt;&lt;strong&gt;Documentation for &lt;code&gt;nix&lt;/code&gt; Code&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sphinx&lt;/code&gt; was originally created as a documentation tool for &lt;code&gt;Python&lt;/code&gt; code, but it has since become a generic tool targeting all sorts of projects. &lt;a href=&quot;#7b6c&quot;&gt;[1]&lt;/a&gt; With &lt;a href=&quot;https://github.com/minijackson&quot;&gt;Rémi “minijackson”&lt;/a&gt; project &lt;code&gt;[sphinxcontrib-nixdomain](https://github.com/minijackson/sphinxcontrib-nixdomain)&lt;/code&gt; (rolls right off the tongue, doesn’t it?), one can document &lt;code&gt;nix&lt;/code&gt; options, modules, functions, package sets…&lt;/p&gt;
&lt;p&gt;This is the first time I see a structured approach to documenting a &lt;code&gt;nix&lt;/code&gt; project. Well done!&lt;/p&gt;
&lt;h3 id=&quot;international-open-source&quot;&gt;International Open Source&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Open Source in China&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Open Source looks different in China, says &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/richard_lin/&quot;&gt;Richard Lin&lt;/a&gt;. There are several factors at play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;FLOSS is seen as a market capture tool in three easy steps:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Turn standards into de facto rules,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rules into monopoly, and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monopoly into profits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Going global is not expansion, it’s survival.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The market in China is dry, so branching out is a necessity.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;FLOSS is a declaration, not procurement. The goal is to nurture industries that will enlarge future tax revenue, not buying a working product. The process for companies is:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Self-declare a directional FLOSS project,&lt;/li&gt;
&lt;li&gt;Build it,&lt;/li&gt;
&lt;li&gt;Pass inspection, and&lt;/li&gt;
&lt;li&gt;Receive cash.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Software development, even FLOSS, is a cathedral, not a bazaar.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Development is top-down.&lt;/li&gt;
&lt;li&gt;Pressure from the FLOSS community is slowly changing that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might notice a lack of FLOSS culture. Instead of “software wants to be free”, this looks very market-driven. And yet, even through this lens, this flavor of open source looks better to me than closed source. It will be interesting to watch how FLOSS develops in China, and how the different viewpoints will evolve.&lt;/p&gt;
&lt;h3 id=&quot;accessibility&quot;&gt;Accessibility&lt;/h3&gt;
&lt;p&gt;I arrived late to &lt;a href=&quot;https://fosdem.org/2026/schedule/speaker/mike_gifford/&quot;&gt;Mike Gifford&lt;/a&gt;’s talk “Accessible Sovereignty: Why the Four Freedoms Depend on Inclusion”, so I can’t say much about the actual content. What &lt;em&gt;did&lt;/em&gt; impress me was that he had a live-transcription of his voice underneath the slides. That is not only terrific for the hard-of-hearing, but also a very comforting addition for everyone else.&lt;/p&gt;
&lt;p&gt;Lessons at the eScience Center often use web slides made with &lt;code&gt;[reveal.js](https://revealjs.com/)&lt;/code&gt;. Modern browsers have a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API&quot;&gt;Web Speech API&lt;/a&gt; which can be used for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition&quot;&gt;speech recognition&lt;/a&gt;. Do you see where this is going…? Would it not be great to have a plugin for &lt;code&gt;reveal.js&lt;/code&gt; presentations that display speech-to-text below the slides? Any volunteers to build this? Anyone?&lt;/p&gt;
&lt;p&gt;Ok, fine. I’ll do it myself.&lt;/p&gt;
&lt;p&gt;P.S.: Here it is: &lt;a href=&quot;https://github.com/OleMussmann/RevealSubtitles&quot;&gt;https://github.com/OleMussmann/RevealSubtitles&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;collaboration&quot;&gt;Collaboration&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tdpauw&quot;&gt;Thierry de Pauw&lt;/a&gt; makes an argument that pull requests are useful for open-source work, but are more of a hindrance in the corporate world. They were coaching a novice team of developers and, to make things simple, they introduced trunk-based development with Non-Blocking Continuous Code Reviews. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everything happens on the &lt;code&gt;main&lt;/code&gt; branch, there are no other branches.&lt;/li&gt;
&lt;li&gt;Changes are (automatically) tested before deployment.&lt;/li&gt;
&lt;li&gt;Every morning, developers review some commits.&lt;/li&gt;
&lt;li&gt;In the end, every commit will be reviewed, after* being deployed(!).&lt;/li&gt;
&lt;li&gt;Fixes are applied, if needed, though this is rare.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Woah.&lt;/p&gt;
&lt;p&gt;I can see this working for a very specific developer situation while having absolutely rock-solid tests. Distributed development? Difficult. Working on features, while keeping the &lt;code&gt;main&lt;/code&gt; branch stable? Impossible. Troubleshooting bugs, bisecting a commit history? Tough.&lt;/p&gt;
&lt;p&gt;This is probably not a good fit for research-software-engineering. But I have to say, kudos for trying something weird &lt;em&gt;and making it work&lt;/em&gt;. And as a side effect, I realize that I have to be more flexible with my assumptions about how to develop software. That alone is already worthwhile.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://documentation.help/Sphinx/index.html&quot;&gt;https://documentation.help/Sphinx/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;faruk-diblen-on-fosdem-2026-sovereignty-burnout-and-the-ai-reality-check&quot;&gt;Faruk Diblen on FOSDEM 2026: Sovereignty, Burnout, and the AI Reality Check&lt;/h2&gt;
&lt;p&gt;I hope that by providing this short summary, I can convince you to participate in the next FOSDEM. It remains the biggest and most awesome open-source conference in Europe — and it is still free. It is so large that it reminds me of certain free open-source software projects: it is full of a specific kind of chaos. This is not due to the organization, but rather the scale of the conference and the range of topics and talks happening simultaneously. I must give kudos to the organizers for doing an amazing job.&lt;/p&gt;
&lt;h3 id=&quot;reflections-on-ai-and-the-community&quot;&gt;Reflections on AI and the Community&lt;/h3&gt;
&lt;p&gt;As I do every year, I was expecting amazing talks from people who are very passionate about open source and “geeky” topics. However, this time I also expected to hear more about how AI is supporting software development. Instead, most talks focused on how AI is dangerous and toxic for open source.&lt;/p&gt;
&lt;p&gt;I think I partly agree with that sentiment, but it may still be useful for certain tasks as a supporting tool. There were many interesting talks and discussions regarding the cultural, ethical, legal, and technological effects of recent developments in AI.&lt;/p&gt;
&lt;p&gt;The infamous &lt;a href=&quot;https://xkcd.com/2347/&quot;&gt;xkcd comic about infrastructure&lt;/a&gt; was also compulsory for all speakers to show. Perhaps the organizers were checking presentations beforehand, and if you did not have this comic, they were not allowing you to present. Jokes aside, I also agree now that this comic represents the current reality; it is perhaps even too modest.&lt;/p&gt;
&lt;h3 id=&quot;networking-and-the-research-track&quot;&gt;Networking and the Research Track&lt;/h3&gt;
&lt;p&gt;One of the other fun parts of FOSDEM is the chance to meet and have conversations with great minds, contributors, and initiators of very impactful open-source projects. Like previous years, I gathered new ideas and identified new potential collaboration opportunities. I should not skip the “fun stands”; you can talk to the amazing groups of people who made your favorite Linux distribution or who are working on drone development.&lt;/p&gt;
&lt;p&gt;As a researcher, I also had a chance to follow some of the &lt;a href=&quot;https://fosdem.org/2026/schedule/track/open-research/&quot;&gt;Open Research&lt;/a&gt; track. Although the research community was under-represented, it had a great variety of interesting topics, some of which are relevant to my own work. My positive experience has made me think about submitting a proposal for next year. For the other talks I followed or found interesting but could not attend in person, please see the &lt;a href=&quot;#72d3&quot;&gt;Highlights**&lt;/a&gt; section below.&lt;/p&gt;
&lt;p&gt;After leaving the conference, I had three things in my mind: sovereignty now, sovereignty in the near future, and sovereignty in the far future. I also deeply felt the messages of “AI is killing Open Source,” “Even if AI gets better, we, the developers, will be needed,” and “Everything will collapse if we do not support open source.” These messages were sometimes subliminal and sometimes mentioned openly.&lt;/p&gt;
&lt;h3 id=&quot;keynotes&quot;&gt;Keynotes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-foss-in-times-of-war%2F&quot;&gt;&lt;strong&gt;FOSDEM 2026 — FOSS in times of war, scarcity and (adversarial) AI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Given by Michiel Leenaards, our neighbor next door. I was expecting him to talk about how NLnet supports open-source software, but he focused on the threats caused by geopolitics. Given the recent political changes in many countries, I think it was a wisely chosen topic that forces us to think about upcoming challenges.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-free-as-in-burned-out%2F&quot;&gt;&lt;strong&gt;FOSDEM 2026 — Free as in Burned Out: Who Really Pays for Open Source?&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Marga Manterola, a long-time Debian developer, talked about why the “donations and sponsorships” model is failing maintainers. She listed common funding sources including a sort of “Open Source tax.” This talk may help us find solutions for software maintenance and sustainability funds.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeynote-security-in-spite-of-ai%2F&quot;&gt;&lt;strong&gt;Open Source Security in spite of AI&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; This was the most fun keynote, given by Daniel Stenberg. He told the story of the cURL project and his fight with issues and pull requests created by LLMs. Eventually, they decided to stop their Bug Bounty program. You can download the talk by using the &lt;code&gt;curl&lt;/code&gt; command below:** &lt;code&gt;curl https://ftp.belnet.be/mirror/FOSDEM/video/2026/janson/B7YKQ7-oss-in-spite-of-ai.av1.webm --output curl_keynote.webm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;highlights&quot;&gt;Highlights&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(The talks I liked the most)&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Frrp-reproducible-research-platform%2F&quot;&gt;RRP: Reproducible Research Platform for FAIR Open Research**&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Andreas Cuny showcased the RRP: a heavyweight solution combining openBIS (RDMS), Git, Docker, and Kubernetes. It allows users to mount datasets into Jupyter/VS Code environments instantly. It is a bit complex to set up, but powerful for institutions. I had a very pleasant conversation with Andreas regarding potential collaborations, such as adding actual FAIR software checks (via &lt;code&gt;howfairis&lt;/code&gt;) to their platform.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwho-funds-the-egg%2F&quot;&gt;&lt;strong&gt;Who Funds the Egg? Cracking the FOSS Funding Paradox&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Deborah Udoh highlighted the “chicken and egg” problem: you need impact to get funding, but you need funding to create impact. The “Pre-seeds” concept — non-monetary investments like visibility and mentorship — seems like a viable bridge for early-stage projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fmultimodal-support-in-llamacpp%2F&quot;&gt;&lt;strong&gt;Multimodal support in llama.cpp — Achievements and Future Directions&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Huge updates for local AI. &lt;code&gt;libmtmd&lt;/code&gt; finally standardizes multimodal support. They showed &lt;code&gt;llama-mtmd-cli&lt;/code&gt; doing low-latency OCR and experimental audio input with Ultravox.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fits-time-to-audit-open-source%2F&quot;&gt;&lt;strong&gt;It’s Time to Audit Open Source: Success Stories with OSTIF&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; OSTIF has now facilitated over 100 security audits for projects like git, cURL, and Kubernetes. The data shows that independent code review works.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fsupply-chain-security-meets-ai%2F&quot;&gt;&lt;strong&gt;Supply chain security meets AI: Detecting AI-generated code&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Philippe Ombredanne introduced a new tool for “fuzzy matching” code snippets to detect AI-generated content. With bots writing billions of lines of code, exact hashing does not work any more.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fthe-ai-shockwave%2F&quot;&gt;&lt;strong&gt;The AI Shockwave in Open Source Communities: How AI Is Reshaping the Foundations of Open Source Communities&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; A worrying trend where newbie questions are dropping because people ask ChatGPT instead. This breaks the “contributor pipeline.”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fburnout-in-open-source%2F&quot;&gt;&lt;strong&gt;Burnout in Open Source: A Structural Problem We Can Fix Together&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Miranda Heath identified “hyper-responsibility” and “toxic entitlement” as key burnout drivers. We need structural changes in how we value maintenance work.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fintroducing-jupyter-book-2%2F&quot;&gt;&lt;strong&gt;Introducing Jupyter Book 2: Next-generation Tools for Creating Computational Narratives&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; A complete rewrite based on the MyST (Markedly Structured Text) engine. It produces semantic, machine-readable content that is much easier to cross-reference.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fparticleos-from-fedora-to-feast%2F&quot;&gt;&lt;strong&gt;ParticleOS, from Fedora to Feast: Stirring Traditional Distros into Immutable Delights&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Luca Boccassi showed how &lt;code&gt;systemd&lt;/code&gt; and &lt;code&gt;mkosi&lt;/code&gt; are changing OS building, creating a fully immutable, signed, and verifiable image.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwhat-do-we-mean-sovereign-ai%2F&quot;&gt;&lt;strong&gt;What do we mean when we say Sovereign AI?&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; Katharine Jarmul explained that true “Sovereign AI” is not just about where the model is hosted, but having the full training data and code available to inspect.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-notable-tracks-and-talks&quot;&gt;Other Notable Tracks and Talks&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Research &amp;#x26; Science&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Frse-movement-uiuc%2F&quot;&gt;Research software engineering: a movement and its instantiation at the University of Illinois Urbana-Champaign&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fresearch-software-funding-models%2F&quot;&gt;Research software grant funding models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fbuilding-open-research-infrastructure%2F&quot;&gt;Building Open Research Infrastructure: Connecting the Lab Bench to Computational Analysis with RSpace &amp;#x26; Galaxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fharnessing-nix-for-bioinformatics%2F&quot;&gt;Building Everything with Nothing — Harnessing Nix for Bioinformatics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fgems-high-level-language%2F&quot;&gt;From Code to Models-as-Data: GEMS, a High-Level Language for Energy System Modelling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fopen-reproducible-ai-lmics%2F&quot;&gt;Building Open and Reproducible AI Practices for LMICs (and Beyond)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fcern-adaptyst%2F&quot;&gt;Towards unified full-stack performance analysis and automated computer system design at CERN with Adaptyst&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Foqtopus-quantum-toolchain%2F&quot;&gt;OQTOPUS: Open Quantum Toolchain for OPerators and USers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fskills-floss-developer%2F&quot;&gt;The Skills of a FLOSS Developer and Why They Are Important in Open Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Ftrusted-by-design%2F&quot;&gt;Trusted by design: set up your research software for community adoption&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Main Track &amp;#x26; Community&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fefficient-git-workflow%2F&quot;&gt;An Efficient Git Workflow For High-Stakes Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fkeep-open-source-open%2F&quot;&gt;How to keep Open Source open without leaving our communities open to threats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fstrategy-trusting-employer%2F&quot;&gt;Strategy for Trusting your Employer in Open Source: a Historical Approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fwho-pays-your-bills%2F&quot;&gt;Who Pays Your Bills? Sustainability, Community and Business: The Open Source Triangle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fnext-gen-postgres-contributors%2F&quot;&gt;Building the next generation of open source contributors — Lessons from 30 years of Postgres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Ffunding-europe-digital-infra%2F&quot;&gt;Funding Europe’s Open Digital Infrastructure: A Detailed Case for an EU Sovereign Tech Fund&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2F32-years-debian%2F&quot;&gt;32 years of Debian: how a do-ocracy keeps evolving&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;AI &amp;#x26; Machine Learning&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Flow-code-ai-agents%2F&quot;&gt;Drag, Drop, and Deploy: Low-Code AI Agents for Network Ops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fself-hosted-llms%2F&quot;&gt;From Infrastructure to Production: A Year of Self-Hosted LLMs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fai-security-monitoring%2F&quot;&gt;AI Security Monitoring: Detecting Threats Against Production ML Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fprevent-ai-garbage%2F&quot;&gt;How to Prevent Your AI from Returning Garbage: It Starts and Ends with Data Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fdeep-learning-snap%2F&quot;&gt;Deep Learning Demystified — Having Fun with Neural Networks in Snap!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Security, Databases &amp;#x26; Infrastructure&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fpost-quantum-cryptography%2F&quot;&gt;Demystifying Post-Quantum Cryptography: The Hybrid Approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Flook-ma-no-secrets%2F&quot;&gt;Look ma, no secrets! — bootstrapping cryptographic trust in my homelab using NixOS, UKIs, TPMs and SPIFFE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Freal-time-ai-rondb%2F&quot;&gt;Real-Time AI Powered by RonDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fduckdb-bike-share%2F&quot;&gt;Exploring time series bike share data with duckdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fopensearch-v3%2F&quot;&gt;OpenSearch v3: A New Era of Search Innovation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fsurf-research-cloud-oss%2F&quot;&gt;SURF Research Cloud is going OSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffosdem.org%2F2026%2Fschedule%2Fevent%2Fguix-container-images%2F&quot;&gt;Guix Container Images — and what you can do with them&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;booths-and-extra-notes&quot;&gt;Booths and Extra Notes&lt;/h3&gt;
&lt;p&gt;After hearing about sovereignty everywhere, I had lengthy chats with the folks from &lt;strong&gt;GitLab, NextCloud, LibreOffice, Forgejo&lt;/strong&gt;, and &lt;strong&gt;Codeberg&lt;/strong&gt; to learn about open-source office solutions and infrastructure. I also talked to someone from Germany who explained the government migration to Linux (see: &lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Fwww.zdnet.com%2Farticle%2Fanother-european-government-is-ditching-microsoft-for-linux%2F&quot;&gt;Yet another European government is ditching Microsoft for Linux&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I visited the &lt;strong&gt;Tor&lt;/strong&gt; stand, where you could get fancy stickers if you donated to help them fight censorship. The &lt;strong&gt;Free Software Foundation Europe (FSFE)&lt;/strong&gt; is also worth following closely as their goals are related to our own. Finally, I learned about &lt;a href=&quot;https://www.google.com/search?q=https%3A%2F%2Ffundingjs.org%2F&quot;&gt;&lt;strong&gt;funding.json&lt;/strong&gt;&lt;/a&gt;, a format to declare financial needs of projects in a machine-readable format.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/fosdem-2026-observations-and-key-takeawa-55dcce06.l9YVToEZ.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Bring Your Own Backend</title><link>https://blog.esciencecenter.nl/posts/2026-03-26---bring-your-own-backend</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-03-26---bring-your-own-backend</guid><description>&lt;p&gt;&lt;em&gt;A pattern for sustainable research software collaboration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;298&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-58215f84.C2jqj6wm_Z1sjKop.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image source &lt;a href=&quot;https://www.pnnl.gov/news-media/new-nationwide-modeling-points-widespread-racial-disparities-urban-heat-stress&quot;&gt;https://www.pnnl.gov/news-media/new-nationwide-modeling-points-widespread-racial-disparities-urban-heat-stress&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a research software engineer (RSE) working at the Netherlands eScience Center, I work on projects together with domain scientists at universities and research institutes.&lt;/p&gt;
&lt;p&gt;For example, currently I am working on the &lt;a href=&quot;https://research-software-directory.org/projects/urban-m4&quot;&gt;Urban-M4 project,&lt;/a&gt; where we are trying to improve a weather model by telling it the properties of buildings in a city. As part of this project, I built a web-based application called &lt;a href=&quot;https://github.com/Urban-M4/Urban-M5&quot;&gt;streetscapes-explorer&lt;/a&gt; to create, review and edit segmented street view images. My engineering colleagues and project partners worked on the machine learning models and data processing pipelines that powered the backend of the web application.&lt;/p&gt;
&lt;p&gt;But as the project neared its end, a familiar worry crept in: &lt;em&gt;what happens after I leave?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-sustainability-problem&quot;&gt;The sustainability problem&lt;/h2&gt;
&lt;p&gt;The project partners are first and foremost domain scientists. They have the expertise and time to maintain a Python backend — updating dependencies, fixing bugs, evolving their data processing pipelines. But maintaining a highly interactive frontend written in TypeScript, with its constantly shifting JavaScript ecosystem, build tools, and UI frameworks, is a different story. That’s not where their expertise or time should go.&lt;/p&gt;
&lt;p&gt;A traditional monolithic application — with frontend and backend tightly coupled and deployed together — would force them to maintain both. They’d need to keep the server running, dependencies updated, security patches applied, and yes, understand that frontend code when something inevitably breaks. Given their constraints, this is a recipe for software rot and eventual abandonment.&lt;/p&gt;
&lt;p&gt;I needed a different approach. One where the frontend could essentially “freeze” after I left, requiring zero maintenance, while my partners could continue evolving their backend independently.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-bring-your-own-backend&quot;&gt;The solution: Bring Your Own Backend&lt;/h2&gt;
&lt;p&gt;The key insight was simple: decouple where the frontend is hosted from where the backend runs**.&lt;/p&gt;
&lt;p&gt;Instead of deploying the frontend and backend together on some server that my partners would need to maintain, I separated them completely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: As a single page web application using &lt;a href=&quot;https://react.dev/&quot;&gt;React framework&lt;/a&gt;. Hosted as static files on &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; — zero maintenance, free hosting, always available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Runs on my Users or partners’ own machines, under their full control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The magic that connects them? A URL query parameter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;607&quot; height=&quot;717&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-f8659c4d.BLuW3jQh_2eE4Yn.webp&quot; srcset=&quot;&quot;&gt;
The main idea, in a nutshell&lt;/p&gt;
&lt;h2 id=&quot;the-magic-url-based-backend-configuration&quot;&gt;The Magic: URL-based backend configuration&lt;/h2&gt;
&lt;p&gt;Here’s the core pattern. The frontend reads the backend URL from the query string:&lt;/p&gt;
&lt;p&gt;export function App() {**  const backend = new URLSearchParams(location.search).get(‘backend’);
if (!backend) {
return &amp;#x3C;BackendForm /&gt;;
}
return &amp;#x3C;StreetscapesExplorer backend={backend} /&gt;;
}When someone visits the frontend without specifying a backend, they see a helpful form with instructions:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;324&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-eb41ae53.2lRmfhfe_zxNKF.webp&quot; srcset=&quot;&quot;&gt;
When the frontend is unable to connect to the specified backend, it shows an error message with troubleshooting tips:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;547&quot; height=&quot;113&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-cdf89285.BWF2Lzc__Z1qVv8L.webp&quot; srcset=&quot;&quot;&gt;
The workflow becomes simply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user starts their backend locally&lt;/li&gt;
&lt;li&gt;A user visits the frontend URL with &lt;code&gt;?backend=http://localhost:5000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The frontend connects to their local backend&lt;/li&gt;
&lt;li&gt;All data stays on their machine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No rebuilds. No redeployments. No complex configuration. Just a URL parameter.&lt;/p&gt;
&lt;h2 id=&quot;keeping-it-simple-for-project-partners&quot;&gt;Keeping it simple for project partners&lt;/h2&gt;
&lt;p&gt;For this pattern to work after I leave, the backend needs to be dead simple to run.&lt;/p&gt;
&lt;p&gt;from dataclasses import dataclass, field
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware&lt;/p&gt;
&lt;p&gt;app = FastAPI()Web browsers do not like the frontend and backend to be at different URLs. For this in the backend we need to enable &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;CORS&lt;/a&gt; like so:&lt;/p&gt;
&lt;p&gt;app.add_middleware(
CORSMiddleware,
allow_origins=[&quot;&lt;em&gt;&quot;],
allow_methods=[&quot;&lt;/em&gt;&quot;],
)Then anyone can simply write a decorated and type annotated Python function to define an API endpoint:&lt;/p&gt;
&lt;p&gt;@dataclass
class FilterParams(Bbox):
ratings: list[int] = Field(default=[])&lt;/p&gt;
&lt;p&gt;@dataclass
class Image:
id: str
url: str
lat: float
lon: float
@app.get(“/images”)
async def fetch_images(filter: Annotated[FilterParams, Query()]) -&gt; list[Image]
# … implementationAnd to make it even more user-friendly, the backend prints a clickable link to the frontend on startup:&lt;/p&gt;
&lt;p&gt;def main() -&gt; None:
url = “&lt;a href=&quot;https://urban-m4.github.io/Urban-M5/?backend=http://localhost:8000&quot;&gt;https://urban-m4.github.io/Urban-M5/?backend=http://localhost:8000&lt;/a&gt;”
print(f”Waiting for the streetscapes-explorer to start…”)
print(f”Goto {url}”)
print(“(Press CTRL+C to quit)”)
uvicorn.run(app, host=“0.0.0.0”, port=8000)&lt;/p&gt;
&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == “&lt;strong&gt;main&lt;/strong&gt;”:
main()If you’re feeling more helpful you can use &lt;a href=&quot;https://docs.python.org/3/library/webbrowser.html#webbrowser.open&quot;&gt;webbrowser.open(url)&lt;/a&gt; to open the URL automatically in the user’s default browser.&lt;/p&gt;
&lt;h2 id=&quot;the-contract-openapi-as-the-bridge&quot;&gt;The contract: OpenAPI as the bridge&lt;/h2&gt;
&lt;p&gt;The frontend and backend need to agree on an API contract. Rather than maintaining documentation that inevitably drifts from reality, I used &lt;a href=&quot;https://www.openapis.org/&quot;&gt;OpenAPI&lt;/a&gt; as the single source of truth.&lt;/p&gt;
&lt;p&gt;FastAPI automatically generates an OpenAPI specification from the Python code. I then use &lt;a href=&quot;https://openapi-ts.dev/introduction&quot;&gt;OpenAPI TypeScript&lt;/a&gt; to generate TypeScript types:&lt;/p&gt;
&lt;p&gt;openapi-typescript &lt;a href=&quot;http://localhost:5000/openapi.json&quot;&gt;http://localhost:5000/openapi.json&lt;/a&gt; -o ./src/lib/streetscapes-api.tsThe frontend then makes type-safe API calls:&lt;/p&gt;
&lt;p&gt;import createClient from ‘openapi-fetch’;
import type { paths } from ’./lib/streetscapes-api’;&lt;/p&gt;
&lt;p&gt;function StreetscapesExplorer({backend}: { backend: string }) {
const client = createClient&amp;#x3C;paths&gt;({ baseUrl: backend });
const { data = [], error } = await client.GET(‘/images’, {
params: { query: { rating: [4, 5] } }
});
return (
&amp;#x3C;div&gt;
{error &amp;#x26;&amp;#x26; &amp;#x3C;div&gt;Error: {error.message}&amp;#x3C;/div&gt;}
{data.map(image =&gt; (
&amp;#x3C;img key={image.id} src={image.url} alt={&lt;code&gt;Image ${image.id}&lt;/code&gt;} /&gt;
))}
{/* … rest of the app like map view */}
&amp;#x3C;/div&gt;
);
};This gives us compile-time safety: if my partners change the API contract, the TypeScript compiler will catch any mismatches when regenerating the types.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out-yourself&quot;&gt;Try it out yourself&lt;/h2&gt;
&lt;p&gt;I made a minimal example of this pattern with a &lt;a href=&quot;https://sverhoeven.github.io/byob-todo-frontend/&quot;&gt;simple TODO application&lt;/a&gt;. To use follow the instructions to run the backend locally.&lt;/p&gt;
&lt;p&gt;The source code is available at &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-frontend&quot;&gt;byob-todo-frontend&lt;/a&gt; and &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-backend&quot;&gt;byob-todo-backend&lt;/a&gt;. In the frontend I used SolidJS and bun to keep the frontend light. In the backend I used uv and inline dependencies to keep the backend easy to run.&lt;/p&gt;
&lt;h2 id=&quot;when-to-use-byob&quot;&gt;When to use BYOB&lt;/h2&gt;
&lt;p&gt;This pattern isn’t for every project, but it shines when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Different expertise levels**: Frontend specialists work with domain experts who prefer other languages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data sensitivity&lt;/strong&gt;: Users need to keep data on their own machines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited resources&lt;/strong&gt;: No budget for ongoing server maintenance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaborative research&lt;/strong&gt;: Multiple groups might want to run their own backends&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The “Bring Your Own Backend” pattern turned what could have been abandoned software into a sustainable tool that my partners can use and evolve long after our collaboration ended. Sometimes the best code you write is the code others don’t have to maintain.&lt;/p&gt;
&lt;p&gt;This post was originally published at &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-frontend/tree/main/blog&quot;&gt;the author’s GitHub account&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;A pattern for sustainable research software collaboration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;298&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-58215f84.C2jqj6wm_Z1sjKop.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image source &lt;a href=&quot;https://www.pnnl.gov/news-media/new-nationwide-modeling-points-widespread-racial-disparities-urban-heat-stress&quot;&gt;https://www.pnnl.gov/news-media/new-nationwide-modeling-points-widespread-racial-disparities-urban-heat-stress&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a research software engineer (RSE) working at the Netherlands eScience Center, I work on projects together with domain scientists at universities and research institutes.&lt;/p&gt;
&lt;p&gt;For example, currently I am working on the &lt;a href=&quot;https://research-software-directory.org/projects/urban-m4&quot;&gt;Urban-M4 project,&lt;/a&gt; where we are trying to improve a weather model by telling it the properties of buildings in a city. As part of this project, I built a web-based application called &lt;a href=&quot;https://github.com/Urban-M4/Urban-M5&quot;&gt;streetscapes-explorer&lt;/a&gt; to create, review and edit segmented street view images. My engineering colleagues and project partners worked on the machine learning models and data processing pipelines that powered the backend of the web application.&lt;/p&gt;
&lt;p&gt;But as the project neared its end, a familiar worry crept in: &lt;em&gt;what happens after I leave?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-sustainability-problem&quot;&gt;The sustainability problem&lt;/h2&gt;
&lt;p&gt;The project partners are first and foremost domain scientists. They have the expertise and time to maintain a Python backend — updating dependencies, fixing bugs, evolving their data processing pipelines. But maintaining a highly interactive frontend written in TypeScript, with its constantly shifting JavaScript ecosystem, build tools, and UI frameworks, is a different story. That’s not where their expertise or time should go.&lt;/p&gt;
&lt;p&gt;A traditional monolithic application — with frontend and backend tightly coupled and deployed together — would force them to maintain both. They’d need to keep the server running, dependencies updated, security patches applied, and yes, understand that frontend code when something inevitably breaks. Given their constraints, this is a recipe for software rot and eventual abandonment.&lt;/p&gt;
&lt;p&gt;I needed a different approach. One where the frontend could essentially “freeze” after I left, requiring zero maintenance, while my partners could continue evolving their backend independently.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-bring-your-own-backend&quot;&gt;The solution: Bring Your Own Backend&lt;/h2&gt;
&lt;p&gt;The key insight was simple: decouple where the frontend is hosted from where the backend runs**.&lt;/p&gt;
&lt;p&gt;Instead of deploying the frontend and backend together on some server that my partners would need to maintain, I separated them completely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: As a single page web application using &lt;a href=&quot;https://react.dev/&quot;&gt;React framework&lt;/a&gt;. Hosted as static files on &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; — zero maintenance, free hosting, always available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Runs on my Users or partners’ own machines, under their full control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The magic that connects them? A URL query parameter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;607&quot; height=&quot;717&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-f8659c4d.BLuW3jQh_2eE4Yn.webp&quot; srcset=&quot;&quot;&gt;
The main idea, in a nutshell&lt;/p&gt;
&lt;h2 id=&quot;the-magic-url-based-backend-configuration&quot;&gt;The Magic: URL-based backend configuration&lt;/h2&gt;
&lt;p&gt;Here’s the core pattern. The frontend reads the backend URL from the query string:&lt;/p&gt;
&lt;p&gt;export function App() {**  const backend = new URLSearchParams(location.search).get(‘backend’);
if (!backend) {
return &amp;#x3C;BackendForm /&gt;;
}
return &amp;#x3C;StreetscapesExplorer backend={backend} /&gt;;
}When someone visits the frontend without specifying a backend, they see a helpful form with instructions:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;324&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-eb41ae53.2lRmfhfe_zxNKF.webp&quot; srcset=&quot;&quot;&gt;
When the frontend is unable to connect to the specified backend, it shows an error message with troubleshooting tips:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bring Your Own Backend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;547&quot; height=&quot;113&quot; src=&quot;https://blog.esciencecenter.nl/_astro/bring-your-own-backend-cdf89285.BWF2Lzc__Z1qVv8L.webp&quot; srcset=&quot;&quot;&gt;
The workflow becomes simply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user starts their backend locally&lt;/li&gt;
&lt;li&gt;A user visits the frontend URL with &lt;code&gt;?backend=http://localhost:5000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The frontend connects to their local backend&lt;/li&gt;
&lt;li&gt;All data stays on their machine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No rebuilds. No redeployments. No complex configuration. Just a URL parameter.&lt;/p&gt;
&lt;h2 id=&quot;keeping-it-simple-for-project-partners&quot;&gt;Keeping it simple for project partners&lt;/h2&gt;
&lt;p&gt;For this pattern to work after I leave, the backend needs to be dead simple to run.&lt;/p&gt;
&lt;p&gt;from dataclasses import dataclass, field
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware&lt;/p&gt;
&lt;p&gt;app = FastAPI()Web browsers do not like the frontend and backend to be at different URLs. For this in the backend we need to enable &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;CORS&lt;/a&gt; like so:&lt;/p&gt;
&lt;p&gt;app.add_middleware(
CORSMiddleware,
allow_origins=[&quot;&lt;em&gt;&quot;],
allow_methods=[&quot;&lt;/em&gt;&quot;],
)Then anyone can simply write a decorated and type annotated Python function to define an API endpoint:&lt;/p&gt;
&lt;p&gt;@dataclass
class FilterParams(Bbox):
ratings: list[int] = Field(default=[])&lt;/p&gt;
&lt;p&gt;@dataclass
class Image:
id: str
url: str
lat: float
lon: float
@app.get(“/images”)
async def fetch_images(filter: Annotated[FilterParams, Query()]) -&gt; list[Image]
# … implementationAnd to make it even more user-friendly, the backend prints a clickable link to the frontend on startup:&lt;/p&gt;
&lt;p&gt;def main() -&gt; None:
url = “&lt;a href=&quot;https://urban-m4.github.io/Urban-M5/?backend=http://localhost:8000&quot;&gt;https://urban-m4.github.io/Urban-M5/?backend=http://localhost:8000&lt;/a&gt;”
print(f”Waiting for the streetscapes-explorer to start…”)
print(f”Goto {url}”)
print(“(Press CTRL+C to quit)”)
uvicorn.run(app, host=“0.0.0.0”, port=8000)&lt;/p&gt;
&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == “&lt;strong&gt;main&lt;/strong&gt;”:
main()If you’re feeling more helpful you can use &lt;a href=&quot;https://docs.python.org/3/library/webbrowser.html#webbrowser.open&quot;&gt;webbrowser.open(url)&lt;/a&gt; to open the URL automatically in the user’s default browser.&lt;/p&gt;
&lt;h2 id=&quot;the-contract-openapi-as-the-bridge&quot;&gt;The contract: OpenAPI as the bridge&lt;/h2&gt;
&lt;p&gt;The frontend and backend need to agree on an API contract. Rather than maintaining documentation that inevitably drifts from reality, I used &lt;a href=&quot;https://www.openapis.org/&quot;&gt;OpenAPI&lt;/a&gt; as the single source of truth.&lt;/p&gt;
&lt;p&gt;FastAPI automatically generates an OpenAPI specification from the Python code. I then use &lt;a href=&quot;https://openapi-ts.dev/introduction&quot;&gt;OpenAPI TypeScript&lt;/a&gt; to generate TypeScript types:&lt;/p&gt;
&lt;p&gt;openapi-typescript &lt;a href=&quot;http://localhost:5000/openapi.json&quot;&gt;http://localhost:5000/openapi.json&lt;/a&gt; -o ./src/lib/streetscapes-api.tsThe frontend then makes type-safe API calls:&lt;/p&gt;
&lt;p&gt;import createClient from ‘openapi-fetch’;
import type { paths } from ’./lib/streetscapes-api’;&lt;/p&gt;
&lt;p&gt;function StreetscapesExplorer({backend}: { backend: string }) {
const client = createClient&amp;#x3C;paths&gt;({ baseUrl: backend });
const { data = [], error } = await client.GET(‘/images’, {
params: { query: { rating: [4, 5] } }
});
return (
&amp;#x3C;div&gt;
{error &amp;#x26;&amp;#x26; &amp;#x3C;div&gt;Error: {error.message}&amp;#x3C;/div&gt;}
{data.map(image =&gt; (
&amp;#x3C;img key={image.id} src={image.url} alt={&lt;code&gt;Image ${image.id}&lt;/code&gt;} /&gt;
))}
{/* … rest of the app like map view */}
&amp;#x3C;/div&gt;
);
};This gives us compile-time safety: if my partners change the API contract, the TypeScript compiler will catch any mismatches when regenerating the types.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out-yourself&quot;&gt;Try it out yourself&lt;/h2&gt;
&lt;p&gt;I made a minimal example of this pattern with a &lt;a href=&quot;https://sverhoeven.github.io/byob-todo-frontend/&quot;&gt;simple TODO application&lt;/a&gt;. To use follow the instructions to run the backend locally.&lt;/p&gt;
&lt;p&gt;The source code is available at &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-frontend&quot;&gt;byob-todo-frontend&lt;/a&gt; and &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-backend&quot;&gt;byob-todo-backend&lt;/a&gt;. In the frontend I used SolidJS and bun to keep the frontend light. In the backend I used uv and inline dependencies to keep the backend easy to run.&lt;/p&gt;
&lt;h2 id=&quot;when-to-use-byob&quot;&gt;When to use BYOB&lt;/h2&gt;
&lt;p&gt;This pattern isn’t for every project, but it shines when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Different expertise levels**: Frontend specialists work with domain experts who prefer other languages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data sensitivity&lt;/strong&gt;: Users need to keep data on their own machines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited resources&lt;/strong&gt;: No budget for ongoing server maintenance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaborative research&lt;/strong&gt;: Multiple groups might want to run their own backends&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The “Bring Your Own Backend” pattern turned what could have been abandoned software into a sustainable tool that my partners can use and evolve long after our collaboration ended. Sometimes the best code you write is the code others don’t have to maintain.&lt;/p&gt;
&lt;p&gt;This post was originally published at &lt;a href=&quot;https://github.com/sverhoeven/byob-todo-frontend/tree/main/blog&quot;&gt;the author’s GitHub account&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/bring-your-own-backend-f8659c4d.BLuW3jQh.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Give Me Data, Yesterday</title><link>https://blog.esciencecenter.nl/posts/2026-03-18---give-me-data-yesterday</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-03-18---give-me-data-yesterday</guid><description>&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-bd7575b9.DXvMDkzN_Z1TbF5C.webp&quot; srcset=&quot;&quot;&gt;
I want this data, and I want it yesterday!&lt;em&gt;This post is adapted, with the &lt;em&gt;&lt;a href=&quot;https://ole-mn.medium.com/&quot;&gt;&lt;em&gt;author&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;’s permission and collaboration, from &lt;em&gt;&lt;a href=&quot;https://ole.mn/posts/2026-02-data-cache/&quot;&gt;&lt;em&gt;this post&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in his personal blog.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a quest. A quest for the right tool for the right job, for usability, and performance. We will torture databases, run tens of thousands of benchmarks and conjure charts, numbers, and tables. Because science. 🧑‍🔬&lt;/p&gt;
&lt;p&gt;But first, some background.&lt;/p&gt;
&lt;p&gt;The patient is the package search program &lt;code&gt;[nps](https://github.com/OleMussmann/nps/)&lt;/code&gt;, which provides information about all packages the &lt;code&gt;[nix](https://nixos.org/)&lt;/code&gt; package manager has to offer. What’s the patient’s complaint? &lt;code&gt;nps&lt;/code&gt; needs a better database and a better way to update its data.&lt;/p&gt;
&lt;p&gt;Erm, &lt;code&gt;nix&lt;/code&gt;? Never heard of it? It’s kinda special. Unlike &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;pacman&lt;/code&gt;, or their siblings, it is declarative, reproducible and reliable. To top it off, it has a &lt;a href=&quot;https://repology.org/repositories/graphs&quot;&gt;gigantic library&lt;/a&gt;. If you don’t know what that means, no worries! Here’s a primer.&lt;/p&gt;
&lt;h2 id=&quot;nix-whats-that&quot;&gt;&lt;code&gt;nix&lt;/code&gt;? What’s That?&lt;/h2&gt;
&lt;p&gt;How do you set up your operating system? You install, for example, Ubuntu. Then you install a bunch of packages. You configure them. Then you set the wallpaper, the color scheme, the fonts, and make yourself at home. And if you set up a new system, you start again from square one. This whole process is &lt;em&gt;procedural&lt;/em&gt;, you follow one step after another. If you re-do all your steps again, you get the same result; and any changes to the recipe will result in a different outcome.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;nix&lt;/code&gt;, you describe the end state you want to have, and &lt;code&gt;nix&lt;/code&gt; will build and set up the system like you describe. Reliably. Reproducibly. &lt;code&gt;nix&lt;/code&gt; is &lt;em&gt;declarative&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Worry not, you can still apply tweaks and modifications. The desired end state including all customizations can be described in a single configuration file (keep it simple), or a set of files (make it modular). Let’s call this configuration file a “flake”. ❄️ Throw &lt;code&gt;git&lt;/code&gt; at this flake file and now you can jump between different versions on demand.&lt;/p&gt;
&lt;p&gt;If you share your flake with someone else, they can re-create the exact environment on their system. This is great for collaborative development! Runs on your computer? Runs everywhere. You can run other people’s software &lt;em&gt;without installing&lt;/em&gt;, and others can run yours. For even more portability, you can create Docker containers, virtual machines, or even a bootable ISO from your project.&lt;/p&gt;
&lt;p&gt;Sounds like magic? It comes close.&lt;/p&gt;
&lt;p&gt;Current gotchas include a lack of broad adoption, a steep learning curve for the &lt;code&gt;nix&lt;/code&gt; language, as well as not great (but improving) documentation. And, well, a distinct lack of a native, fast, offline program for searching packages.&lt;/p&gt;
&lt;h2 id=&quot;paper-cuts&quot;&gt;Paper Cuts&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt;’s usability has, let’s say, still room for improvement. Prime example: how to find out which packages one can install. What do these packages do exactly, and what version do I get? The &lt;a href=&quot;https://wiki.nixos.org/wiki/Searching_packages&quot;&gt;recommended way&lt;/a&gt; is – drumroll – a website: &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;search.nixos.org/packages&lt;/a&gt;. It’s fast, comprehensive, and detailed. It works well.&lt;/p&gt;
&lt;p&gt;But it’s a website.&lt;/p&gt;
&lt;p&gt;When I’m pondering about installing packages, I’m not staring at a browser. I’m in the terminal. I want to have the equivalent of &lt;code&gt;apt search&lt;/code&gt; or &lt;code&gt;pacman -Ss&lt;/code&gt;¹.&lt;/p&gt;
&lt;p&gt;There are some wonderful CLI search programs out there², but they hook into the ElasticSearch database powering the backend of &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;search.nixos.org/packages&lt;/a&gt;. This means that you need to be online to get any package information, and (minor quibble, I know) it takes a bit for the information to appear on your screen.&lt;/p&gt;
&lt;h2 id=&quot;nps&quot;&gt;&lt;code&gt;nps&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I built the &lt;a href=&quot;https://github.com/OleMussmann/nps/&quot;&gt;Nix Package Search &lt;/a&gt;&lt;code&gt;[nps](https://github.com/OleMussmann/nps/)&lt;/code&gt; program to do my part to make &lt;code&gt;nix&lt;/code&gt; more user-friendly. &lt;code&gt;nps&lt;/code&gt; stores the package information locally, searches this cache, and presents the result – color-coded and sanely sorted. It works offline. It’s fast. It’s beautiful. Yeah, yeah, I know, I’m biased. Try it for yourself, though! Remember, you can run it without installing.&lt;/p&gt;
&lt;p&gt;Lately, &lt;a href=&quot;https://github.com/kevb1973&quot;&gt;kevb1973&lt;/a&gt; asked me to &lt;a href=&quot;https://github.com/OleMussmann/nps/issues/25&quot;&gt;provide more package information&lt;/a&gt; in the (dense) output that &lt;code&gt;nps&lt;/code&gt; provides. It’s a great idea and would increase the utility that &lt;code&gt;nps&lt;/code&gt; provides! Unfortunately, this is not something I can just bolt on to the existing program. Let’s have a look at the moving parts of &lt;code&gt;nps&lt;/code&gt; to understand why.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;Ok, architecture is a big word. Let me run by you how &lt;code&gt;nps&lt;/code&gt; currently works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;nix search nixpkgs ^&lt;/code&gt; – get all information for “all” packages.&lt;/li&gt;
&lt;li&gt;Create a text file with package names, versions, and descriptions and store them locally.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep&lt;/code&gt; through the text file (yes, it’s that low-tech) to find matches.&lt;/li&gt;
&lt;li&gt;Sort matches nicely into exact hits (searching for “avahi” matches package &lt;code&gt;avahi&lt;/code&gt;), direct hits (finds packages starting with “avahi”, e.g. &lt;code&gt;avahi-compat&lt;/code&gt;) and indirect hits (“avahi” appears anywhere in the package name or description).&lt;/li&gt;
&lt;li&gt;Create columns for better readability.&lt;/li&gt;
&lt;li&gt;Add a lick of paint to color-code the different types of matches.&lt;/li&gt;
&lt;li&gt;Print the result.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The issue: the data is stored as one row per package. Adding more information to each package row will make it harder for &lt;code&gt;grep&lt;/code&gt; to find the packages you’re looking for. This looks like a job for a “proper” database now. But which one? There’s plenty of cool tech out there, but which would be the “best” one for this use case?&lt;/p&gt;
&lt;h2 id=&quot;database-candidate-boundary-conditions&quot;&gt;Database Candidate Boundary Conditions&lt;/h2&gt;
&lt;p&gt;Alright, before we dive in, let’s define a few corner stones.&lt;/p&gt;
&lt;h3 id=&quot;data-source&quot;&gt;Data Source&lt;/h3&gt;
&lt;p&gt;Remember the &lt;code&gt;nix search&lt;/code&gt; command from above? It does not actually find “all” packages, &lt;a href=&quot;https://search.nixos.org&quot;&gt;https://search.nixos.org&lt;/a&gt; finds significantly more³. Why? No idea. Also, &lt;code&gt;nix search&lt;/code&gt; supplies only the package name, version, and description. No other information. Not great. Another aspect that’s missing is that packages might provide a differently named executable: you install the package &lt;code&gt;neovim&lt;/code&gt; and use the executable &lt;code&gt;nvim&lt;/code&gt;; some packages even provide multiple different executables. &lt;code&gt;nix search&lt;/code&gt; can’t find those.&lt;/p&gt;
&lt;p&gt;The data needs to come from a better source.&lt;/p&gt;
&lt;p&gt;The ElasticSearch backend is a good choice, but it’s meant to be queried, not downloaded. This means we have to scrape it in its entirety first.&lt;/p&gt;
&lt;p&gt;Setting up a project that does the scraping and regularly builds a cache that is usable by (a future version of) &lt;code&gt;nps&lt;/code&gt; is a task that goes beyond the scope of this post. Let’s assume for now that we have the data available, and we can squish (very scientific term here) it into any shape or form that we need for querying.&lt;/p&gt;
&lt;h3 id=&quot;substring-matching&quot;&gt;Substring Matching&lt;/h3&gt;
&lt;p&gt;Subwhat? A substring is a part of a string: “crow” is a substring of “miCROWave”. It can be anywhere in a string, beginning, middle, or end. When searching for “nvim” I want to find &lt;code&gt;nvim&lt;/code&gt; (duh!), as well as &lt;code&gt;nvimpager&lt;/code&gt; “use neovim as pager”, and &lt;code&gt;gnvim&lt;/code&gt; “GUI for neovim, without any web bloat”. As most databases are specialized in retrieving “exact” matches, substring matching might take some convincing.&lt;/p&gt;
&lt;h3 id=&quot;query-time&quot;&gt;Query Time&lt;/h3&gt;
&lt;p&gt;I want future &lt;code&gt;nps&lt;/code&gt; to stay fast. I’m happy with the responsiveness of the current implementation. To get a feeling for this, using &lt;code&gt;nps&lt;/code&gt; to search for the package &lt;code&gt;nps&lt;/code&gt; takes about 6ms on my desktop – so let’s take that as a baseline. If the pure data retrieval of the database candidates takes longer than current-&lt;code&gt;nps&lt;/code&gt;, then that’s a red flag, since sorting, coloring, etc. will take some extra time on top of that.&lt;/p&gt;
&lt;p&gt;Quick Cold Start**&lt;/p&gt;
&lt;p&gt;Related to “Query Time”: many “serious” databases are designed to run as a service; that makes querying fast, but you need something running in the background all the time. We don’t want that. Instead, we have a single program that starts up, queries a database, prints stuff, and then quits. This excludes many of the usual suspects like MySQL and its colleagues.&lt;/p&gt;
&lt;h3 id=&quot;data-amount&quot;&gt;Data Amount&lt;/h3&gt;
&lt;p&gt;The current data amount is about 8.5 Mb of package information and metadata for one &lt;code&gt;nixpkgs&lt;/code&gt; channel. The future, more detailed one (also including a long description, project URL and location within the &lt;code&gt;nixpkgs&lt;/code&gt; repo) would be 26 Mb of plain text. For three NixOS channels (“unstable”, “current stable”, “previous stable”), this would be about 80 Mb. While compression can bring this down a bit, some databases need to index their database to be able to search quickly; this will increase the data amount again. How much? That depends on the database used.&lt;/p&gt;
&lt;p&gt;The increased data amount is defensible when taking into account that one could regularly download the &lt;em&gt;incremental changes&lt;/em&gt; instead of the whole database for refreshing the cache.&lt;/p&gt;
&lt;p&gt;Yes, this is pretty hand-wavy for now. We’ll get more concrete about this later.&lt;/p&gt;
&lt;h3 id=&quot;memory-usage&quot;&gt;Memory Usage&lt;/h3&gt;
&lt;p&gt;A bit less crucial than the above, I’d like to use as little RAM as possible during the search. &lt;code&gt;nps&lt;/code&gt; is a guest on your machine and it should use only as much of your resources as needed.&lt;/p&gt;
&lt;p&gt;Many databases (as well as the good ol’ &lt;code&gt;grep&lt;/code&gt;) don’t load the whole data into memory before searching, they “crawl” through the data and drop the parts they have already used. I’d set that as a “nice to have”.&lt;/p&gt;
&lt;h2 id=&quot;database-candidates&quot;&gt;Database Candidates&lt;/h2&gt;
&lt;p&gt;First, let’s discuss the candidates and their structural strengths and weaknesses. We get to the hard numbers below, in the chapter &lt;a href=&quot;#37a0&quot;&gt;&lt;strong&gt;“Gimme Numbers!”&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;grep-a-text-file-&quot;&gt;&lt;code&gt;grep&lt;/code&gt; a Text File 🦖&lt;/h3&gt;
&lt;p&gt;Why change a working system? The old dinosaur &lt;code&gt;grep&lt;/code&gt; is fast. Really fast. We have the &lt;a href=&quot;https://www.gnu.org/software/grep/&quot;&gt;“GNU” flavor&lt;/a&gt; that runs on the command line, then there’s a &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;Rust implementation called &lt;/a&gt;&lt;code&gt;[ripgrep](https://github.com/BurntSushi/ripgrep)&lt;/code&gt;, and lastly the &lt;a href=&quot;https://docs.rs/grep/latest/grep/&quot;&gt;Rust crate called &lt;/a&gt;&lt;code&gt;[grep](https://docs.rs/grep/latest/grep/)&lt;/code&gt;, which is – despite the name – closer to &lt;code&gt;ripgrep&lt;/code&gt; than to &lt;code&gt;grep&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dial it up a notch. I’d like to see how just calling &lt;code&gt;grep&lt;/code&gt; or its cousin &lt;code&gt;ripgrep&lt;/code&gt; from the command line (equivalent to step 3. from &lt;a href=&quot;#architecture&quot;&gt;“Architecture”&lt;/a&gt;; we will label all those tests with the “CLI” suffix) compares to calling it from Rust and splitting the results (necessity for the “new” architecture). &lt;code&gt;ripgrep&lt;/code&gt; likes to work with streaming data, but we can’t do that if we want to form columns later. So what’s the overhead of the extra data mangling?&lt;/p&gt;
&lt;p&gt;That brings us to the following list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNU &lt;code&gt;grep&lt;/code&gt; (called from CLI, results &lt;em&gt;not&lt;/em&gt; split)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ripgrep&lt;/code&gt; (called from CLI, results &lt;em&gt;not&lt;/em&gt; split)&lt;/li&gt;
&lt;li&gt;GNU &lt;code&gt;grep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ripgrep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;li&gt;Rust crate &lt;code&gt;grep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;benefits&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Single file “database”&lt;/li&gt;
&lt;li&gt;Easy and good compression&lt;/li&gt;
&lt;li&gt;Trivial substring matching&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Extra finagling to only search certain parts of a line, yet still returning the whole row of data; in practice this means extra lines of code plus possibly a few extra gray hairs&lt;/li&gt;
&lt;li&gt;Incremental data updates are difficult&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sqlite-&quot;&gt;SQLite 🪶&lt;/h3&gt;
&lt;p&gt;The gold standard for “simple” databases. Scales less well for serious applications than MySQL (or MariaDB or whatever), but should be “good enough” for a few hundred thousand packages.&lt;/p&gt;
&lt;p&gt;We use trigram (N-gram with N=3)⁴search to achieve fast substring matching. This makes it, well, fast. But it also inflates the database size and ignores any search terms shorter than 3 characters. One &lt;em&gt;could&lt;/em&gt; check for search string length and use a different matching algorithm for shorter terms, but is that worth the effort?&lt;/p&gt;
&lt;h3 id=&quot;benefits-1&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Single file database&lt;/li&gt;
&lt;li&gt;Battle-tested and stable&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;li&gt;Incremental updates are trivial&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How compressible is an already compressed database?&lt;/li&gt;
&lt;li&gt;Needs indexing for fast substring matches, balancing database size vs performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-1&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tantivy-&quot;&gt;Tantivy 🐎&lt;/h3&gt;
&lt;p&gt;I sparred with ChatGPT about which database to use, and it was very enthusiastic about Tantivy — we will see later if that was a good idea or not. It is designed for a quick cold-start and fast data retrieval, sounds like a match to me! Tantivy stores data in several files and has a &lt;code&gt;meta.json&lt;/code&gt; file to figure out what’s what.&lt;/p&gt;
&lt;p&gt;A quirk: technically, you can’t delete already stored data. Instead, you add a “delete” file that ignores entries and you can delete storage files that eventually become obsolete. Still, incremental updates should not be too hard this way. Every once in a while one would need to re-download the whole thing once the local index grew too large with all those “delete” files.&lt;/p&gt;
&lt;p&gt;Same as with &lt;code&gt;SQLite&lt;/code&gt;, we use trigram matching for speed, with the same benefits and drawbacks.&lt;/p&gt;
&lt;h3 id=&quot;benefits-2&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pretty much designed for this purpose&lt;/li&gt;
&lt;li&gt;Incremental updates are easy&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs-1&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The database is a folder with multiple files&lt;/li&gt;
&lt;li&gt;Needs indexing for fast substring matches, balancing database size vs performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-2&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Incremental updates do need a strategy, with an occasional fresh download of the whole database&lt;/li&gt;
&lt;li&gt;The many files might take some time to read, benchmarks will tell if that’s an issue&lt;/li&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;duckdb-&quot;&gt;DuckDB 🦆&lt;/h3&gt;
&lt;p&gt;Completing our zoo is the new duckling on the block. DuckDB sports rad analytics which might be handy for retrieving already correctly sorted search results.&lt;/p&gt;
&lt;p&gt;However, DuckDB can’t do N-grams. &lt;a href=&quot;https://github.com/duckdb/duckdb/discussions/16071&quot;&gt;Yet&lt;/a&gt;. Sad quack.&lt;/p&gt;
&lt;p&gt;What can we do instead?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Benchmark the slower, standard way of case-insensitive substring matching, called &lt;code&gt;ILIKE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Benchmark the slower, other way of case-insensitive substring matching with regular expressions: &lt;code&gt;regex&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Who needs built-in N-gram indexing when Gemini can build one (let’s call it &lt;code&gt;trigram&lt;/code&gt;) for you? We will soon find out if that’s a good idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;benefits-3&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ducks are cool&lt;/li&gt;
&lt;li&gt;Single file database&lt;/li&gt;
&lt;li&gt;Supports incremental updates&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs-2&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Would the analytics work for proper sorting?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-3&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No built-in N-gram indexing for fast substring matching, uh oh!&lt;/li&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;benchmarking-boundary-conditions&quot;&gt;Benchmarking Boundary Conditions&lt;/h2&gt;
&lt;p&gt;We will be testing for a lot of things at once, here’s a break-down.&lt;/p&gt;
&lt;h3 id=&quot;parameters&quot;&gt;Parameters&lt;/h3&gt;
&lt;p&gt;We are searching for four different search terms with increasing number of matches. This should give us enough data points to make out a trend.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“nps” (21 matches)&lt;/li&gt;
&lt;li&gt;“nvim” (1301 matches)&lt;/li&gt;
&lt;li&gt;“python” (21123 matches)&lt;/li&gt;
&lt;li&gt;“e” (131567 matches, almost the whole database)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;data-types&quot;&gt;Data Types&lt;/h3&gt;
&lt;p&gt;To be able to compare database performances with the current implementation of &lt;code&gt;nps&lt;/code&gt; we start with a “minimal” database, containing the package name, version, and short description. This mirrors the current implementation of &lt;code&gt;nps&lt;/code&gt; and allows for comparisons.&lt;/p&gt;
&lt;p&gt;The entire “minimal” data for the &lt;code&gt;abcde&lt;/code&gt; package look like this:&lt;/p&gt;
&lt;p&gt;abcde   2.9.3   Command-line audio CD ripperThen we try a “detailed” database, containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;package name&lt;/li&gt;
&lt;li&gt;executable names (which might be different than the package name)&lt;/li&gt;
&lt;li&gt;version&lt;/li&gt;
&lt;li&gt;description (short)&lt;/li&gt;
&lt;li&gt;description (long)&lt;/li&gt;
&lt;li&gt;homepage URL&lt;/li&gt;
&lt;li&gt;and the URL to the package in the &lt;code&gt;nixpkgs&lt;/code&gt; repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Formatted, the information for the same package could look like this:&lt;/p&gt;
&lt;p&gt;abcde [abcde-musicbrainz-tool, abcde, cddb-tool]  2.9.3&lt;/p&gt;
&lt;p&gt;Command-line audio CD ripper
abcde is a front-end command-line utility (actually, a shell
script) that grabs tracks off a CD, encodes them to Ogg/Vorbis,
MP3, FLAC, Ogg/Speex and/or MPP/MP+ (Musepack) format, and tags
them, all in one go.
Project URL: &lt;a href=&quot;http://abcde.einval.com/wiki/&quot;&gt;http://abcde.einval.com/wiki/&lt;/a&gt;
Nixpkgs URL: &lt;a href=&quot;https://github.com/NixOS/nixpkgs/pkgs/by-name/ab/abcde/package.nix:83Off-topic&quot;&gt;https://github.com/NixOS/nixpkgs/pkgs/by-name/ab/abcde/package.nix:83Off-topic&lt;/a&gt;: this project’s website gives me heavy 90’s vibes, woah.&lt;/p&gt;
&lt;h3 id=&quot;hyperfine-engage&quot;&gt;&lt;code&gt;hyperfine&lt;/code&gt;, Engage&lt;/h3&gt;
&lt;p&gt;If you counted correctly, you should have four search terms, two data types, and eleven search approaches. We are skipping some combinations, e.g. “detailed search” is not supported on the O.G. &lt;code&gt;nps&lt;/code&gt;, and Tantivy and DuckDB can’t find anything shorter than 3 characters. In the end we have more than 80 distinctly different benchmarks. Some are run from Rust, some from the command line. To be able to compare them, we benchmark them with &lt;code&gt;[hyperfine](https://github.com/rmlmcfadden/hyperfine)&lt;/code&gt;. Bonus: on top of min-, max-, mean-, and median-runtimes we also get the memory usage of the runs. Nice!&lt;/p&gt;
&lt;p&gt;This is what a typical run on the command line looks like:&lt;/p&gt;
&lt;p&gt;$ hyperfine ‘nps neovim’
Benchmark 1: nps neovim
Time (mean ± σ):       6.0 ms ±   0.4 ms    [User: 1.5 ms, System: 4.4 ms]
Range (min … max):     5.0 ms …   7.3 ms    351 runsEven better, we can also get the results in JSON format. Unfortunately, this also means that it’s written to file.&lt;/p&gt;
&lt;p&gt;Sigh. So we have to read in that file to get the data we need. On the plus side, the JSON detour makes sure we don’t have any unforeseen hick-ups with data parsing, which could have happened if we wanted to retrieve the runtimes via regex from the output shown above.&lt;/p&gt;
&lt;p&gt;The JSON data looks like this:&lt;/p&gt;
&lt;p&gt;{
“results”: [
{
“command”: “nps neovim”,
“mean”: 0.006715249454725274,
“stddev”: 0.0026061538013605248,
“median”: 0.0065737821799999995,
“user”: 0.001504577142857143,
“system”: 0.005087126153846152,
“min”: 0.00505421018,
“max”: 0.03085960318,
“times”: [
0.03085960318,
0.00686827018,
…
],
“memory_usage_byte”: [
12791808,
12791808,
…
],
“exit_codes”: [
0,
0,
…
]
}
]
}For benchmarking, we are using &lt;code&gt;hyperfine&lt;/code&gt; the following way:&lt;/p&gt;
&lt;p&gt;hyperfine —shell=none —warmup=5 —export-json [filename] ‘COMMAND’Break-down of the moving parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--shell=none&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to, well, not start any shell. This shaves a few milliseconds off the benchmark score and allows for easier runtime comparisons.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--warmup=5&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to run &lt;code&gt;COMMAND&lt;/code&gt; 5 times before actually measuring the runtime. This makes sure that all files that are read are properly cached first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--export-json [filename]&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to write out the data in JSON format.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;gimme-numbers&quot;&gt;Gimme Numbers&lt;/h2&gt;
&lt;p&gt;Now to the fun part. Buckle up, it’s finally benchmark time! With repetitions, we have &gt;40.000 data retrieval runs.&lt;/p&gt;
&lt;p&gt;Below are all the tests we run against the above parameters and data types. To be able to compare apples to apples, these are the steps each approach conducts, unless noted otherwise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read in the data,&lt;/li&gt;
&lt;li&gt;Find package matches in the whole row (minimal databases) , or in the fields “package name”, “executable names”, and “package description (short)” (detailed databases),&lt;/li&gt;
&lt;li&gt;Split the matched data if necessary, so we have access to the “fields” of the data row,&lt;/li&gt;
&lt;li&gt;Collect the split data lines into an array, so we could sort and color them later, and&lt;/li&gt;
&lt;li&gt;Print all results to screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Disclaimer: Apart from &lt;em&gt;&lt;code&gt;*nps*&lt;/code&gt;&lt;/em&gt;, all search approaches are mostly vibe-coded with “Gemini 3 Pro Preview”. I wanted to iterate quickly to test as many approaches as needed. I did my best to avoid the common pitfalls, but it’s always possible that I missed something. To be fair, the same warning would apply if I coded it by hand.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This code will &lt;em&gt;not&lt;/em&gt; end up in production.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Once I identify the correct approach, I will re-write it from scratch and work it into the &lt;em&gt;&lt;code&gt;*nps*&lt;/code&gt;&lt;/em&gt; implementation. This way I make sure I am responsible for and understand every line of it.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;comparing-speed-against-current-nps&quot;&gt;Comparing Speed against Current &lt;code&gt;nps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We start out to compare the new contenders against the existing approach. For this, we query the smaller, “minimal” database.&lt;/p&gt;
&lt;h3 id=&quot;nps-1&quot;&gt;&lt;code&gt;nps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Providing a baseline, we try the current &lt;code&gt;nps&lt;/code&gt; program. It &lt;em&gt;should&lt;/em&gt; be slower than the other search implementations, since it provides the full pipeline instead of the four steps mentioned above; this includes forming proper columns and coloring the output.&lt;/p&gt;
&lt;p&gt;We also throw the Rust crate &lt;code&gt;grep&lt;/code&gt; into the ring; this is what &lt;code&gt;nps&lt;/code&gt; currently uses internally. Usually, Rust &lt;code&gt;grep&lt;/code&gt; likes to work with a data stream; this makes it really fast. For the benchmark, however, we are deliberately sabotaging its performance by collecting the output into a vector before printing. This is needed for the future &lt;code&gt;nps&lt;/code&gt; implementation, where we will sort the results and color them appropriately. Without hamstringing Rust &lt;code&gt;grep&lt;/code&gt;, the benchmark comparisons would not be entirely fair.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Regarding the data: often the &lt;em&gt;&lt;code&gt;*y*&lt;/code&gt;&lt;/em&gt;-axis (the vertical one) will be logarithmic. Each tick on the &lt;em&gt;&lt;code&gt;*y*&lt;/code&gt;&lt;/em&gt;-axis will denote “10x more than the previous one”. This makes sure we can comfortably see a difference between 2 ms, 2.5 ms and 2000 ms in the same plot.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-c8b7629b.DGTEI-TB_Z5Od7G.webp&quot; srcset=&quot;&quot;&gt;
Now we have something to aim for. If the pure search approach is slower than &lt;code&gt;nps&lt;/code&gt; – which includes creating columns and coloring the output – then we shout “boo!”. Is it faster than the current data retrieval “Rust grep”? Extra brownie points.&lt;/p&gt;
&lt;h3 id=&quot;gnu-grep&quot;&gt;GNU &lt;code&gt;grep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;“Rust &lt;code&gt;grep&lt;/code&gt;” is already there. Now we compare it to “GNU grep” both from the command line and from within Rust. We keep the above run times for &lt;code&gt;nps&lt;/code&gt; and Rust &lt;code&gt;grep&lt;/code&gt; as a gray band for comparison.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-c3a768c9.GPlXR2xR_1TJjd.webp&quot; srcset=&quot;&quot;&gt;
The base speed is decent, but remarkably, the old “GNU &lt;code&gt;grep&lt;/code&gt; (CLI)” becomes &lt;em&gt;faster&lt;/em&gt; with shorter search terms. Afterwards there’s some extra work to do, namely splitting the lines into fields, negating this speed benefit somewhat. This run is labeled “GNU &lt;code&gt;grep&lt;/code&gt; (CLI, rs)”.&lt;/p&gt;
&lt;h3 id=&quot;ripgrep&quot;&gt;&lt;code&gt;ripgrep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Will the Rust flavor of &lt;code&gt;grep&lt;/code&gt; fare any different?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-34a0003e.DkdtsC3M_1eaTBO.webp&quot; srcset=&quot;&quot;&gt;
Yes. Yes it does. Here we start faster than the “GNU &lt;code&gt;grep&lt;/code&gt; (CLI)” above, but take a bit more time the more matches we find, labeled “&lt;code&gt;ripgrep&lt;/code&gt; (CLI)”. Including line splitting, we’re competitive compared to &lt;code&gt;nps&lt;/code&gt;. This is marked as “&lt;code&gt;ripgrep&lt;/code&gt; (CLI, rs)”.&lt;/p&gt;
&lt;h3 id=&quot;tantivy&quot;&gt;&lt;code&gt;Tantivy&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next, we put ChatGPT’s favorite through the wringer. Note that we are dropping the search for &lt;code&gt;e&lt;/code&gt;, since Tantivy cannot find it with the trigram matching in place.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-6e7b6b2c.BEF1GESd_ZPlmtJ.webp&quot; srcset=&quot;&quot;&gt;
While reasonably fast for few matches, it becomes pretty slow for increasing hits. Sad pony. After whining to ChatGPT about it, it suggests that it could have to do something with the number of files to be read. Doubtful, since it &lt;em&gt;can&lt;/em&gt; be fast for few matches. I’m not sure why it can’t keep up.&lt;/p&gt;
&lt;h3 id=&quot;duckdb&quot;&gt;&lt;code&gt;DuckDB&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We are probing three ducklings, one that uses &lt;code&gt;ILIKE&lt;/code&gt;, one that uses &lt;code&gt;regex&lt;/code&gt;, and the self-made &lt;code&gt;trigram&lt;/code&gt; indexing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-fd04450a.BCcx5qpP_gHCrQ.webp&quot; srcset=&quot;&quot;&gt;
Ok, this is bad. Really bad. Remember that we have a logarithmic &lt;code&gt;y&lt;/code&gt;-axis? The bump you see in the plot is the jump from 88 ms for searching for “nvim” to 2.3 s(!) for searching for “python”. For the letter “e” it probably uses the same fallback search that the other two versions have, since anything shorter than three letters not in the trigram index.&lt;/p&gt;
&lt;p&gt;Apparently Gemini cannot successfully hallucinate a feature which would take a small team of software engineers weeks to create, tune, polish, and test.&lt;/p&gt;
&lt;p&gt;Moving on. The other approaches are not disastrous, but they are not great either. Since DuckDB has to crawl through every row of data to find substring matches, that’s not too surprising. If we were searching for exact words &lt;em&gt;only&lt;/em&gt;, that would look much different. But alas, we’re not.&lt;/p&gt;
&lt;h3 id=&quot;sqlite&quot;&gt;&lt;code&gt;SQLite&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;How about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Embedded_database#SQLite&quot;&gt;most widely deployed SQL database engine in the world&lt;/a&gt;?Fun fact, SQLite is open-source, but maybe not in a way you’d expect: instead of having a license attached, the code is entirely in the &lt;a href=&quot;https://sqlite.org/copyright.html&quot;&gt;Public Domain&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-6b334e6c.govxRFMb_ZXex76.webp&quot; srcset=&quot;&quot;&gt;
Nice. For few-result queries, SQLite is &lt;em&gt;really&lt;/em&gt; fast. Approaching thousands of results, it’s on par with Rust &lt;code&gt;grep&lt;/code&gt; and only takes a moderate performance hit beyond that.&lt;/p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Here we condense the above results in a single plot and aim for the realistic worst-case scenario of searching for “python”. The results are not spanning orders of magnitude, so the &lt;code&gt;y&lt;/code&gt;-axis is back to linear.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-ad585d61.BiwugPu__Z6kzfO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;comparing-speed-for-future-nps&quot;&gt;Comparing Speed for Future &lt;code&gt;nps&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To cut an entirely too long story slightly shorter, we get pretty much comparable results for querying the “detailed” database.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-aa3c82c3.McYyLmvj_Z2pSKee.webp&quot; srcset=&quot;&quot;&gt;
Let’s condense the above results in a single, easy-to-interpret table.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;409&quot; height=&quot;430&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-cf19c14b.CIHFNJx9_Z4hYYB.webp&quot; srcset=&quot;&quot;&gt;
So far Rust &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;ripgrep&lt;/code&gt; are leading the pack, with SQLite and GNU &lt;code&gt;grep&lt;/code&gt; hard on their virtual heels.&lt;/p&gt;
&lt;h3 id=&quot;database-size&quot;&gt;Database Size&lt;/h3&gt;
&lt;p&gt;That one is easy, we ask the disc usage tool &lt;code&gt;du&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;du —apparent-size -h *Break-down of the arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--apparent-size&lt;/code&gt; - show the size of the files as they would be without file-system compression, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - human-readable output, e.g. &lt;code&gt;M&lt;/code&gt; for megabytes instead of just bytes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On top of the plain size (as it would appear on a user’s machine), we also compress the databases with &lt;code&gt;gzip&lt;/code&gt; to see how large a typical download would be.&lt;/p&gt;
&lt;p&gt;$ du —apparent-size -h *
63M     detailed.sqlite
28M     detailed.sqlite.tar.gz
15M     detailed_duckdb.db
6.3M    detailed_duckdb.db.tar.gz
169M    detailed_duckdb_trigram.db
48M     detailed_duckdb_trigram.db.tar.gz
30M     detailed_tantivy_index
21M     detailed_tantivy_index.tar.gz
46M     minimal.sqlite
23M     minimal.sqlite.tar.gz
4.8M    minimal_duckdb.db
2.9M    minimal_duckdb.db.tar.gz
148M    minimal_duckdb_trigram.db
42M     minimal_duckdb_trigram.db.tar.gz
23M     minimal_tantivy_index
15M     minimal_tantivy_index.tar.gz
25M     package_list_detailed.txt
4.7M    package_list_detailed.txt.tar.gz
8.5M    package_list_minimal.txt
2.3M    package_list_minimal.txt.tar.gzIn the same discussion we also need to have a look at what updating the database with fresh package information would look like.&lt;/p&gt;
&lt;p&gt;For plain text files, we would either download the whole thing from scratch, or supply diff information, so the existing file could be “patched” with the updates. This would work on a per-row basis which is unfortunate, considering that most of the time you would have an updated version number. To make things worse, the diff would need to indicate the old data &lt;em&gt;and&lt;/em&gt; the new data. Not great.&lt;/p&gt;
&lt;p&gt;Tantivy cannot directly change data, but works with “delete” files that ignore entries. Once a data fragment is ignored in its entirety, it can be deleted. In practice this would mean that the local database size would slowly grow with “delete” files, until a whole, fresh database would be downloaded. The same per-row gotcha from plain text files applies here as well.&lt;/p&gt;
&lt;p&gt;DuckDB and SQLite not only support incremental updates, they also store the data as fields. This allows the updates to be tiny, containing just the information that has changed. This does require some data-dance of “downloadable full databases” and “incremental update files” as well as logic to combine those, but this is solvable.&lt;/p&gt;
&lt;p&gt;Summarized in a table:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;403&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-acd39667.DsJY5DAG_Z4A8Xp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;ram-usage&quot;&gt;RAM usage&lt;/h3&gt;
&lt;p&gt;For both “minimal” and “detailed” searches:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-7ab29ec9.DQKpIJuf_lI5rV.webp&quot; srcset=&quot;&quot;&gt;
This is excitingly unexciting. Ignoring the poor performance of DuckDB with bad &lt;code&gt;trigram&lt;/code&gt; indexing, the worst contender only uses a smidgen more than 30 Mb of RAM. This is fine for all but embedded systems, which would be outside the target group.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Tallied up in one neat overview:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;601&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-fbc295ef.gTMkNuhG_nOfVm.webp&quot; srcset=&quot;&quot;&gt;
The family of &lt;code&gt;grep&lt;/code&gt;s were surprisingly fast. They did a splendid job up till now, but do not scale too well with additional information. Larger datasets also introduce the challenge of download size for updating package information.&lt;/p&gt;
&lt;p&gt;Tantivy gallops quickly for few-result queries, but struggles a bit with large result sets. It’s unclear to me why that would be. Do let me know if you either know why, or point out where I made performance mistakes. Incremental updates are possible, but complicated.&lt;/p&gt;
&lt;p&gt;The paddling (this is the actual collective noun!) of ducks did not fare too well, no thanks to the missing N-gram indexing. It’s probably plenty fast for retrieving exact words, but that’s not what we’re after here. B̶u̶i̶l̶d̶i̶n̶g̶ ̶t̶h̶e̶ ̶i̶n̶d̶e̶x̶ ̶o̶u̶r̶s̶e̶l̶v̶e̶s̶ &lt;em&gt;Gemini vibing the index&lt;/em&gt; leads to the worst performance in all metrics. Shocker.&lt;/p&gt;
&lt;p&gt;SQLite truly shines here. Speed is great, even with many matches. The only challenge is the increased database size due to indexing, but this can be solved by both extra compression for downloads as well as tiny diff files for updating existing databases.&lt;/p&gt;
&lt;p&gt;Phew. That was longer than planned, but we finally have a candidate for the future &lt;code&gt;nps&lt;/code&gt; implementation.&lt;/p&gt;
&lt;h2 id=&quot;award-ceremony&quot;&gt;Award Ceremony&lt;/h2&gt;
&lt;p&gt;Due to outstanding scores in the “update” category, as well as excellent speed scores, we are handing the “cup of brrrrrr” to SQLite.&lt;/p&gt;
&lt;p&gt;🪶🏆👌&lt;/p&gt;
&lt;p&gt;The question of the data source remains unsolved. For the short term, I will scrape and provide the package data myself. Maybe in the future, &lt;code&gt;nixpkgs&lt;/code&gt; data could be offered as a SQLite database, or at least as a JSON file?&lt;/p&gt;
&lt;p&gt;But that, dear reader, is a challenge for another day.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They have their flaws as well. The packages that I want to check out are usually somewhere in the middle of a wall of text. Now I have to search the results of my previous search. Yay.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/peterldowns/nix-search-cli&quot;&gt;https://github.com/peterldowns/nix-search-cli&lt;/a&gt; and &lt;a href=&quot;https://github.com/nix-community/nh?tab=readme-ov-file#nh-search&quot;&gt;https://github.com/nix-community/nh?tab=readme-ov-file#nh-search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;About 27%, or 132,108 vs 103,640 — as of January 2026.&lt;/li&gt;
&lt;li&gt;This form of indexing stores strings of N letters pointing to the word they are extracted from: “duc”, “uck”, and “cks” would point to the word “ducks”, for N=3.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-bd7575b9.DXvMDkzN_Z1TbF5C.webp&quot; srcset=&quot;&quot;&gt;
I want this data, and I want it yesterday!&lt;em&gt;This post is adapted, with the &lt;em&gt;&lt;a href=&quot;https://ole-mn.medium.com/&quot;&gt;&lt;em&gt;author&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;’s permission and collaboration, from &lt;em&gt;&lt;a href=&quot;https://ole.mn/posts/2026-02-data-cache/&quot;&gt;&lt;em&gt;this post&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in his personal blog.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a quest. A quest for the right tool for the right job, for usability, and performance. We will torture databases, run tens of thousands of benchmarks and conjure charts, numbers, and tables. Because science. 🧑‍🔬&lt;/p&gt;
&lt;p&gt;But first, some background.&lt;/p&gt;
&lt;p&gt;The patient is the package search program &lt;code&gt;[nps](https://github.com/OleMussmann/nps/)&lt;/code&gt;, which provides information about all packages the &lt;code&gt;[nix](https://nixos.org/)&lt;/code&gt; package manager has to offer. What’s the patient’s complaint? &lt;code&gt;nps&lt;/code&gt; needs a better database and a better way to update its data.&lt;/p&gt;
&lt;p&gt;Erm, &lt;code&gt;nix&lt;/code&gt;? Never heard of it? It’s kinda special. Unlike &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;pacman&lt;/code&gt;, or their siblings, it is declarative, reproducible and reliable. To top it off, it has a &lt;a href=&quot;https://repology.org/repositories/graphs&quot;&gt;gigantic library&lt;/a&gt;. If you don’t know what that means, no worries! Here’s a primer.&lt;/p&gt;
&lt;h2 id=&quot;nix-whats-that&quot;&gt;&lt;code&gt;nix&lt;/code&gt;? What’s That?&lt;/h2&gt;
&lt;p&gt;How do you set up your operating system? You install, for example, Ubuntu. Then you install a bunch of packages. You configure them. Then you set the wallpaper, the color scheme, the fonts, and make yourself at home. And if you set up a new system, you start again from square one. This whole process is &lt;em&gt;procedural&lt;/em&gt;, you follow one step after another. If you re-do all your steps again, you get the same result; and any changes to the recipe will result in a different outcome.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;nix&lt;/code&gt;, you describe the end state you want to have, and &lt;code&gt;nix&lt;/code&gt; will build and set up the system like you describe. Reliably. Reproducibly. &lt;code&gt;nix&lt;/code&gt; is &lt;em&gt;declarative&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Worry not, you can still apply tweaks and modifications. The desired end state including all customizations can be described in a single configuration file (keep it simple), or a set of files (make it modular). Let’s call this configuration file a “flake”. ❄️ Throw &lt;code&gt;git&lt;/code&gt; at this flake file and now you can jump between different versions on demand.&lt;/p&gt;
&lt;p&gt;If you share your flake with someone else, they can re-create the exact environment on their system. This is great for collaborative development! Runs on your computer? Runs everywhere. You can run other people’s software &lt;em&gt;without installing&lt;/em&gt;, and others can run yours. For even more portability, you can create Docker containers, virtual machines, or even a bootable ISO from your project.&lt;/p&gt;
&lt;p&gt;Sounds like magic? It comes close.&lt;/p&gt;
&lt;p&gt;Current gotchas include a lack of broad adoption, a steep learning curve for the &lt;code&gt;nix&lt;/code&gt; language, as well as not great (but improving) documentation. And, well, a distinct lack of a native, fast, offline program for searching packages.&lt;/p&gt;
&lt;h2 id=&quot;paper-cuts&quot;&gt;Paper Cuts&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nix&lt;/code&gt;’s usability has, let’s say, still room for improvement. Prime example: how to find out which packages one can install. What do these packages do exactly, and what version do I get? The &lt;a href=&quot;https://wiki.nixos.org/wiki/Searching_packages&quot;&gt;recommended way&lt;/a&gt; is – drumroll – a website: &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;search.nixos.org/packages&lt;/a&gt;. It’s fast, comprehensive, and detailed. It works well.&lt;/p&gt;
&lt;p&gt;But it’s a website.&lt;/p&gt;
&lt;p&gt;When I’m pondering about installing packages, I’m not staring at a browser. I’m in the terminal. I want to have the equivalent of &lt;code&gt;apt search&lt;/code&gt; or &lt;code&gt;pacman -Ss&lt;/code&gt;¹.&lt;/p&gt;
&lt;p&gt;There are some wonderful CLI search programs out there², but they hook into the ElasticSearch database powering the backend of &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;search.nixos.org/packages&lt;/a&gt;. This means that you need to be online to get any package information, and (minor quibble, I know) it takes a bit for the information to appear on your screen.&lt;/p&gt;
&lt;h2 id=&quot;nps&quot;&gt;&lt;code&gt;nps&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I built the &lt;a href=&quot;https://github.com/OleMussmann/nps/&quot;&gt;Nix Package Search &lt;/a&gt;&lt;code&gt;[nps](https://github.com/OleMussmann/nps/)&lt;/code&gt; program to do my part to make &lt;code&gt;nix&lt;/code&gt; more user-friendly. &lt;code&gt;nps&lt;/code&gt; stores the package information locally, searches this cache, and presents the result – color-coded and sanely sorted. It works offline. It’s fast. It’s beautiful. Yeah, yeah, I know, I’m biased. Try it for yourself, though! Remember, you can run it without installing.&lt;/p&gt;
&lt;p&gt;Lately, &lt;a href=&quot;https://github.com/kevb1973&quot;&gt;kevb1973&lt;/a&gt; asked me to &lt;a href=&quot;https://github.com/OleMussmann/nps/issues/25&quot;&gt;provide more package information&lt;/a&gt; in the (dense) output that &lt;code&gt;nps&lt;/code&gt; provides. It’s a great idea and would increase the utility that &lt;code&gt;nps&lt;/code&gt; provides! Unfortunately, this is not something I can just bolt on to the existing program. Let’s have a look at the moving parts of &lt;code&gt;nps&lt;/code&gt; to understand why.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;Ok, architecture is a big word. Let me run by you how &lt;code&gt;nps&lt;/code&gt; currently works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;nix search nixpkgs ^&lt;/code&gt; – get all information for “all” packages.&lt;/li&gt;
&lt;li&gt;Create a text file with package names, versions, and descriptions and store them locally.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep&lt;/code&gt; through the text file (yes, it’s that low-tech) to find matches.&lt;/li&gt;
&lt;li&gt;Sort matches nicely into exact hits (searching for “avahi” matches package &lt;code&gt;avahi&lt;/code&gt;), direct hits (finds packages starting with “avahi”, e.g. &lt;code&gt;avahi-compat&lt;/code&gt;) and indirect hits (“avahi” appears anywhere in the package name or description).&lt;/li&gt;
&lt;li&gt;Create columns for better readability.&lt;/li&gt;
&lt;li&gt;Add a lick of paint to color-code the different types of matches.&lt;/li&gt;
&lt;li&gt;Print the result.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The issue: the data is stored as one row per package. Adding more information to each package row will make it harder for &lt;code&gt;grep&lt;/code&gt; to find the packages you’re looking for. This looks like a job for a “proper” database now. But which one? There’s plenty of cool tech out there, but which would be the “best” one for this use case?&lt;/p&gt;
&lt;h2 id=&quot;database-candidate-boundary-conditions&quot;&gt;Database Candidate Boundary Conditions&lt;/h2&gt;
&lt;p&gt;Alright, before we dive in, let’s define a few corner stones.&lt;/p&gt;
&lt;h3 id=&quot;data-source&quot;&gt;Data Source&lt;/h3&gt;
&lt;p&gt;Remember the &lt;code&gt;nix search&lt;/code&gt; command from above? It does not actually find “all” packages, &lt;a href=&quot;https://search.nixos.org&quot;&gt;https://search.nixos.org&lt;/a&gt; finds significantly more³. Why? No idea. Also, &lt;code&gt;nix search&lt;/code&gt; supplies only the package name, version, and description. No other information. Not great. Another aspect that’s missing is that packages might provide a differently named executable: you install the package &lt;code&gt;neovim&lt;/code&gt; and use the executable &lt;code&gt;nvim&lt;/code&gt;; some packages even provide multiple different executables. &lt;code&gt;nix search&lt;/code&gt; can’t find those.&lt;/p&gt;
&lt;p&gt;The data needs to come from a better source.&lt;/p&gt;
&lt;p&gt;The ElasticSearch backend is a good choice, but it’s meant to be queried, not downloaded. This means we have to scrape it in its entirety first.&lt;/p&gt;
&lt;p&gt;Setting up a project that does the scraping and regularly builds a cache that is usable by (a future version of) &lt;code&gt;nps&lt;/code&gt; is a task that goes beyond the scope of this post. Let’s assume for now that we have the data available, and we can squish (very scientific term here) it into any shape or form that we need for querying.&lt;/p&gt;
&lt;h3 id=&quot;substring-matching&quot;&gt;Substring Matching&lt;/h3&gt;
&lt;p&gt;Subwhat? A substring is a part of a string: “crow” is a substring of “miCROWave”. It can be anywhere in a string, beginning, middle, or end. When searching for “nvim” I want to find &lt;code&gt;nvim&lt;/code&gt; (duh!), as well as &lt;code&gt;nvimpager&lt;/code&gt; “use neovim as pager”, and &lt;code&gt;gnvim&lt;/code&gt; “GUI for neovim, without any web bloat”. As most databases are specialized in retrieving “exact” matches, substring matching might take some convincing.&lt;/p&gt;
&lt;h3 id=&quot;query-time&quot;&gt;Query Time&lt;/h3&gt;
&lt;p&gt;I want future &lt;code&gt;nps&lt;/code&gt; to stay fast. I’m happy with the responsiveness of the current implementation. To get a feeling for this, using &lt;code&gt;nps&lt;/code&gt; to search for the package &lt;code&gt;nps&lt;/code&gt; takes about 6ms on my desktop – so let’s take that as a baseline. If the pure data retrieval of the database candidates takes longer than current-&lt;code&gt;nps&lt;/code&gt;, then that’s a red flag, since sorting, coloring, etc. will take some extra time on top of that.&lt;/p&gt;
&lt;p&gt;Quick Cold Start**&lt;/p&gt;
&lt;p&gt;Related to “Query Time”: many “serious” databases are designed to run as a service; that makes querying fast, but you need something running in the background all the time. We don’t want that. Instead, we have a single program that starts up, queries a database, prints stuff, and then quits. This excludes many of the usual suspects like MySQL and its colleagues.&lt;/p&gt;
&lt;h3 id=&quot;data-amount&quot;&gt;Data Amount&lt;/h3&gt;
&lt;p&gt;The current data amount is about 8.5 Mb of package information and metadata for one &lt;code&gt;nixpkgs&lt;/code&gt; channel. The future, more detailed one (also including a long description, project URL and location within the &lt;code&gt;nixpkgs&lt;/code&gt; repo) would be 26 Mb of plain text. For three NixOS channels (“unstable”, “current stable”, “previous stable”), this would be about 80 Mb. While compression can bring this down a bit, some databases need to index their database to be able to search quickly; this will increase the data amount again. How much? That depends on the database used.&lt;/p&gt;
&lt;p&gt;The increased data amount is defensible when taking into account that one could regularly download the &lt;em&gt;incremental changes&lt;/em&gt; instead of the whole database for refreshing the cache.&lt;/p&gt;
&lt;p&gt;Yes, this is pretty hand-wavy for now. We’ll get more concrete about this later.&lt;/p&gt;
&lt;h3 id=&quot;memory-usage&quot;&gt;Memory Usage&lt;/h3&gt;
&lt;p&gt;A bit less crucial than the above, I’d like to use as little RAM as possible during the search. &lt;code&gt;nps&lt;/code&gt; is a guest on your machine and it should use only as much of your resources as needed.&lt;/p&gt;
&lt;p&gt;Many databases (as well as the good ol’ &lt;code&gt;grep&lt;/code&gt;) don’t load the whole data into memory before searching, they “crawl” through the data and drop the parts they have already used. I’d set that as a “nice to have”.&lt;/p&gt;
&lt;h2 id=&quot;database-candidates&quot;&gt;Database Candidates&lt;/h2&gt;
&lt;p&gt;First, let’s discuss the candidates and their structural strengths and weaknesses. We get to the hard numbers below, in the chapter &lt;a href=&quot;#37a0&quot;&gt;&lt;strong&gt;“Gimme Numbers!”&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;grep-a-text-file-&quot;&gt;&lt;code&gt;grep&lt;/code&gt; a Text File 🦖&lt;/h3&gt;
&lt;p&gt;Why change a working system? The old dinosaur &lt;code&gt;grep&lt;/code&gt; is fast. Really fast. We have the &lt;a href=&quot;https://www.gnu.org/software/grep/&quot;&gt;“GNU” flavor&lt;/a&gt; that runs on the command line, then there’s a &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;Rust implementation called &lt;/a&gt;&lt;code&gt;[ripgrep](https://github.com/BurntSushi/ripgrep)&lt;/code&gt;, and lastly the &lt;a href=&quot;https://docs.rs/grep/latest/grep/&quot;&gt;Rust crate called &lt;/a&gt;&lt;code&gt;[grep](https://docs.rs/grep/latest/grep/)&lt;/code&gt;, which is – despite the name – closer to &lt;code&gt;ripgrep&lt;/code&gt; than to &lt;code&gt;grep&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dial it up a notch. I’d like to see how just calling &lt;code&gt;grep&lt;/code&gt; or its cousin &lt;code&gt;ripgrep&lt;/code&gt; from the command line (equivalent to step 3. from &lt;a href=&quot;#architecture&quot;&gt;“Architecture”&lt;/a&gt;; we will label all those tests with the “CLI” suffix) compares to calling it from Rust and splitting the results (necessity for the “new” architecture). &lt;code&gt;ripgrep&lt;/code&gt; likes to work with streaming data, but we can’t do that if we want to form columns later. So what’s the overhead of the extra data mangling?&lt;/p&gt;
&lt;p&gt;That brings us to the following list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNU &lt;code&gt;grep&lt;/code&gt; (called from CLI, results &lt;em&gt;not&lt;/em&gt; split)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ripgrep&lt;/code&gt; (called from CLI, results &lt;em&gt;not&lt;/em&gt; split)&lt;/li&gt;
&lt;li&gt;GNU &lt;code&gt;grep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ripgrep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;li&gt;Rust crate &lt;code&gt;grep&lt;/code&gt; (called from Rust)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;benefits&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Single file “database”&lt;/li&gt;
&lt;li&gt;Easy and good compression&lt;/li&gt;
&lt;li&gt;Trivial substring matching&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Extra finagling to only search certain parts of a line, yet still returning the whole row of data; in practice this means extra lines of code plus possibly a few extra gray hairs&lt;/li&gt;
&lt;li&gt;Incremental data updates are difficult&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sqlite-&quot;&gt;SQLite 🪶&lt;/h3&gt;
&lt;p&gt;The gold standard for “simple” databases. Scales less well for serious applications than MySQL (or MariaDB or whatever), but should be “good enough” for a few hundred thousand packages.&lt;/p&gt;
&lt;p&gt;We use trigram (N-gram with N=3)⁴search to achieve fast substring matching. This makes it, well, fast. But it also inflates the database size and ignores any search terms shorter than 3 characters. One &lt;em&gt;could&lt;/em&gt; check for search string length and use a different matching algorithm for shorter terms, but is that worth the effort?&lt;/p&gt;
&lt;h3 id=&quot;benefits-1&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Single file database&lt;/li&gt;
&lt;li&gt;Battle-tested and stable&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;li&gt;Incremental updates are trivial&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How compressible is an already compressed database?&lt;/li&gt;
&lt;li&gt;Needs indexing for fast substring matches, balancing database size vs performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-1&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tantivy-&quot;&gt;Tantivy 🐎&lt;/h3&gt;
&lt;p&gt;I sparred with ChatGPT about which database to use, and it was very enthusiastic about Tantivy — we will see later if that was a good idea or not. It is designed for a quick cold-start and fast data retrieval, sounds like a match to me! Tantivy stores data in several files and has a &lt;code&gt;meta.json&lt;/code&gt; file to figure out what’s what.&lt;/p&gt;
&lt;p&gt;A quirk: technically, you can’t delete already stored data. Instead, you add a “delete” file that ignores entries and you can delete storage files that eventually become obsolete. Still, incremental updates should not be too hard this way. Every once in a while one would need to re-download the whole thing once the local index grew too large with all those “delete” files.&lt;/p&gt;
&lt;p&gt;Same as with &lt;code&gt;SQLite&lt;/code&gt;, we use trigram matching for speed, with the same benefits and drawbacks.&lt;/p&gt;
&lt;h3 id=&quot;benefits-2&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pretty much designed for this purpose&lt;/li&gt;
&lt;li&gt;Incremental updates are easy&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs-1&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The database is a folder with multiple files&lt;/li&gt;
&lt;li&gt;Needs indexing for fast substring matches, balancing database size vs performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-2&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Incremental updates do need a strategy, with an occasional fresh download of the whole database&lt;/li&gt;
&lt;li&gt;The many files might take some time to read, benchmarks will tell if that’s an issue&lt;/li&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;duckdb-&quot;&gt;DuckDB 🦆&lt;/h3&gt;
&lt;p&gt;Completing our zoo is the new duckling on the block. DuckDB sports rad analytics which might be handy for retrieving already correctly sorted search results.&lt;/p&gt;
&lt;p&gt;However, DuckDB can’t do N-grams. &lt;a href=&quot;https://github.com/duckdb/duckdb/discussions/16071&quot;&gt;Yet&lt;/a&gt;. Sad quack.&lt;/p&gt;
&lt;p&gt;What can we do instead?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Benchmark the slower, standard way of case-insensitive substring matching, called &lt;code&gt;ILIKE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Benchmark the slower, other way of case-insensitive substring matching with regular expressions: &lt;code&gt;regex&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Who needs built-in N-gram indexing when Gemini can build one (let’s call it &lt;code&gt;trigram&lt;/code&gt;) for you? We will soon find out if that’s a good idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;benefits-3&quot;&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ducks are cool&lt;/li&gt;
&lt;li&gt;Single file database&lt;/li&gt;
&lt;li&gt;Supports incremental updates&lt;/li&gt;
&lt;li&gt;“Proper” database queries, the results are well-structured&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trade-offs-2&quot;&gt;Trade-offs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Would the analytics work for proper sorting?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drawbacks-3&quot;&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No built-in N-gram indexing for fast substring matching, uh oh!&lt;/li&gt;
&lt;li&gt;Compression per row, not on the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;benchmarking-boundary-conditions&quot;&gt;Benchmarking Boundary Conditions&lt;/h2&gt;
&lt;p&gt;We will be testing for a lot of things at once, here’s a break-down.&lt;/p&gt;
&lt;h3 id=&quot;parameters&quot;&gt;Parameters&lt;/h3&gt;
&lt;p&gt;We are searching for four different search terms with increasing number of matches. This should give us enough data points to make out a trend.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“nps” (21 matches)&lt;/li&gt;
&lt;li&gt;“nvim” (1301 matches)&lt;/li&gt;
&lt;li&gt;“python” (21123 matches)&lt;/li&gt;
&lt;li&gt;“e” (131567 matches, almost the whole database)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;data-types&quot;&gt;Data Types&lt;/h3&gt;
&lt;p&gt;To be able to compare database performances with the current implementation of &lt;code&gt;nps&lt;/code&gt; we start with a “minimal” database, containing the package name, version, and short description. This mirrors the current implementation of &lt;code&gt;nps&lt;/code&gt; and allows for comparisons.&lt;/p&gt;
&lt;p&gt;The entire “minimal” data for the &lt;code&gt;abcde&lt;/code&gt; package look like this:&lt;/p&gt;
&lt;p&gt;abcde   2.9.3   Command-line audio CD ripperThen we try a “detailed” database, containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;package name&lt;/li&gt;
&lt;li&gt;executable names (which might be different than the package name)&lt;/li&gt;
&lt;li&gt;version&lt;/li&gt;
&lt;li&gt;description (short)&lt;/li&gt;
&lt;li&gt;description (long)&lt;/li&gt;
&lt;li&gt;homepage URL&lt;/li&gt;
&lt;li&gt;and the URL to the package in the &lt;code&gt;nixpkgs&lt;/code&gt; repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Formatted, the information for the same package could look like this:&lt;/p&gt;
&lt;p&gt;abcde [abcde-musicbrainz-tool, abcde, cddb-tool]  2.9.3&lt;/p&gt;
&lt;p&gt;Command-line audio CD ripper
abcde is a front-end command-line utility (actually, a shell
script) that grabs tracks off a CD, encodes them to Ogg/Vorbis,
MP3, FLAC, Ogg/Speex and/or MPP/MP+ (Musepack) format, and tags
them, all in one go.
Project URL: &lt;a href=&quot;http://abcde.einval.com/wiki/&quot;&gt;http://abcde.einval.com/wiki/&lt;/a&gt;
Nixpkgs URL: &lt;a href=&quot;https://github.com/NixOS/nixpkgs/pkgs/by-name/ab/abcde/package.nix:83Off-topic&quot;&gt;https://github.com/NixOS/nixpkgs/pkgs/by-name/ab/abcde/package.nix:83Off-topic&lt;/a&gt;: this project’s website gives me heavy 90’s vibes, woah.&lt;/p&gt;
&lt;h3 id=&quot;hyperfine-engage&quot;&gt;&lt;code&gt;hyperfine&lt;/code&gt;, Engage&lt;/h3&gt;
&lt;p&gt;If you counted correctly, you should have four search terms, two data types, and eleven search approaches. We are skipping some combinations, e.g. “detailed search” is not supported on the O.G. &lt;code&gt;nps&lt;/code&gt;, and Tantivy and DuckDB can’t find anything shorter than 3 characters. In the end we have more than 80 distinctly different benchmarks. Some are run from Rust, some from the command line. To be able to compare them, we benchmark them with &lt;code&gt;[hyperfine](https://github.com/rmlmcfadden/hyperfine)&lt;/code&gt;. Bonus: on top of min-, max-, mean-, and median-runtimes we also get the memory usage of the runs. Nice!&lt;/p&gt;
&lt;p&gt;This is what a typical run on the command line looks like:&lt;/p&gt;
&lt;p&gt;$ hyperfine ‘nps neovim’
Benchmark 1: nps neovim
Time (mean ± σ):       6.0 ms ±   0.4 ms    [User: 1.5 ms, System: 4.4 ms]
Range (min … max):     5.0 ms …   7.3 ms    351 runsEven better, we can also get the results in JSON format. Unfortunately, this also means that it’s written to file.&lt;/p&gt;
&lt;p&gt;Sigh. So we have to read in that file to get the data we need. On the plus side, the JSON detour makes sure we don’t have any unforeseen hick-ups with data parsing, which could have happened if we wanted to retrieve the runtimes via regex from the output shown above.&lt;/p&gt;
&lt;p&gt;The JSON data looks like this:&lt;/p&gt;
&lt;p&gt;{
“results”: [
{
“command”: “nps neovim”,
“mean”: 0.006715249454725274,
“stddev”: 0.0026061538013605248,
“median”: 0.0065737821799999995,
“user”: 0.001504577142857143,
“system”: 0.005087126153846152,
“min”: 0.00505421018,
“max”: 0.03085960318,
“times”: [
0.03085960318,
0.00686827018,
…
],
“memory_usage_byte”: [
12791808,
12791808,
…
],
“exit_codes”: [
0,
0,
…
]
}
]
}For benchmarking, we are using &lt;code&gt;hyperfine&lt;/code&gt; the following way:&lt;/p&gt;
&lt;p&gt;hyperfine —shell=none —warmup=5 —export-json [filename] ‘COMMAND’Break-down of the moving parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--shell=none&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to, well, not start any shell. This shaves a few milliseconds off the benchmark score and allows for easier runtime comparisons.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--warmup=5&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to run &lt;code&gt;COMMAND&lt;/code&gt; 5 times before actually measuring the runtime. This makes sure that all files that are read are properly cached first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--export-json [filename]&lt;/code&gt; tells &lt;code&gt;hyperfine&lt;/code&gt; to write out the data in JSON format.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;gimme-numbers&quot;&gt;Gimme Numbers&lt;/h2&gt;
&lt;p&gt;Now to the fun part. Buckle up, it’s finally benchmark time! With repetitions, we have &gt;40.000 data retrieval runs.&lt;/p&gt;
&lt;p&gt;Below are all the tests we run against the above parameters and data types. To be able to compare apples to apples, these are the steps each approach conducts, unless noted otherwise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read in the data,&lt;/li&gt;
&lt;li&gt;Find package matches in the whole row (minimal databases) , or in the fields “package name”, “executable names”, and “package description (short)” (detailed databases),&lt;/li&gt;
&lt;li&gt;Split the matched data if necessary, so we have access to the “fields” of the data row,&lt;/li&gt;
&lt;li&gt;Collect the split data lines into an array, so we could sort and color them later, and&lt;/li&gt;
&lt;li&gt;Print all results to screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Disclaimer: Apart from &lt;em&gt;&lt;code&gt;*nps*&lt;/code&gt;&lt;/em&gt;, all search approaches are mostly vibe-coded with “Gemini 3 Pro Preview”. I wanted to iterate quickly to test as many approaches as needed. I did my best to avoid the common pitfalls, but it’s always possible that I missed something. To be fair, the same warning would apply if I coded it by hand.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This code will &lt;em&gt;not&lt;/em&gt; end up in production.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Once I identify the correct approach, I will re-write it from scratch and work it into the &lt;em&gt;&lt;code&gt;*nps*&lt;/code&gt;&lt;/em&gt; implementation. This way I make sure I am responsible for and understand every line of it.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;comparing-speed-against-current-nps&quot;&gt;Comparing Speed against Current &lt;code&gt;nps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We start out to compare the new contenders against the existing approach. For this, we query the smaller, “minimal” database.&lt;/p&gt;
&lt;h3 id=&quot;nps-1&quot;&gt;&lt;code&gt;nps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Providing a baseline, we try the current &lt;code&gt;nps&lt;/code&gt; program. It &lt;em&gt;should&lt;/em&gt; be slower than the other search implementations, since it provides the full pipeline instead of the four steps mentioned above; this includes forming proper columns and coloring the output.&lt;/p&gt;
&lt;p&gt;We also throw the Rust crate &lt;code&gt;grep&lt;/code&gt; into the ring; this is what &lt;code&gt;nps&lt;/code&gt; currently uses internally. Usually, Rust &lt;code&gt;grep&lt;/code&gt; likes to work with a data stream; this makes it really fast. For the benchmark, however, we are deliberately sabotaging its performance by collecting the output into a vector before printing. This is needed for the future &lt;code&gt;nps&lt;/code&gt; implementation, where we will sort the results and color them appropriately. Without hamstringing Rust &lt;code&gt;grep&lt;/code&gt;, the benchmark comparisons would not be entirely fair.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Regarding the data: often the &lt;em&gt;&lt;code&gt;*y*&lt;/code&gt;&lt;/em&gt;-axis (the vertical one) will be logarithmic. Each tick on the &lt;em&gt;&lt;code&gt;*y*&lt;/code&gt;&lt;/em&gt;-axis will denote “10x more than the previous one”. This makes sure we can comfortably see a difference between 2 ms, 2.5 ms and 2000 ms in the same plot.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-c8b7629b.DGTEI-TB_Z5Od7G.webp&quot; srcset=&quot;&quot;&gt;
Now we have something to aim for. If the pure search approach is slower than &lt;code&gt;nps&lt;/code&gt; – which includes creating columns and coloring the output – then we shout “boo!”. Is it faster than the current data retrieval “Rust grep”? Extra brownie points.&lt;/p&gt;
&lt;h3 id=&quot;gnu-grep&quot;&gt;GNU &lt;code&gt;grep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;“Rust &lt;code&gt;grep&lt;/code&gt;” is already there. Now we compare it to “GNU grep” both from the command line and from within Rust. We keep the above run times for &lt;code&gt;nps&lt;/code&gt; and Rust &lt;code&gt;grep&lt;/code&gt; as a gray band for comparison.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-c3a768c9.GPlXR2xR_1TJjd.webp&quot; srcset=&quot;&quot;&gt;
The base speed is decent, but remarkably, the old “GNU &lt;code&gt;grep&lt;/code&gt; (CLI)” becomes &lt;em&gt;faster&lt;/em&gt; with shorter search terms. Afterwards there’s some extra work to do, namely splitting the lines into fields, negating this speed benefit somewhat. This run is labeled “GNU &lt;code&gt;grep&lt;/code&gt; (CLI, rs)”.&lt;/p&gt;
&lt;h3 id=&quot;ripgrep&quot;&gt;&lt;code&gt;ripgrep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Will the Rust flavor of &lt;code&gt;grep&lt;/code&gt; fare any different?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-34a0003e.DkdtsC3M_1eaTBO.webp&quot; srcset=&quot;&quot;&gt;
Yes. Yes it does. Here we start faster than the “GNU &lt;code&gt;grep&lt;/code&gt; (CLI)” above, but take a bit more time the more matches we find, labeled “&lt;code&gt;ripgrep&lt;/code&gt; (CLI)”. Including line splitting, we’re competitive compared to &lt;code&gt;nps&lt;/code&gt;. This is marked as “&lt;code&gt;ripgrep&lt;/code&gt; (CLI, rs)”.&lt;/p&gt;
&lt;h3 id=&quot;tantivy&quot;&gt;&lt;code&gt;Tantivy&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next, we put ChatGPT’s favorite through the wringer. Note that we are dropping the search for &lt;code&gt;e&lt;/code&gt;, since Tantivy cannot find it with the trigram matching in place.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-6e7b6b2c.BEF1GESd_ZPlmtJ.webp&quot; srcset=&quot;&quot;&gt;
While reasonably fast for few matches, it becomes pretty slow for increasing hits. Sad pony. After whining to ChatGPT about it, it suggests that it could have to do something with the number of files to be read. Doubtful, since it &lt;em&gt;can&lt;/em&gt; be fast for few matches. I’m not sure why it can’t keep up.&lt;/p&gt;
&lt;h3 id=&quot;duckdb&quot;&gt;&lt;code&gt;DuckDB&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We are probing three ducklings, one that uses &lt;code&gt;ILIKE&lt;/code&gt;, one that uses &lt;code&gt;regex&lt;/code&gt;, and the self-made &lt;code&gt;trigram&lt;/code&gt; indexing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-fd04450a.BCcx5qpP_gHCrQ.webp&quot; srcset=&quot;&quot;&gt;
Ok, this is bad. Really bad. Remember that we have a logarithmic &lt;code&gt;y&lt;/code&gt;-axis? The bump you see in the plot is the jump from 88 ms for searching for “nvim” to 2.3 s(!) for searching for “python”. For the letter “e” it probably uses the same fallback search that the other two versions have, since anything shorter than three letters not in the trigram index.&lt;/p&gt;
&lt;p&gt;Apparently Gemini cannot successfully hallucinate a feature which would take a small team of software engineers weeks to create, tune, polish, and test.&lt;/p&gt;
&lt;p&gt;Moving on. The other approaches are not disastrous, but they are not great either. Since DuckDB has to crawl through every row of data to find substring matches, that’s not too surprising. If we were searching for exact words &lt;em&gt;only&lt;/em&gt;, that would look much different. But alas, we’re not.&lt;/p&gt;
&lt;h3 id=&quot;sqlite&quot;&gt;&lt;code&gt;SQLite&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;How about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Embedded_database#SQLite&quot;&gt;most widely deployed SQL database engine in the world&lt;/a&gt;?Fun fact, SQLite is open-source, but maybe not in a way you’d expect: instead of having a license attached, the code is entirely in the &lt;a href=&quot;https://sqlite.org/copyright.html&quot;&gt;Public Domain&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-6b334e6c.govxRFMb_ZXex76.webp&quot; srcset=&quot;&quot;&gt;
Nice. For few-result queries, SQLite is &lt;em&gt;really&lt;/em&gt; fast. Approaching thousands of results, it’s on par with Rust &lt;code&gt;grep&lt;/code&gt; and only takes a moderate performance hit beyond that.&lt;/p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Here we condense the above results in a single plot and aim for the realistic worst-case scenario of searching for “python”. The results are not spanning orders of magnitude, so the &lt;code&gt;y&lt;/code&gt;-axis is back to linear.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-ad585d61.BiwugPu__Z6kzfO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;comparing-speed-for-future-nps&quot;&gt;Comparing Speed for Future &lt;code&gt;nps&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To cut an entirely too long story slightly shorter, we get pretty much comparable results for querying the “detailed” database.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-aa3c82c3.McYyLmvj_Z2pSKee.webp&quot; srcset=&quot;&quot;&gt;
Let’s condense the above results in a single, easy-to-interpret table.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;409&quot; height=&quot;430&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-cf19c14b.CIHFNJx9_Z4hYYB.webp&quot; srcset=&quot;&quot;&gt;
So far Rust &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;ripgrep&lt;/code&gt; are leading the pack, with SQLite and GNU &lt;code&gt;grep&lt;/code&gt; hard on their virtual heels.&lt;/p&gt;
&lt;h3 id=&quot;database-size&quot;&gt;Database Size&lt;/h3&gt;
&lt;p&gt;That one is easy, we ask the disc usage tool &lt;code&gt;du&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;du —apparent-size -h *Break-down of the arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--apparent-size&lt;/code&gt; - show the size of the files as they would be without file-system compression, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - human-readable output, e.g. &lt;code&gt;M&lt;/code&gt; for megabytes instead of just bytes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On top of the plain size (as it would appear on a user’s machine), we also compress the databases with &lt;code&gt;gzip&lt;/code&gt; to see how large a typical download would be.&lt;/p&gt;
&lt;p&gt;$ du —apparent-size -h *
63M     detailed.sqlite
28M     detailed.sqlite.tar.gz
15M     detailed_duckdb.db
6.3M    detailed_duckdb.db.tar.gz
169M    detailed_duckdb_trigram.db
48M     detailed_duckdb_trigram.db.tar.gz
30M     detailed_tantivy_index
21M     detailed_tantivy_index.tar.gz
46M     minimal.sqlite
23M     minimal.sqlite.tar.gz
4.8M    minimal_duckdb.db
2.9M    minimal_duckdb.db.tar.gz
148M    minimal_duckdb_trigram.db
42M     minimal_duckdb_trigram.db.tar.gz
23M     minimal_tantivy_index
15M     minimal_tantivy_index.tar.gz
25M     package_list_detailed.txt
4.7M    package_list_detailed.txt.tar.gz
8.5M    package_list_minimal.txt
2.3M    package_list_minimal.txt.tar.gzIn the same discussion we also need to have a look at what updating the database with fresh package information would look like.&lt;/p&gt;
&lt;p&gt;For plain text files, we would either download the whole thing from scratch, or supply diff information, so the existing file could be “patched” with the updates. This would work on a per-row basis which is unfortunate, considering that most of the time you would have an updated version number. To make things worse, the diff would need to indicate the old data &lt;em&gt;and&lt;/em&gt; the new data. Not great.&lt;/p&gt;
&lt;p&gt;Tantivy cannot directly change data, but works with “delete” files that ignore entries. Once a data fragment is ignored in its entirety, it can be deleted. In practice this would mean that the local database size would slowly grow with “delete” files, until a whole, fresh database would be downloaded. The same per-row gotcha from plain text files applies here as well.&lt;/p&gt;
&lt;p&gt;DuckDB and SQLite not only support incremental updates, they also store the data as fields. This allows the updates to be tiny, containing just the information that has changed. This does require some data-dance of “downloadable full databases” and “incremental update files” as well as logic to combine those, but this is solvable.&lt;/p&gt;
&lt;p&gt;Summarized in a table:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;403&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-acd39667.DsJY5DAG_Z4A8Xp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;ram-usage&quot;&gt;RAM usage&lt;/h3&gt;
&lt;p&gt;For both “minimal” and “detailed” searches:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-7ab29ec9.DQKpIJuf_lI5rV.webp&quot; srcset=&quot;&quot;&gt;
This is excitingly unexciting. Ignoring the poor performance of DuckDB with bad &lt;code&gt;trigram&lt;/code&gt; indexing, the worst contender only uses a smidgen more than 30 Mb of RAM. This is fine for all but embedded systems, which would be outside the target group.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Tallied up in one neat overview:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Give Me Data, Yesterday&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;601&quot; src=&quot;https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-fbc295ef.gTMkNuhG_nOfVm.webp&quot; srcset=&quot;&quot;&gt;
The family of &lt;code&gt;grep&lt;/code&gt;s were surprisingly fast. They did a splendid job up till now, but do not scale too well with additional information. Larger datasets also introduce the challenge of download size for updating package information.&lt;/p&gt;
&lt;p&gt;Tantivy gallops quickly for few-result queries, but struggles a bit with large result sets. It’s unclear to me why that would be. Do let me know if you either know why, or point out where I made performance mistakes. Incremental updates are possible, but complicated.&lt;/p&gt;
&lt;p&gt;The paddling (this is the actual collective noun!) of ducks did not fare too well, no thanks to the missing N-gram indexing. It’s probably plenty fast for retrieving exact words, but that’s not what we’re after here. B̶u̶i̶l̶d̶i̶n̶g̶ ̶t̶h̶e̶ ̶i̶n̶d̶e̶x̶ ̶o̶u̶r̶s̶e̶l̶v̶e̶s̶ &lt;em&gt;Gemini vibing the index&lt;/em&gt; leads to the worst performance in all metrics. Shocker.&lt;/p&gt;
&lt;p&gt;SQLite truly shines here. Speed is great, even with many matches. The only challenge is the increased database size due to indexing, but this can be solved by both extra compression for downloads as well as tiny diff files for updating existing databases.&lt;/p&gt;
&lt;p&gt;Phew. That was longer than planned, but we finally have a candidate for the future &lt;code&gt;nps&lt;/code&gt; implementation.&lt;/p&gt;
&lt;h2 id=&quot;award-ceremony&quot;&gt;Award Ceremony&lt;/h2&gt;
&lt;p&gt;Due to outstanding scores in the “update” category, as well as excellent speed scores, we are handing the “cup of brrrrrr” to SQLite.&lt;/p&gt;
&lt;p&gt;🪶🏆👌&lt;/p&gt;
&lt;p&gt;The question of the data source remains unsolved. For the short term, I will scrape and provide the package data myself. Maybe in the future, &lt;code&gt;nixpkgs&lt;/code&gt; data could be offered as a SQLite database, or at least as a JSON file?&lt;/p&gt;
&lt;p&gt;But that, dear reader, is a challenge for another day.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They have their flaws as well. The packages that I want to check out are usually somewhere in the middle of a wall of text. Now I have to search the results of my previous search. Yay.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/peterldowns/nix-search-cli&quot;&gt;https://github.com/peterldowns/nix-search-cli&lt;/a&gt; and &lt;a href=&quot;https://github.com/nix-community/nh?tab=readme-ov-file#nh-search&quot;&gt;https://github.com/nix-community/nh?tab=readme-ov-file#nh-search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;About 27%, or 132,108 vs 103,640 — as of January 2026.&lt;/li&gt;
&lt;li&gt;This form of indexing stores strings of N letters pointing to the word they are extracted from: “duc”, “uck”, and “cks” would point to the word “ducks”, for N=3.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/give-me-data-yesterday-c8b7629b.DGTEI-TB.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Making LLMs Work for Science: How AI-Powered Storytelling Helps Researchers Communicate Their Software</title><link>https://blog.esciencecenter.nl/posts/2026-02-26---making-llms-work-for-science-how-ai-powered-storytelling-hel</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-02-26---making-llms-work-for-science-how-ai-powered-storytelling-hel</guid><description>&lt;p&gt;Large language models get a lot of attention in research for what they might replace. We wanted to explore what they can enable: better, faster scientific communication that actually reaches the right audiences.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1372&quot; height=&quot;755&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_d1EFyNcb4difLC1_5QkMvg-a2755dce.CIpdYCd3_Z1MrcDA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Welcome page on the storytelling application.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Authors:&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jesse-gonzalez/&quot;&gt;&lt;em&gt;Jesse González&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/kody-moodley/&quot;&gt;&lt;em&gt;Kody Moodley&lt;/em&gt;&lt;/a&gt;*&lt;br&gt;
Application:* &lt;a href=&quot;https://nlesc.github.io/data-storytelling/&quot;&gt;https://nlesc.github.io/data-storytelling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There’s an ongoing conversation in the research community about large language models. Most of it focuses on risks: hallucinations, bias, the worry that generated text might replace genuine scholarly work. Those concerns are valid and worth taking seriously.&lt;/p&gt;
&lt;p&gt;But there’s another side to this conversation that doesn’t get enough attention. LLMs can be genuinely useful tools when they’re pointed at the right problems, with the right constraints and the right human oversight. Scientific communication is one of those problems.&lt;/p&gt;
&lt;p&gt;At the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, we build research software across four scientific domains: &lt;strong&gt;Environment &amp;#x26; Sustainability&lt;/strong&gt;, &lt;strong&gt;Life Sciences&lt;/strong&gt;, &lt;strong&gt;Natural Sciences&lt;/strong&gt; &amp;#x26; &lt;strong&gt;Engineering&lt;/strong&gt; and &lt;strong&gt;Social Sciences &amp;#x26; Humanities&lt;/strong&gt;. This means hundreds of projects, each of them representing months or years of collaborative work with research teams across the country and internationally, all catalogued in the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;. The software is solid, sometimes groundbreaking. But communicating that work to different audiences (the public, academic peers, funders, workshop participants) takes time that most research teams simply don’t have. There’s a persistent gap between the research software we produce and the stories we tell about it.&lt;/p&gt;
&lt;p&gt;We built a tool to close that gap. And in doing so, we learned some things about what it actually looks like when LLMs serve science instead of the other way around.&lt;/p&gt;
&lt;h2 id=&quot;an-interactive-journey-through-four-research-domains&quot;&gt;An interactive journey through four research domains&lt;/h2&gt;
&lt;p&gt;The first thing you see when you open the &lt;a href=&quot;https://github.com/NLeSC/data-storytelling&quot;&gt;Data Storytelling app&lt;/a&gt; is a 3D particle system. Not a dashboard. Not a table. A cloud of two thousand glowing dots that shift and pulse as you scroll down the page.&lt;/p&gt;
&lt;p&gt;The idea was simple: before you read a single word about a piece of software, you should already have a sense of the research domain it belongs to. Visuals create that context faster than text ever could.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1358&quot; height=&quot;844&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jHWTVqw8VvdPdCDGuCnAZA-1ec471a4.iXSBXRak_2b2YLV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Floating projects retrieved via the Research Software Directory&lt;/p&gt;
&lt;p&gt;The entire application is one long scroll. As you move down, you pass through the domains, each with its own custom 3D scene built in &lt;em&gt;Three.js&lt;/em&gt;. Each 3D scene is peppered with floating cards. Actual projects from the Research Software Directory, fetched live from the API. You hover over one, it glows and scales up. You click it and boom, a modal with the full project details. Description, DOI, metadata, links.&lt;/p&gt;
&lt;p&gt;And tucked inside that modal? A tab labelled “ &lt;strong&gt;Generate Story.&lt;/strong&gt;” That’s where the real magic happens.&lt;/p&gt;
&lt;h2 id=&quot;the-communication-bottleneck-in-research-software&quot;&gt;The communication bottleneck in research software&lt;/h2&gt;
&lt;p&gt;Anyone in research communications will recognise this situation.&lt;/p&gt;
&lt;p&gt;You’ve got a brilliant piece of software. It does something novel with satellite imagery or protein folding or natural language processing for historical Dutch manuscripts. You need to write about it. But write about it for &lt;strong&gt;whom&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;The version for the general public needs to be warm, accessible, maybe open with a compelling question like &lt;em&gt;“What if we could predict floods before they happen?”&lt;/em&gt; The version for an academic journal needs an abstract, proper methodology discussion, and citations formatted just so. The internal review for your board needs FTE estimates, risk assessments, and honest talk about technical debt. And your programme director just wants a one-pager they can scan in three minutes between meetings.&lt;/p&gt;
&lt;p&gt;Same project. Four different pieces of writing. And you need to do this for a hundred projects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is where good research software becomes invisible. Not because the work isn’t worth communicating, but because the communication itself is a bottleneck.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The software ships, the README gets written, maybe a tweet goes out, and that’s it. Months of collaborative work, reduced to a paragraph.&lt;/p&gt;
&lt;p&gt;This is also precisely the kind of problem where LLMs can be a real asset to researchers. Not as a replacement for human judgment, but as a drafting tool that handles the structural heavy lifting: tone calibration, audience adaptation, first-pass content generation. The key is being intentional about how you use them. Not &lt;em&gt;“throw a description at a chatbot and hope for the best”&lt;/em&gt;, but structured, context-rich prompts designed for specific communication goals.&lt;/p&gt;
&lt;h2 id=&quot;generating-stories-feeding-the-model-with-extra-information&quot;&gt;Generating stories feeding the model with extra information&lt;/h2&gt;
&lt;p&gt;The generator pulls related software from the same research domain via the RSD API, without any extra effort from the user. So if you’re generating a story about a climate modelling tool, &lt;strong&gt;it already knows about the other environmental software in the ecosystem and can reference them&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;851&quot; height=&quot;1041&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_w9zVYbuhgtBu_JsNujBL3g-231cdb75.DyuLa9XF_1YkGaM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Project &amp;#x26; Software Information&lt;/p&gt;
&lt;p&gt;You can also upload documents. PDFs, text files, markdown. Research proposals work great for this. The app extracts the text (up to 10,000 characters worth), folds it into the prompt, and the output goes from generic to grounded in specifics.&lt;/p&gt;
&lt;p&gt;For custom projects (things not in the RSD) there’s an “Own Project” button in the top navigation. Pop in a title, description, some reference URLs, upload whatever context you’ve got, pick your audience, and off you go. Same six templates, same quality, no RSD dependency.&lt;/p&gt;
&lt;h2 id=&quot;six-audiences-six-different-stories&quot;&gt;Six audiences, six different stories&lt;/h2&gt;
&lt;p&gt;The story generator ships with six prompt templates. I want to be specific about what these are, because “prompt template” sounds trivial and these are anything but.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1362&quot; height=&quot;1418&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CE8C0Vl-iE0Xjfy3E71HVw-084e4c64.ByNQYqe-_Z1Oa3eq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Generating the story given the selected audience.&lt;/p&gt;
&lt;p&gt;Each one is 500-plus words of careful instructions, closer to a creative brief than a prompt. They specify structure, tone, section order, word count targets, what to emphasise, what to skip. Here’s what each does:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Communications&lt;/strong&gt; (roughly 800 to 1,200 words). Tells the model to write like a science journalist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Academic&lt;/strong&gt; (1,500 to 2,000 words). Formal. Structured. Abstract up front, methodology section, validation results, related work comparison, citation placeholders in `[Author, Year]` format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Internal Review&lt;/strong&gt; (1,000 to 1,500 words). This is the honest one. The prompt tells the model to be “candid about challenges and risks” and to include resource analysis with FTE estimates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One Pager&lt;/strong&gt; (under 300 words). Concise to the point of ruthlessness. What it does, who it’s for, key benefits, quick stats, how to get started.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Course Material&lt;/strong&gt; (2,000 to 3,000 words). We added this one not long ago and I’m kind of excited about it. It generates educational content you could hand to someone: learning objectives, a technology deep dive, step-by-step tutorials, three tiers of exercises (beginner, intermediate, advanced), and self-assessment questions. Give it to a workshop organiser and they’ve got a starting point for a full training session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blog Post&lt;/strong&gt; (800 to 1,200 words). This one was modelled directly on the eScience Center’s own Medium blog. We analysed dozens of our published posts to capture the voice: community-focused, accessible, story-driven with a problem-solution structure. The idea is that a researcher or RSE could generate a first draft and hand it to communications with minimal rework.&lt;/p&gt;
&lt;p&gt;The difference between a good and a mediocre generated story almost never comes down to the model. &lt;strong&gt;It comes down to the prompt.&lt;/strong&gt; Two thousand five hundred words of structured instructions. That’s the actual product. The Gemini API call is almost the easy part.&lt;/p&gt;
&lt;h2 id=&quot;what-this-taught-us-about-llms-as-tools-for-science&quot;&gt;What this taught us about LLMs as tools for science&lt;/h2&gt;
&lt;p&gt;Building and using this tool surfaced a few insights about how LLMs can genuinely serve researchers, rather than just generate noise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nobody needs another text generator.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Researchers need a tool that adapts to the audience and understands the difference between writing for a review committee and writing for the general public. The real value is in the gap between generate some text about this software and generate an internal review with risk assessment and FTE estimates in the right tone, because once you add that kind of specificity to prompts, LLMs stop being gimmicks and start being useful.&lt;/p&gt;
&lt;p&gt;Another big win is generating multiple perspectives on the same project. If you create a communications piece, an academic paper, a review document, a one-pager, a course module, and a blog post from the same source, each lens reveals something different, like overlooked methodological contributions, the true core value in twenty words, what is actually teachable, and how the work connects to the wider research community, so the LLM becomes a thinking tool, not just a writing tool.&lt;/p&gt;
&lt;p&gt;And honestly, context matters more than model sophistication. Running the same prompt on Gemini Flash versus Gemini Pro changes little, but enriching the input with a research proposal, team info, and related software packages changes everything, which suggests institutions will get more value by investing in structured metadata and rich context than by chasing the newest model.&lt;/p&gt;
&lt;h2 id=&quot;llms-as-collaborators-not-replacements&quot;&gt;LLMs as collaborators, not replacements&lt;/h2&gt;
&lt;p&gt;Let me be clear about what this tool does and doesn’t do.&lt;/p&gt;
&lt;p&gt;It doesn’t replace the science communicator who knows that a particular project has a funny origin story, or that the lead developer gave a brilliant conference talk last month, or that “ &lt;em&gt;digital bridges&lt;/em&gt; ” works better for this audience than &lt;em&gt;“computational pipelines.”&lt;/em&gt; Those things require human judgment, institutional memory, and taste. No model provides that.&lt;/p&gt;
&lt;p&gt;That’s the pattern we think works for LLMs in science more broadly. Not autonomous generation. Not replacing experts. Instead: structured tools that handle well-defined tasks with rich context and human oversight. Tools that make researchers more effective at the parts of their job that aren’t their core expertise but still matter, like communicating their work to the people who need to hear about it.&lt;/p&gt;
&lt;p&gt;The conversation about LLMs in research is often framed as a threat. We think it’s more productive to ask: &lt;strong&gt;where can these tools genuinely help, and what does it take to use them responsibly?&lt;/strong&gt; For me, scientific communication turned out to be a great answer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A hundred projects, six audience types, one tool. The stories were always there. We just needed a better way to start telling them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;under-the-bonnet-tech-stack-for-the-curious-ones&quot;&gt;Under the bonnet tech stack (for the curious ones)&lt;/h2&gt;
&lt;p&gt;A few technical choices that I think are interesting, even if they’re invisible to most users:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No backend.&lt;/strong&gt; The Gemini API gets called straight from the browser. No server, no proxy, no infrastructure to babysit. You deploy it as a static site and walk away. The tradeoff? Users bring their own API key, stored in localStorage, never sent anywhere except to Google. For a research-oriented audience that already juggles API keys for half a dozen services, this felt like a reasonable ask.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Svelte 5 runes everywhere&lt;/strong&gt;. The whole app runs on Svelte 5’s new reactivity system: &lt;em&gt;`&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected group as argument to &amp;#x27;\&amp;#x60;&amp;#x27; at end of input: state\&amp;#x60;, \&amp;#x60;&quot; style=&quot;color:#cc0000&quot;&gt;state\`, \`&lt;/span&gt;derived`, `$effect`&lt;/em&gt;. When AI-generated text streams in, only the story display component re-renders. Not the 3D scene. Not the navigation. Not the settings panel. For something that’s running WebGL animations, parsing SSE streams, and managing modal state all at once, that granularity needs to be optional.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scroll velocity drives the 3D&lt;/strong&gt;. This is the detail I’m most proud of. The scroll store doesn’t just track how far down the page you are. It measures how &lt;strong&gt;fast&lt;/strong&gt; you’re scrolling and in which direction. That velocity feeds into the &lt;em&gt;Three.js&lt;/em&gt; scenes. Scroll fast and the camera pulls back, particles scatter wider, everything feels like it’s accelerating with you. Scroll slow and things settle into a gentle rotation. It’s the kind of thing you won’t notice unless you’re looking for it, which is the point. The best interactions are the ones you feel rather than see.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt engineering treated as product design.&lt;/strong&gt; I keep coming back to this because I think it’s the least obvious and most important decision we made. The prompt templates weren’t written by a developer in ten minutes. They were iterated on, tested against real projects, revised, tested again. The “Internal Review” template went through five or six drafts before it produced output a programme manager would find useful on a consistent basis. Treating prompts with the same rigour you’d give a product spec? That’s where the real value lives.&lt;/p&gt;
&lt;p&gt;— -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Data Storytelling application is open source at &lt;a href=&quot;https://github.com/NLeSC/data-storytelling&quot;&gt;https://github.com/NLeSC/data-storytelling&lt;/a&gt;. Built at the Netherlands eScience Center, and the Google Gemini API. We’d love to hear how other research organisations approach this challenge. Contributions and conversations welcome.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Thu, 26 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Large language models get a lot of attention in research for what they might replace. We wanted to explore what they can enable: better, faster scientific communication that actually reaches the right audiences.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1372&quot; height=&quot;755&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_d1EFyNcb4difLC1_5QkMvg-a2755dce.CIpdYCd3_Z1MrcDA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Welcome page on the storytelling application.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Authors:&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jesse-gonzalez/&quot;&gt;&lt;em&gt;Jesse González&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/kody-moodley/&quot;&gt;&lt;em&gt;Kody Moodley&lt;/em&gt;&lt;/a&gt;*&lt;br&gt;
Application:* &lt;a href=&quot;https://nlesc.github.io/data-storytelling/&quot;&gt;https://nlesc.github.io/data-storytelling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There’s an ongoing conversation in the research community about large language models. Most of it focuses on risks: hallucinations, bias, the worry that generated text might replace genuine scholarly work. Those concerns are valid and worth taking seriously.&lt;/p&gt;
&lt;p&gt;But there’s another side to this conversation that doesn’t get enough attention. LLMs can be genuinely useful tools when they’re pointed at the right problems, with the right constraints and the right human oversight. Scientific communication is one of those problems.&lt;/p&gt;
&lt;p&gt;At the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, we build research software across four scientific domains: &lt;strong&gt;Environment &amp;#x26; Sustainability&lt;/strong&gt;, &lt;strong&gt;Life Sciences&lt;/strong&gt;, &lt;strong&gt;Natural Sciences&lt;/strong&gt; &amp;#x26; &lt;strong&gt;Engineering&lt;/strong&gt; and &lt;strong&gt;Social Sciences &amp;#x26; Humanities&lt;/strong&gt;. This means hundreds of projects, each of them representing months or years of collaborative work with research teams across the country and internationally, all catalogued in the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;. The software is solid, sometimes groundbreaking. But communicating that work to different audiences (the public, academic peers, funders, workshop participants) takes time that most research teams simply don’t have. There’s a persistent gap between the research software we produce and the stories we tell about it.&lt;/p&gt;
&lt;p&gt;We built a tool to close that gap. And in doing so, we learned some things about what it actually looks like when LLMs serve science instead of the other way around.&lt;/p&gt;
&lt;h2 id=&quot;an-interactive-journey-through-four-research-domains&quot;&gt;An interactive journey through four research domains&lt;/h2&gt;
&lt;p&gt;The first thing you see when you open the &lt;a href=&quot;https://github.com/NLeSC/data-storytelling&quot;&gt;Data Storytelling app&lt;/a&gt; is a 3D particle system. Not a dashboard. Not a table. A cloud of two thousand glowing dots that shift and pulse as you scroll down the page.&lt;/p&gt;
&lt;p&gt;The idea was simple: before you read a single word about a piece of software, you should already have a sense of the research domain it belongs to. Visuals create that context faster than text ever could.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1358&quot; height=&quot;844&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jHWTVqw8VvdPdCDGuCnAZA-1ec471a4.iXSBXRak_2b2YLV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Floating projects retrieved via the Research Software Directory&lt;/p&gt;
&lt;p&gt;The entire application is one long scroll. As you move down, you pass through the domains, each with its own custom 3D scene built in &lt;em&gt;Three.js&lt;/em&gt;. Each 3D scene is peppered with floating cards. Actual projects from the Research Software Directory, fetched live from the API. You hover over one, it glows and scales up. You click it and boom, a modal with the full project details. Description, DOI, metadata, links.&lt;/p&gt;
&lt;p&gt;And tucked inside that modal? A tab labelled “ &lt;strong&gt;Generate Story.&lt;/strong&gt;” That’s where the real magic happens.&lt;/p&gt;
&lt;h2 id=&quot;the-communication-bottleneck-in-research-software&quot;&gt;The communication bottleneck in research software&lt;/h2&gt;
&lt;p&gt;Anyone in research communications will recognise this situation.&lt;/p&gt;
&lt;p&gt;You’ve got a brilliant piece of software. It does something novel with satellite imagery or protein folding or natural language processing for historical Dutch manuscripts. You need to write about it. But write about it for &lt;strong&gt;whom&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;The version for the general public needs to be warm, accessible, maybe open with a compelling question like &lt;em&gt;“What if we could predict floods before they happen?”&lt;/em&gt; The version for an academic journal needs an abstract, proper methodology discussion, and citations formatted just so. The internal review for your board needs FTE estimates, risk assessments, and honest talk about technical debt. And your programme director just wants a one-pager they can scan in three minutes between meetings.&lt;/p&gt;
&lt;p&gt;Same project. Four different pieces of writing. And you need to do this for a hundred projects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is where good research software becomes invisible. Not because the work isn’t worth communicating, but because the communication itself is a bottleneck.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The software ships, the README gets written, maybe a tweet goes out, and that’s it. Months of collaborative work, reduced to a paragraph.&lt;/p&gt;
&lt;p&gt;This is also precisely the kind of problem where LLMs can be a real asset to researchers. Not as a replacement for human judgment, but as a drafting tool that handles the structural heavy lifting: tone calibration, audience adaptation, first-pass content generation. The key is being intentional about how you use them. Not &lt;em&gt;“throw a description at a chatbot and hope for the best”&lt;/em&gt;, but structured, context-rich prompts designed for specific communication goals.&lt;/p&gt;
&lt;h2 id=&quot;generating-stories-feeding-the-model-with-extra-information&quot;&gt;Generating stories feeding the model with extra information&lt;/h2&gt;
&lt;p&gt;The generator pulls related software from the same research domain via the RSD API, without any extra effort from the user. So if you’re generating a story about a climate modelling tool, &lt;strong&gt;it already knows about the other environmental software in the ecosystem and can reference them&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;851&quot; height=&quot;1041&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_w9zVYbuhgtBu_JsNujBL3g-231cdb75.DyuLa9XF_1YkGaM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Project &amp;#x26; Software Information&lt;/p&gt;
&lt;p&gt;You can also upload documents. PDFs, text files, markdown. Research proposals work great for this. The app extracts the text (up to 10,000 characters worth), folds it into the prompt, and the output goes from generic to grounded in specifics.&lt;/p&gt;
&lt;p&gt;For custom projects (things not in the RSD) there’s an “Own Project” button in the top navigation. Pop in a title, description, some reference URLs, upload whatever context you’ve got, pick your audience, and off you go. Same six templates, same quality, no RSD dependency.&lt;/p&gt;
&lt;h2 id=&quot;six-audiences-six-different-stories&quot;&gt;Six audiences, six different stories&lt;/h2&gt;
&lt;p&gt;The story generator ships with six prompt templates. I want to be specific about what these are, because “prompt template” sounds trivial and these are anything but.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1362&quot; height=&quot;1418&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CE8C0Vl-iE0Xjfy3E71HVw-084e4c64.ByNQYqe-_Z1Oa3eq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Generating the story given the selected audience.&lt;/p&gt;
&lt;p&gt;Each one is 500-plus words of careful instructions, closer to a creative brief than a prompt. They specify structure, tone, section order, word count targets, what to emphasise, what to skip. Here’s what each does:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Communications&lt;/strong&gt; (roughly 800 to 1,200 words). Tells the model to write like a science journalist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Academic&lt;/strong&gt; (1,500 to 2,000 words). Formal. Structured. Abstract up front, methodology section, validation results, related work comparison, citation placeholders in `[Author, Year]` format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Internal Review&lt;/strong&gt; (1,000 to 1,500 words). This is the honest one. The prompt tells the model to be “candid about challenges and risks” and to include resource analysis with FTE estimates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One Pager&lt;/strong&gt; (under 300 words). Concise to the point of ruthlessness. What it does, who it’s for, key benefits, quick stats, how to get started.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Course Material&lt;/strong&gt; (2,000 to 3,000 words). We added this one not long ago and I’m kind of excited about it. It generates educational content you could hand to someone: learning objectives, a technology deep dive, step-by-step tutorials, three tiers of exercises (beginner, intermediate, advanced), and self-assessment questions. Give it to a workshop organiser and they’ve got a starting point for a full training session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blog Post&lt;/strong&gt; (800 to 1,200 words). This one was modelled directly on the eScience Center’s own Medium blog. We analysed dozens of our published posts to capture the voice: community-focused, accessible, story-driven with a problem-solution structure. The idea is that a researcher or RSE could generate a first draft and hand it to communications with minimal rework.&lt;/p&gt;
&lt;p&gt;The difference between a good and a mediocre generated story almost never comes down to the model. &lt;strong&gt;It comes down to the prompt.&lt;/strong&gt; Two thousand five hundred words of structured instructions. That’s the actual product. The Gemini API call is almost the easy part.&lt;/p&gt;
&lt;h2 id=&quot;what-this-taught-us-about-llms-as-tools-for-science&quot;&gt;What this taught us about LLMs as tools for science&lt;/h2&gt;
&lt;p&gt;Building and using this tool surfaced a few insights about how LLMs can genuinely serve researchers, rather than just generate noise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nobody needs another text generator.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Researchers need a tool that adapts to the audience and understands the difference between writing for a review committee and writing for the general public. The real value is in the gap between generate some text about this software and generate an internal review with risk assessment and FTE estimates in the right tone, because once you add that kind of specificity to prompts, LLMs stop being gimmicks and start being useful.&lt;/p&gt;
&lt;p&gt;Another big win is generating multiple perspectives on the same project. If you create a communications piece, an academic paper, a review document, a one-pager, a course module, and a blog post from the same source, each lens reveals something different, like overlooked methodological contributions, the true core value in twenty words, what is actually teachable, and how the work connects to the wider research community, so the LLM becomes a thinking tool, not just a writing tool.&lt;/p&gt;
&lt;p&gt;And honestly, context matters more than model sophistication. Running the same prompt on Gemini Flash versus Gemini Pro changes little, but enriching the input with a research proposal, team info, and related software packages changes everything, which suggests institutions will get more value by investing in structured metadata and rich context than by chasing the newest model.&lt;/p&gt;
&lt;h2 id=&quot;llms-as-collaborators-not-replacements&quot;&gt;LLMs as collaborators, not replacements&lt;/h2&gt;
&lt;p&gt;Let me be clear about what this tool does and doesn’t do.&lt;/p&gt;
&lt;p&gt;It doesn’t replace the science communicator who knows that a particular project has a funny origin story, or that the lead developer gave a brilliant conference talk last month, or that “ &lt;em&gt;digital bridges&lt;/em&gt; ” works better for this audience than &lt;em&gt;“computational pipelines.”&lt;/em&gt; Those things require human judgment, institutional memory, and taste. No model provides that.&lt;/p&gt;
&lt;p&gt;That’s the pattern we think works for LLMs in science more broadly. Not autonomous generation. Not replacing experts. Instead: structured tools that handle well-defined tasks with rich context and human oversight. Tools that make researchers more effective at the parts of their job that aren’t their core expertise but still matter, like communicating their work to the people who need to hear about it.&lt;/p&gt;
&lt;p&gt;The conversation about LLMs in research is often framed as a threat. We think it’s more productive to ask: &lt;strong&gt;where can these tools genuinely help, and what does it take to use them responsibly?&lt;/strong&gt; For me, scientific communication turned out to be a great answer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A hundred projects, six audience types, one tool. The stories were always there. We just needed a better way to start telling them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;under-the-bonnet-tech-stack-for-the-curious-ones&quot;&gt;Under the bonnet tech stack (for the curious ones)&lt;/h2&gt;
&lt;p&gt;A few technical choices that I think are interesting, even if they’re invisible to most users:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No backend.&lt;/strong&gt; The Gemini API gets called straight from the browser. No server, no proxy, no infrastructure to babysit. You deploy it as a static site and walk away. The tradeoff? Users bring their own API key, stored in localStorage, never sent anywhere except to Google. For a research-oriented audience that already juggles API keys for half a dozen services, this felt like a reasonable ask.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Svelte 5 runes everywhere&lt;/strong&gt;. The whole app runs on Svelte 5’s new reactivity system: &lt;em&gt;`&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected group as argument to &amp;#x27;\&amp;#x60;&amp;#x27; at end of input: state\&amp;#x60;, \&amp;#x60;&quot; style=&quot;color:#cc0000&quot;&gt;state\`, \`&lt;/span&gt;derived`, `$effect`&lt;/em&gt;. When AI-generated text streams in, only the story display component re-renders. Not the 3D scene. Not the navigation. Not the settings panel. For something that’s running WebGL animations, parsing SSE streams, and managing modal state all at once, that granularity needs to be optional.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scroll velocity drives the 3D&lt;/strong&gt;. This is the detail I’m most proud of. The scroll store doesn’t just track how far down the page you are. It measures how &lt;strong&gt;fast&lt;/strong&gt; you’re scrolling and in which direction. That velocity feeds into the &lt;em&gt;Three.js&lt;/em&gt; scenes. Scroll fast and the camera pulls back, particles scatter wider, everything feels like it’s accelerating with you. Scroll slow and things settle into a gentle rotation. It’s the kind of thing you won’t notice unless you’re looking for it, which is the point. The best interactions are the ones you feel rather than see.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt engineering treated as product design.&lt;/strong&gt; I keep coming back to this because I think it’s the least obvious and most important decision we made. The prompt templates weren’t written by a developer in ten minutes. They were iterated on, tested against real projects, revised, tested again. The “Internal Review” template went through five or six drafts before it produced output a programme manager would find useful on a consistent basis. Treating prompts with the same rigour you’d give a product spec? That’s where the real value lives.&lt;/p&gt;
&lt;p&gt;— -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Data Storytelling application is open source at &lt;a href=&quot;https://github.com/NLeSC/data-storytelling&quot;&gt;https://github.com/NLeSC/data-storytelling&lt;/a&gt;. Built at the Netherlands eScience Center, and the Google Gemini API. We’d love to hear how other research organisations approach this challenge. Contributions and conversations welcome.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_jHWTVqw8VvdPdCDGuCnAZA-1ec471a4.iXSBXRak.gif" medium="image"/><author>Jesse Gonzalez</author></item><item><title>Enabling best practices for sustainable software in the Natural &amp;amp; Engineering sciences (SS-NES)</title><link>https://blog.esciencecenter.nl/posts/2026-02-11---enabling-best-practices-for-sustainable-software-in-the-natu</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-02-11---enabling-best-practices-for-sustainable-software-in-the-natu</guid><description>&lt;h1 id=&quot;enabling-best-practices-for-sustainable-software-in-the-natural--engineering-sciences-ss-nes&quot;&gt;&lt;strong&gt;Enabling best practices for sustainable software in the Natural &amp;#x26; Engineering sciences (SS-NES)&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Authors: Roel Janssen, Jason Maassen and Carlos Martinez-Ortiz&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With the available constellation of data and code repositories, it can be hard to choose the best way of making your research code and data available. Here we present an automated way of synchronizing &lt;em&gt;&lt;a href=&quot;https://community.data.4tu.nl/&quot;&gt;&lt;em&gt;4TU.ResearchData&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; with the &lt;em&gt;&lt;a href=&quot;https://research-software-directory.org/&quot;&gt;&lt;em&gt;Research Software Directory&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;329&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--312dc003.C2NZAdf8_1g5qpn.webp&quot; srcset=&quot;&quot;&gt;
4TU.ResearchData is a data and software repository for science, engineering and design domains, as well as support services and a vibrant community around them. The Research Software Directory is an open-source project initiated by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and jointly developed with &lt;a href=&quot;https://www.helmholtz.de/&quot;&gt;Helmholtz&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As part of the project &lt;a href=&quot;https://ss-nes.github.io/&quot;&gt;Enabling best practices for sustainable software in the Natural &amp;#x26; Engineering sciences (**&lt;/a&gt;**SS-NES) **the 4TU.ResearchData’s data repository and eScience Center’s Research Software Directory (RSD) collaborated to ensure software published in 4TU.ResearchData is also made available in the Research Software Directory.&lt;/p&gt;
&lt;p&gt;To achieve this goal, 4TU.ResearchData adapted its metadata intake and implemented API endpoints following the &lt;a href=&quot;https://codemeta.github.io/&quot;&gt;CodeMeta&lt;/a&gt; standard. Additionally, 4TU.ResearchData implemented API endpoints to communicate statistics on Git repositories following existing Github and Gitlab practices.&lt;/p&gt;
&lt;p&gt;The RSD implemented a harvester for 4TU.ResearchData which uses the CodeMeta metadata standard and a Communities feature to group software from a particular source.&lt;/p&gt;
&lt;h2 id=&quot;adding-to-the-research-software-landscape&quot;&gt;Adding to the research software landscape&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;408&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--2404cfd2.B3rnVSTT_Z1C7idO.webp&quot; srcset=&quot;&quot;&gt;
When creating software as part of your research activities, it is advisable to use a version control system like Git to manage the evolution of the software. At some point, the software needs to be shared with other researchers, either to reuse or extend it, or to validate the research results. Publishing the software provides the benefits of having a URL to cite as well as having a guarantee that the source code of the software is stored at a persistent location for the long term. These benefits are provided by 4TU.ResearchData.&lt;/p&gt;
&lt;p&gt;To publish the software in 4TU.ResearchData from Gitlab, Github or Codeberg, one can use Git’s “remotes” concept to push a copy to 4TU.ResearchData while retaining the active development on the hub.&lt;/p&gt;
&lt;p&gt;Fun fact**: Due to the collaboration between the eScienceCenter’s RSD and 4TU.ResearchData, the latter added the “Git repository name” and “Code hosting project URL” metadata fields so that they can be used and passed along to the RSD.&lt;/p&gt;
&lt;p&gt;We chose this approach because it works regardless of whether the repository is public or private, and regardless of the implementation of the hosting platform. We support Github, Gitlab, Codeberg, Savannah, or any other Git-based platform. Additionally, when dealing with private Git repositories, no systematic integration or information exposure is needed.&lt;/p&gt;
&lt;h2 id=&quot;finding-and-showcasing-software-in-the-research-software-landscape&quot;&gt;Finding and showcasing software in the research software landscape&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;643&quot; height=&quot;359&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--4f34d759.DxzODF57_Z10Rf5t.webp&quot; srcset=&quot;&quot;&gt;
Once the software is published on 4TU.ResearchData, it is automatically picked up by the RSD and added to the 4TU Community collection. The RSD uses the information recorded in 4TU.ResearchData to generate a unique software page designed to highlight the impact of the software.&lt;/p&gt;
&lt;p&gt;Next to showing basic static information about the software such as a short description, author list, keywords, and links to the source code, the RSD also enriches the software page with information harvested from other data sources in the open science and open-source ecosystem. Examples include information on software development activity, citation information for the different software releases, and a list of papers citing the software.&lt;/p&gt;
&lt;h2 id=&quot;concluding-words&quot;&gt;Concluding words&lt;/h2&gt;
&lt;p&gt;Publishing your software on a trusted repository is one of the good practices advocated by the SS-NES project and the eScience Center. With the integration between 4TU.ResearchData and the RSD, researchers automatically benefit from the findability and exposability of the RSD when they publish their software in 4TU.ResearchData. The RSD has become a more complete source of mapping the research software landscape by automatically harvesting 4TU.ResearchData’s software publications.&lt;/p&gt;</description><pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;enabling-best-practices-for-sustainable-software-in-the-natural--engineering-sciences-ss-nes&quot;&gt;&lt;strong&gt;Enabling best practices for sustainable software in the Natural &amp;#x26; Engineering sciences (SS-NES)&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Authors: Roel Janssen, Jason Maassen and Carlos Martinez-Ortiz&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With the available constellation of data and code repositories, it can be hard to choose the best way of making your research code and data available. Here we present an automated way of synchronizing &lt;em&gt;&lt;a href=&quot;https://community.data.4tu.nl/&quot;&gt;&lt;em&gt;4TU.ResearchData&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; with the &lt;em&gt;&lt;a href=&quot;https://research-software-directory.org/&quot;&gt;&lt;em&gt;Research Software Directory&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;329&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--312dc003.C2NZAdf8_1g5qpn.webp&quot; srcset=&quot;&quot;&gt;
4TU.ResearchData is a data and software repository for science, engineering and design domains, as well as support services and a vibrant community around them. The Research Software Directory is an open-source project initiated by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and jointly developed with &lt;a href=&quot;https://www.helmholtz.de/&quot;&gt;Helmholtz&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As part of the project &lt;a href=&quot;https://ss-nes.github.io/&quot;&gt;Enabling best practices for sustainable software in the Natural &amp;#x26; Engineering sciences (**&lt;/a&gt;**SS-NES) **the 4TU.ResearchData’s data repository and eScience Center’s Research Software Directory (RSD) collaborated to ensure software published in 4TU.ResearchData is also made available in the Research Software Directory.&lt;/p&gt;
&lt;p&gt;To achieve this goal, 4TU.ResearchData adapted its metadata intake and implemented API endpoints following the &lt;a href=&quot;https://codemeta.github.io/&quot;&gt;CodeMeta&lt;/a&gt; standard. Additionally, 4TU.ResearchData implemented API endpoints to communicate statistics on Git repositories following existing Github and Gitlab practices.&lt;/p&gt;
&lt;p&gt;The RSD implemented a harvester for 4TU.ResearchData which uses the CodeMeta metadata standard and a Communities feature to group software from a particular source.&lt;/p&gt;
&lt;h2 id=&quot;adding-to-the-research-software-landscape&quot;&gt;Adding to the research software landscape&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;408&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--2404cfd2.B3rnVSTT_Z1C7idO.webp&quot; srcset=&quot;&quot;&gt;
When creating software as part of your research activities, it is advisable to use a version control system like Git to manage the evolution of the software. At some point, the software needs to be shared with other researchers, either to reuse or extend it, or to validate the research results. Publishing the software provides the benefits of having a URL to cite as well as having a guarantee that the source code of the software is stored at a persistent location for the long term. These benefits are provided by 4TU.ResearchData.&lt;/p&gt;
&lt;p&gt;To publish the software in 4TU.ResearchData from Gitlab, Github or Codeberg, one can use Git’s “remotes” concept to push a copy to 4TU.ResearchData while retaining the active development on the hub.&lt;/p&gt;
&lt;p&gt;Fun fact**: Due to the collaboration between the eScienceCenter’s RSD and 4TU.ResearchData, the latter added the “Git repository name” and “Code hosting project URL” metadata fields so that they can be used and passed along to the RSD.&lt;/p&gt;
&lt;p&gt;We chose this approach because it works regardless of whether the repository is public or private, and regardless of the implementation of the hosting platform. We support Github, Gitlab, Codeberg, Savannah, or any other Git-based platform. Additionally, when dealing with private Git repositories, no systematic integration or information exposure is needed.&lt;/p&gt;
&lt;h2 id=&quot;finding-and-showcasing-software-in-the-research-software-landscape&quot;&gt;Finding and showcasing software in the research software landscape&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Enabling best practices for sustainable software in the Natural &amp;amp;#x26; Engineering sciences (SS-NES)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;643&quot; height=&quot;359&quot; src=&quot;https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--4f34d759.DxzODF57_Z10Rf5t.webp&quot; srcset=&quot;&quot;&gt;
Once the software is published on 4TU.ResearchData, it is automatically picked up by the RSD and added to the 4TU Community collection. The RSD uses the information recorded in 4TU.ResearchData to generate a unique software page designed to highlight the impact of the software.&lt;/p&gt;
&lt;p&gt;Next to showing basic static information about the software such as a short description, author list, keywords, and links to the source code, the RSD also enriches the software page with information harvested from other data sources in the open science and open-source ecosystem. Examples include information on software development activity, citation information for the different software releases, and a list of papers citing the software.&lt;/p&gt;
&lt;h2 id=&quot;concluding-words&quot;&gt;Concluding words&lt;/h2&gt;
&lt;p&gt;Publishing your software on a trusted repository is one of the good practices advocated by the SS-NES project and the eScience Center. With the integration between 4TU.ResearchData and the RSD, researchers automatically benefit from the findability and exposability of the RSD when they publish their software in 4TU.ResearchData. The RSD has become a more complete source of mapping the research software landscape by automatically harvesting 4TU.ResearchData’s software publications.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/enabling-best-practices-for-sustainable--312dc003.C2NZAdf8.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Use Julia to write code that runs on any GPU</title><link>https://blog.esciencecenter.nl/posts/2026-01-15---use-julia-to-write-code-that-runs-on-any-gpu</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2026-01-15---use-julia-to-write-code-that-runs-on-any-gpu</guid><description>&lt;h1 id=&quot;use-julia-to-write-code-that-runs-on-any-gpu&quot;&gt;Use Julia to write code that runs on &lt;em&gt;any&lt;/em&gt; GPU&lt;/h1&gt;
&lt;p&gt;10&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How to write Julia code than can run on any GPU, and why you would want to do that.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As the name implies, the main use of Graphics Processing Units is to process and render things to your screen, such as images, videos, or video games. Almost any device that has a display will have a GPU, although this can also come in the form of a chip integrated in the CPU instead of a separate graphics card. When using applications such as Google Maps, YouTube, or Netflix, the GPU renders the image/video to the screen more quickly and efficiently compared to the CPU. This can result in lower power consumption and a better user experience.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Use Julia to write code that runs on any GPU&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/use-julia-to-write-code-that-runs-on-any-f2817526.BrL0gaPi_1SLleG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@synesthe2ia?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Dimitris Chapsoulas&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To be able to render things to screen quickly, GPUs are able to do a lot of computations in parallel. Besides just graphics rendering, doing many computations in parallel can also come in use elsewhere, such as in (scientific) numerical models, and especially relevant recently, machine learning.&lt;/p&gt;
&lt;p&gt;Before the release of Nvidia’s CUDA platform in 2007, people would use routines designed for graphics processing (like &lt;a href=&quot;https://en.wikipedia.org/wiki/Shader&quot;&gt;shaders&lt;/a&gt;), for non-graphics purposes &lt;a href=&quot;https://doi.org/10.1145/882262.882363&quot;&gt;such as numerical solvers for the Navier-Stokes equations&lt;/a&gt;. However, with CUDA, and soon after also OpenCL, it became more straightforward to write General Purpose GPU code.&lt;/p&gt;
&lt;p&gt;When writing code for CUDA, you are locked into Nvidia designed GPUs, and the code cannot run elsewhere. With OpenCL, it &lt;em&gt;was&lt;/em&gt; possible to write GPU code that can run on many platforms. While it can still work well on most hardware, it is seeing less and less support from Apple and Nvidia, who prefer to push their own proprietary platforms (Metal and CUDA).&lt;/p&gt;
&lt;p&gt;Writing generic GPU code has a few benefits however, as you are not tied to a certain vendor, and there is a larger possible user base and thus more use cases. For example; accelerating a scientific model with GPU impacts both for laptop and high performance computing users.&lt;/p&gt;
&lt;p&gt;To continue writing GPU code that can run on any hardware you can make use of &lt;a href=&quot;https://juliagpu.org&quot;&gt;Julia’s GPU ecosystem&lt;/a&gt;. With the &lt;a href=&quot;https://juliagpu.github.io/KernelAbstractions.jl&quot;&gt;KernelAbstractions.jl&lt;/a&gt; package you can write a kernel (a function that runs on a GPU and executes in parallel) that will work on any of the supported backends. Currently supported are Nvidia’s CUDA, AMD’s ROCm, Apple Metal, and Intel oneAPI. Which means that nearly all modern GPUs are supported, ranging from small laptops to supercomputers.&lt;/p&gt;
&lt;h2 id=&quot;julia-example&quot;&gt;Julia example&lt;/h2&gt;
&lt;p&gt;To get started, after installing Julia, you can initialize arrays on the GPU with the appropriate backend package. As an example, I will use oneAPI, but the code will look the same for the other backends. The following line is the only one that’s machine dependent:&lt;/p&gt;
&lt;p&gt;import oneAPI.oneArray as GPUArrayHaving imported this, we can define arrays on the GPU. In this case a 2D matrix containing single-precision floating point numbers:&lt;/p&gt;
&lt;p&gt;A = GPUArray(ones(Float32, 1024, 1024))Now we can write a kernel. This example comes from the &lt;a href=&quot;https://juliagpu.github.io/KernelAbstractions.jl/stable/quickstart/&quot;&gt;KernelAbstractions documentation&lt;/a&gt;, and will simply multiply every element of the matrix by 2:&lt;/p&gt;
&lt;p&gt;using KernelAbstractions&lt;/p&gt;
&lt;p&gt;@kernel function mul2_kernel(A)
I = @index(Global)
A[I] = 2 * A[I]
endWe can apply the kernel to the matrix &lt;code&gt;A&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;backend = get_backend(A)
mul2_kernel(backend, 64)(A, ndrange=size(A))And that’s it! — &lt;em&gt;Note that &lt;em&gt;&lt;code&gt;64&lt;/code&gt;&lt;/em&gt; is the “workgroup size”, i.e., the number of the array elements assigned to one work group. Tuning this parameter can make the kernel run faster.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;import AcceleratedKernels as AK&lt;/p&gt;
&lt;p&gt;function cpu_copy!(dst, src)
for i in eachindex(src)
dst[i] = src[i]
end
end&lt;/p&gt;
&lt;p&gt;function gpu_copy!(dst, src)
AK.foreachindex(src) do i
dst[i] = src[i]
end
endThe &lt;code&gt;gpu_copy&lt;/code&gt; function will run on GPU if &lt;code&gt;dst&lt;/code&gt; and &lt;code&gt;src&lt;/code&gt; are GPU arrays. Otherwise the function will run on CPU.&lt;/p&gt;
&lt;h2 id=&quot;example-packages&quot;&gt;Example packages&lt;/h2&gt;
&lt;p&gt;There are already some great packages that use KernelAbstractions to run on both CPU and any GPU. One of these is &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S0010465525002504&quot;&gt;WaterLily.jl&lt;/a&gt;, a Computational Fluid Dynamics solver. Because it uses KernelAbstractions, they were able to run simulations not only on Nvidia GPUs, but also on AMD GPUs available on the &lt;a href=&quot;https://www.surf.nl/en/services/compute/lumi&quot;&gt;LUMI supercomputer&lt;/a&gt; (one of the fastest in Europe!).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Use Julia to write code that runs on any GPU&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;500&quot; height=&quot;490&quot; src=&quot;https://blog.esciencecenter.nl/_astro/use-julia-to-write-code-that-runs-on-any-6be9197d.C_s27B6T_19MMwC.webp&quot; srcset=&quot;&quot;&gt;
Simple 2D flow around the Julia logo, simulated using &lt;a href=&quot;https://github.com/WaterLily-jl/WaterLily.jl&quot;&gt;WaterLily.jl&lt;/a&gt; (source: WaterLily.jl)The animation above can be generated on a laptop using the CPU or integrated graphics, but can be easily adapted to a higher resolution or 3D simulation to be run on a supercomputer.&lt;/p&gt;
&lt;p&gt;The Julia GPU &lt;a href=&quot;https://juliagpu.org/showcases/&quot;&gt;showcase page&lt;/a&gt; has many more examples ranging from climate models to bioinformatics.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By using Julia’s generic GPU framework, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run and debug code locally, on your laptop using your CPU or GPU&lt;/li&gt;
&lt;li&gt;have a larger community of users who can run the code on their own devices&lt;/li&gt;
&lt;li&gt;deploy the code on any supercomputer, e.g., both Snellius (Nvidia GPUs) and LUMI (AMD GPUs)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So next time you need code to be fast and portable, consider using Julia to write code that can run fast, anywhere.&lt;/p&gt;</description><pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;use-julia-to-write-code-that-runs-on-any-gpu&quot;&gt;Use Julia to write code that runs on &lt;em&gt;any&lt;/em&gt; GPU&lt;/h1&gt;
&lt;p&gt;10&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How to write Julia code than can run on any GPU, and why you would want to do that.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As the name implies, the main use of Graphics Processing Units is to process and render things to your screen, such as images, videos, or video games. Almost any device that has a display will have a GPU, although this can also come in the form of a chip integrated in the CPU instead of a separate graphics card. When using applications such as Google Maps, YouTube, or Netflix, the GPU renders the image/video to the screen more quickly and efficiently compared to the CPU. This can result in lower power consumption and a better user experience.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Use Julia to write code that runs on any GPU&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/use-julia-to-write-code-that-runs-on-any-f2817526.BrL0gaPi_1SLleG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@synesthe2ia?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Dimitris Chapsoulas&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To be able to render things to screen quickly, GPUs are able to do a lot of computations in parallel. Besides just graphics rendering, doing many computations in parallel can also come in use elsewhere, such as in (scientific) numerical models, and especially relevant recently, machine learning.&lt;/p&gt;
&lt;p&gt;Before the release of Nvidia’s CUDA platform in 2007, people would use routines designed for graphics processing (like &lt;a href=&quot;https://en.wikipedia.org/wiki/Shader&quot;&gt;shaders&lt;/a&gt;), for non-graphics purposes &lt;a href=&quot;https://doi.org/10.1145/882262.882363&quot;&gt;such as numerical solvers for the Navier-Stokes equations&lt;/a&gt;. However, with CUDA, and soon after also OpenCL, it became more straightforward to write General Purpose GPU code.&lt;/p&gt;
&lt;p&gt;When writing code for CUDA, you are locked into Nvidia designed GPUs, and the code cannot run elsewhere. With OpenCL, it &lt;em&gt;was&lt;/em&gt; possible to write GPU code that can run on many platforms. While it can still work well on most hardware, it is seeing less and less support from Apple and Nvidia, who prefer to push their own proprietary platforms (Metal and CUDA).&lt;/p&gt;
&lt;p&gt;Writing generic GPU code has a few benefits however, as you are not tied to a certain vendor, and there is a larger possible user base and thus more use cases. For example; accelerating a scientific model with GPU impacts both for laptop and high performance computing users.&lt;/p&gt;
&lt;p&gt;To continue writing GPU code that can run on any hardware you can make use of &lt;a href=&quot;https://juliagpu.org&quot;&gt;Julia’s GPU ecosystem&lt;/a&gt;. With the &lt;a href=&quot;https://juliagpu.github.io/KernelAbstractions.jl&quot;&gt;KernelAbstractions.jl&lt;/a&gt; package you can write a kernel (a function that runs on a GPU and executes in parallel) that will work on any of the supported backends. Currently supported are Nvidia’s CUDA, AMD’s ROCm, Apple Metal, and Intel oneAPI. Which means that nearly all modern GPUs are supported, ranging from small laptops to supercomputers.&lt;/p&gt;
&lt;h2 id=&quot;julia-example&quot;&gt;Julia example&lt;/h2&gt;
&lt;p&gt;To get started, after installing Julia, you can initialize arrays on the GPU with the appropriate backend package. As an example, I will use oneAPI, but the code will look the same for the other backends. The following line is the only one that’s machine dependent:&lt;/p&gt;
&lt;p&gt;import oneAPI.oneArray as GPUArrayHaving imported this, we can define arrays on the GPU. In this case a 2D matrix containing single-precision floating point numbers:&lt;/p&gt;
&lt;p&gt;A = GPUArray(ones(Float32, 1024, 1024))Now we can write a kernel. This example comes from the &lt;a href=&quot;https://juliagpu.github.io/KernelAbstractions.jl/stable/quickstart/&quot;&gt;KernelAbstractions documentation&lt;/a&gt;, and will simply multiply every element of the matrix by 2:&lt;/p&gt;
&lt;p&gt;using KernelAbstractions&lt;/p&gt;
&lt;p&gt;@kernel function mul2_kernel(A)
I = @index(Global)
A[I] = 2 * A[I]
endWe can apply the kernel to the matrix &lt;code&gt;A&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;backend = get_backend(A)
mul2_kernel(backend, 64)(A, ndrange=size(A))And that’s it! — &lt;em&gt;Note that &lt;em&gt;&lt;code&gt;64&lt;/code&gt;&lt;/em&gt; is the “workgroup size”, i.e., the number of the array elements assigned to one work group. Tuning this parameter can make the kernel run faster.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;import AcceleratedKernels as AK&lt;/p&gt;
&lt;p&gt;function cpu_copy!(dst, src)
for i in eachindex(src)
dst[i] = src[i]
end
end&lt;/p&gt;
&lt;p&gt;function gpu_copy!(dst, src)
AK.foreachindex(src) do i
dst[i] = src[i]
end
endThe &lt;code&gt;gpu_copy&lt;/code&gt; function will run on GPU if &lt;code&gt;dst&lt;/code&gt; and &lt;code&gt;src&lt;/code&gt; are GPU arrays. Otherwise the function will run on CPU.&lt;/p&gt;
&lt;h2 id=&quot;example-packages&quot;&gt;Example packages&lt;/h2&gt;
&lt;p&gt;There are already some great packages that use KernelAbstractions to run on both CPU and any GPU. One of these is &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S0010465525002504&quot;&gt;WaterLily.jl&lt;/a&gt;, a Computational Fluid Dynamics solver. Because it uses KernelAbstractions, they were able to run simulations not only on Nvidia GPUs, but also on AMD GPUs available on the &lt;a href=&quot;https://www.surf.nl/en/services/compute/lumi&quot;&gt;LUMI supercomputer&lt;/a&gt; (one of the fastest in Europe!).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Use Julia to write code that runs on any GPU&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;500&quot; height=&quot;490&quot; src=&quot;https://blog.esciencecenter.nl/_astro/use-julia-to-write-code-that-runs-on-any-6be9197d.C_s27B6T_19MMwC.webp&quot; srcset=&quot;&quot;&gt;
Simple 2D flow around the Julia logo, simulated using &lt;a href=&quot;https://github.com/WaterLily-jl/WaterLily.jl&quot;&gt;WaterLily.jl&lt;/a&gt; (source: WaterLily.jl)The animation above can be generated on a laptop using the CPU or integrated graphics, but can be easily adapted to a higher resolution or 3D simulation to be run on a supercomputer.&lt;/p&gt;
&lt;p&gt;The Julia GPU &lt;a href=&quot;https://juliagpu.org/showcases/&quot;&gt;showcase page&lt;/a&gt; has many more examples ranging from climate models to bioinformatics.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By using Julia’s generic GPU framework, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run and debug code locally, on your laptop using your CPU or GPU&lt;/li&gt;
&lt;li&gt;have a larger community of users who can run the code on their own devices&lt;/li&gt;
&lt;li&gt;deploy the code on any supercomputer, e.g., both Snellius (Nvidia GPUs) and LUMI (AMD GPUs)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So next time you need code to be fast and portable, consider using Julia to write code that can run fast, anywhere.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/use-julia-to-write-code-that-runs-on-any-f2817526.BrL0gaPi.jpg" medium="image"/><author>Bart Schilperoort</author></item><item><title>Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup</title><link>https://blog.esciencecenter.nl/posts/2025-12-09---strengthening-research-software-management-in-dutch-umcs-hig</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-12-09---strengthening-research-software-management-in-dutch-umcs-hig</guid><description>&lt;h1 id=&quot;strengthening-research-software-management-in-dutch-umcs-highlights-from-the-second-dreams-community-meetup&quot;&gt;&lt;strong&gt;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Written by Anna Niehues, Özgün Balaban, Magnus Palmblad, Mariia Steeghs-Turchina, and the DReaMS Community&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dreams-community.github.io/about/&quot;&gt;DReaMS&lt;/a&gt; is a collaborative community formed by Digital Competence Centers (DCCs) from Dutch University Medical Centers (UMCs), committed to advancing research software management (RSM). During the LUMC Research Data Day on 23 September 2025, network members came together in Leiden for the second community meetup. The event aimed to align practices and foster collaboration across institutions, building on the momentum of the first meetup in 2024 (&lt;a href=&quot;https://blog.esciencecenter.nl/how-is-research-software-managed-at-umcs-insights-from-a-first-meetup-4181e9626a60&quot;&gt;Pronk 2024&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;565&quot; height=&quot;313&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-3878cbea.CcpX6cFs_Z1FbAdX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Research Software includes source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose” &lt;em&gt;(&lt;/em&gt;&lt;a href=&quot;https://doi.org/10.5281/zenodo.5504016&quot;&gt;&lt;em&gt;Gruenpeter et al. 2021&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Dutch UMCs, effectively managing research software is essential to ensuring reproducibility, efficiency, and reuse, while supporting compliance with Open Science policies and regulatory requirements.&lt;/p&gt;
&lt;h2 id=&quot;opening-session&quot;&gt;Opening Session&lt;/h2&gt;
&lt;p&gt;The opening session, co-chaired by Anna Niehues and Thomas Pronk, featured updates shared by participants, setting the stage for a day of engaging discussions and knowledge exchange. The meetup provided a valuable opportunity for the participating UMCs and national infrastructure partners — the Netherlands eScience Center and ELIXIR-NL — to connect, share updates, and explore key topics. The discussions focused on developing RSM guidelines, strategies for software sustainability, providing training, and identifying connection points to strengthen joint efforts.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;533&quot; height=&quot;256&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-0e793bd0.Cs3AvKJY_2f6Ib0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;towards-research-software-management-guidelines-for-dutch-umcs&quot;&gt;Towards Research Software Management Guidelines for Dutch UMCs&lt;/h2&gt;
&lt;p&gt;During the session on Research Software Management Guidelines, co-chaired by Mariia Steeghs-Turchina and Carlos Martinez, participants identified common questions that researchers have, mapped available support, and identified gaps across Dutch UMCs. We explored what researchers need most, how institutions respond, and where key gaps remain.&lt;/p&gt;
&lt;p&gt;Researchers regularly seek support on version control, Git or GitHub usage, and software maintenance. This indicates growing awareness but also uncertainty about best practices. In the absence of clear guidelines, RSM support staff often direct researchers to online tutorials, the&lt;a href=&quot;https://software-carpentry.org/&quot;&gt; Software Carpentry&lt;/a&gt; programme, the&lt;a href=&quot;https://everse.software/RSQKit/&quot;&gt; Research Software Quality Toolkit for Sciences (RSQkit)&lt;/a&gt; and institutional Git courses, as well as AI-powered coding assistants. These dispersed resources may be difficult to navigate and a shared resource hub connecting training and guiding materials could provide added value to researchers. Better recognition mechanisms, such as software citation, are also needed to incentivise the following best practices.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;343&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-cb0ad5db.CLv39PIQ_nnUCP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-sustainability-long-term-maintenance-and-reusability&quot;&gt;Research Software Sustainability: Long-term Maintenance and Reusability&lt;/h2&gt;
&lt;p&gt;During the breakout session on research software sustainability, which was co-chaired by Magnus Palmblad and Sietse Rispens, the challenges of maintaining software, especially when the original developer is no longer available, were discussed. Possible internal and external solutions were also explored.&lt;/p&gt;
&lt;p&gt;A critical phase occurs between the realisation that a particular piece of software has wider applicability and the developer’s departure, often after completing their studies or postdoctoral research. During this period, it is important to plan for sustainability as early as possible, with a focus on documenting the code, creating software metadata and involving more people in the development process.&lt;/p&gt;
&lt;p&gt;Good habits, such as writing code that is both readable and well-documented, encourages others to contribute to the codebase and help to sustain it. Students are often highly motivated to write software from scratch. While this is an important experience, students making significant contributions by adding novel functionality to existing projects should be rewarded equally. This requires a change in culture, away from “yet another tool to do X” to having more people contribute to community-supported open science projects. Training on how to use Git or how to contribute to community projects is essential. Journal editors should be encouraged to consider such contributions as potentially equally novel and useful as stand-alone software.&lt;/p&gt;
&lt;h2 id=&quot;research-software-training-through-the-lens-of-fair-and-open-science&quot;&gt;Research Software Training Through the Lens of FAIR and Open Science&lt;/h2&gt;
&lt;p&gt;While the first DReaMS meetup in 2024 identified a lack of intermediate-level training as a key challenge, this year’s breakout session on software training, co-chaired by Özgün Balaban and Bauke van der Velde, uncovered gaps in fundamental research software training.&lt;/p&gt;
&lt;p&gt;It is often challenging to identify suitable communication channels through which to raise awareness among new PhD students and researchers of research software practices and available training and resources. While some topics, such as Git, which also have a high popularity, are covered repeatedly by training programmes, others are underrepresented. These include, e.g., conceptual-level training for beginners, good coding practices, software management, documentation, and AI-supported development. A lack of balanced training coverage also poses a risk to the sustainability of research software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-f500b663.BJT5BEe7_Zgh0Fk.webp&quot; srcset=&quot;&quot;&gt;
The activities identified as being effective in increasing awareness include Coding CAFEs (&lt;a href=&quot;https://code-cafes-nl.github.io/cafe_playbook/&quot;&gt;Moopen et al. 2023&lt;/a&gt;), mentorship programmes, peer learning, peer reviews of software documentation, and guest lectures. Such formats do not only build practical skills, but also strengthen communities.&lt;/p&gt;
&lt;p&gt;Suggested collaboration opportunities include sharing course materials across institutions, setting up trainer communication channels, such as&lt;a href=&quot;https://researchsoftwaretraining.nl/&quot;&gt; RST-NL&lt;/a&gt;, and offering joint workshops. The next steps will be discussed during upcoming online meetings of the DReaMS community.&lt;/p&gt;
&lt;p&gt;A common challenge in the current training landscape and in the sustainability of research software is that initiatives are fragmented, resulting in uneven coverage across the software development lifecycle. A more coherent approach is required to address this, involving clear policies, long-term planning, secure funding and a sufficient workforce aligned with institutional project needs.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-the-dreams-community&quot;&gt;Get in Touch With the DReaMS Community&lt;/h2&gt;
&lt;p&gt;Take a look at our &lt;a href=&quot;https://dreams-community.github.io/&quot;&gt;website&lt;/a&gt; and get in touch with us via the community members.&lt;/p&gt;
&lt;p&gt;This blog is cross-posted here: &lt;a href=&quot;https://dreams-community.github.io/blog/second-meetup/&quot;&gt;https://dreams-community.github.io/blog/second-meetup/&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 09 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;strengthening-research-software-management-in-dutch-umcs-highlights-from-the-second-dreams-community-meetup&quot;&gt;&lt;strong&gt;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Written by Anna Niehues, Özgün Balaban, Magnus Palmblad, Mariia Steeghs-Turchina, and the DReaMS Community&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dreams-community.github.io/about/&quot;&gt;DReaMS&lt;/a&gt; is a collaborative community formed by Digital Competence Centers (DCCs) from Dutch University Medical Centers (UMCs), committed to advancing research software management (RSM). During the LUMC Research Data Day on 23 September 2025, network members came together in Leiden for the second community meetup. The event aimed to align practices and foster collaboration across institutions, building on the momentum of the first meetup in 2024 (&lt;a href=&quot;https://blog.esciencecenter.nl/how-is-research-software-managed-at-umcs-insights-from-a-first-meetup-4181e9626a60&quot;&gt;Pronk 2024&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;565&quot; height=&quot;313&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-3878cbea.CcpX6cFs_Z1FbAdX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Research Software includes source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose” &lt;em&gt;(&lt;/em&gt;&lt;a href=&quot;https://doi.org/10.5281/zenodo.5504016&quot;&gt;&lt;em&gt;Gruenpeter et al. 2021&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Dutch UMCs, effectively managing research software is essential to ensuring reproducibility, efficiency, and reuse, while supporting compliance with Open Science policies and regulatory requirements.&lt;/p&gt;
&lt;h2 id=&quot;opening-session&quot;&gt;Opening Session&lt;/h2&gt;
&lt;p&gt;The opening session, co-chaired by Anna Niehues and Thomas Pronk, featured updates shared by participants, setting the stage for a day of engaging discussions and knowledge exchange. The meetup provided a valuable opportunity for the participating UMCs and national infrastructure partners — the Netherlands eScience Center and ELIXIR-NL — to connect, share updates, and explore key topics. The discussions focused on developing RSM guidelines, strategies for software sustainability, providing training, and identifying connection points to strengthen joint efforts.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;533&quot; height=&quot;256&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-0e793bd0.Cs3AvKJY_2f6Ib0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;towards-research-software-management-guidelines-for-dutch-umcs&quot;&gt;Towards Research Software Management Guidelines for Dutch UMCs&lt;/h2&gt;
&lt;p&gt;During the session on Research Software Management Guidelines, co-chaired by Mariia Steeghs-Turchina and Carlos Martinez, participants identified common questions that researchers have, mapped available support, and identified gaps across Dutch UMCs. We explored what researchers need most, how institutions respond, and where key gaps remain.&lt;/p&gt;
&lt;p&gt;Researchers regularly seek support on version control, Git or GitHub usage, and software maintenance. This indicates growing awareness but also uncertainty about best practices. In the absence of clear guidelines, RSM support staff often direct researchers to online tutorials, the&lt;a href=&quot;https://software-carpentry.org/&quot;&gt; Software Carpentry&lt;/a&gt; programme, the&lt;a href=&quot;https://everse.software/RSQKit/&quot;&gt; Research Software Quality Toolkit for Sciences (RSQkit)&lt;/a&gt; and institutional Git courses, as well as AI-powered coding assistants. These dispersed resources may be difficult to navigate and a shared resource hub connecting training and guiding materials could provide added value to researchers. Better recognition mechanisms, such as software citation, are also needed to incentivise the following best practices.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;343&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-cb0ad5db.CLv39PIQ_nnUCP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-sustainability-long-term-maintenance-and-reusability&quot;&gt;Research Software Sustainability: Long-term Maintenance and Reusability&lt;/h2&gt;
&lt;p&gt;During the breakout session on research software sustainability, which was co-chaired by Magnus Palmblad and Sietse Rispens, the challenges of maintaining software, especially when the original developer is no longer available, were discussed. Possible internal and external solutions were also explored.&lt;/p&gt;
&lt;p&gt;A critical phase occurs between the realisation that a particular piece of software has wider applicability and the developer’s departure, often after completing their studies or postdoctoral research. During this period, it is important to plan for sustainability as early as possible, with a focus on documenting the code, creating software metadata and involving more people in the development process.&lt;/p&gt;
&lt;p&gt;Good habits, such as writing code that is both readable and well-documented, encourages others to contribute to the codebase and help to sustain it. Students are often highly motivated to write software from scratch. While this is an important experience, students making significant contributions by adding novel functionality to existing projects should be rewarded equally. This requires a change in culture, away from “yet another tool to do X” to having more people contribute to community-supported open science projects. Training on how to use Git or how to contribute to community projects is essential. Journal editors should be encouraged to consider such contributions as potentially equally novel and useful as stand-alone software.&lt;/p&gt;
&lt;h2 id=&quot;research-software-training-through-the-lens-of-fair-and-open-science&quot;&gt;Research Software Training Through the Lens of FAIR and Open Science&lt;/h2&gt;
&lt;p&gt;While the first DReaMS meetup in 2024 identified a lack of intermediate-level training as a key challenge, this year’s breakout session on software training, co-chaired by Özgün Balaban and Bauke van der Velde, uncovered gaps in fundamental research software training.&lt;/p&gt;
&lt;p&gt;It is often challenging to identify suitable communication channels through which to raise awareness among new PhD students and researchers of research software practices and available training and resources. While some topics, such as Git, which also have a high popularity, are covered repeatedly by training programmes, others are underrepresented. These include, e.g., conceptual-level training for beginners, good coding practices, software management, documentation, and AI-supported development. A lack of balanced training coverage also poses a risk to the sustainability of research software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strengthening Research Software Management in Dutch UMCs: Highlights from the Second DReaMS Community Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-f500b663.BJT5BEe7_Zgh0Fk.webp&quot; srcset=&quot;&quot;&gt;
The activities identified as being effective in increasing awareness include Coding CAFEs (&lt;a href=&quot;https://code-cafes-nl.github.io/cafe_playbook/&quot;&gt;Moopen et al. 2023&lt;/a&gt;), mentorship programmes, peer learning, peer reviews of software documentation, and guest lectures. Such formats do not only build practical skills, but also strengthen communities.&lt;/p&gt;
&lt;p&gt;Suggested collaboration opportunities include sharing course materials across institutions, setting up trainer communication channels, such as&lt;a href=&quot;https://researchsoftwaretraining.nl/&quot;&gt; RST-NL&lt;/a&gt;, and offering joint workshops. The next steps will be discussed during upcoming online meetings of the DReaMS community.&lt;/p&gt;
&lt;p&gt;A common challenge in the current training landscape and in the sustainability of research software is that initiatives are fragmented, resulting in uneven coverage across the software development lifecycle. A more coherent approach is required to address this, involving clear policies, long-term planning, secure funding and a sufficient workforce aligned with institutional project needs.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-the-dreams-community&quot;&gt;Get in Touch With the DReaMS Community&lt;/h2&gt;
&lt;p&gt;Take a look at our &lt;a href=&quot;https://dreams-community.github.io/&quot;&gt;website&lt;/a&gt; and get in touch with us via the community members.&lt;/p&gt;
&lt;p&gt;This blog is cross-posted here: &lt;a href=&quot;https://dreams-community.github.io/blog/second-meetup/&quot;&gt;https://dreams-community.github.io/blog/second-meetup/&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/strengthening-research-software-manageme-3878cbea.CcpX6cFs.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>A special gift (December 5th)</title><link>https://blog.esciencecenter.nl/posts/2025-12-05---a-special-gift-december-5th</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-12-05---a-special-gift-december-5th</guid><description>&lt;h2 id=&quot;ode-to-the-research-software-engineer&quot;&gt;Ode to the research software engineer&lt;/h2&gt;
&lt;p&gt;8&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sinterklaas is a Dutch tradition featuring Saint Nicholas, who is said to arrive from Spain with his helpers and travel across rooftops to deliver small gifts and poems. Today, the Sint is visiting the eScience Center.&lt;/p&gt;
&lt;p&gt;As days are getting colder and the nights becoming long,
we make our office cozy with hot chocolate and song.
The fireplace is lit albeit on the conference screen;
it is an office atmosphere unlike you’ve ever seen.&lt;/p&gt;
&lt;p&gt;We sit together ‘round the fire and wait for what’s to come,
when suddenly we hear a heavy beating, like a drum.
We chase towards the office entrance seeing who is there,
but nothing’s to be seen except a letter near the stairs.&lt;/p&gt;
&lt;p&gt;The letter reads “My dearest friends and fellow RSEs,
please go back to your conference room and make yourself at ease.
You’ve made me feel so welcome and I brought you in return
a bundle of delights for you to live and love and learn.”&lt;/p&gt;
&lt;p&gt;Curious we sat once more around the makeshift fire,
stunned to find some gifts that any scientist should desire.
A bag full of best practices to make your software shine,
sparked with digital literacy and beautiful design.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A special gift (December 5th)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-special-gift-december-5th-d7100f1d.BgmdqWgn_21oTQh.webp&quot; srcset=&quot;&quot;&gt;
Chocolate letters are part of the traditionTo start it off we first unpacked a gift so smart and bright:
a coffee mug for every soul who codes late in the night.
On it was a text that read “your 9 to 5 is fine,
but if you rather work at night, some caffeine’s divine”.&lt;/p&gt;
&lt;p&gt;The next gift comes in handy for a project big or small
a touch of git to help you keep your code under control.
A branching scheme, a tidy diff, a history clear and clean
A present many researchers admit they’ve never seen.&lt;/p&gt;
&lt;p&gt;Then slips beneath the office door a test suite neatly wrapped,
with unit tests and fixtures all meticulously mapped.
“Oh generous Sint,” we all proclaim, “now bugs no more appear!”
(Though secretly he knows they will, but less, and less severe.)&lt;/p&gt;
&lt;p&gt;A handbook tied with twine he leaves, with pretty illustrations
on licenses and versioning and good documentation.
For knowledge lost is hard to find when months have come and gone,
but with this helpful guide the happy coding can go on.&lt;/p&gt;
&lt;p&gt;Sint conjures CI pipelines high above us in the cloud,
where automated checks and builds assemble clean and proud
A magical parade of green ticks marching in a row,
the sweetest sight for anyone who’s watched code fail to grow.&lt;/p&gt;
&lt;p&gt;But most of all, the Sint bestows a gift both rare and dear:
the quiet craft, the steady hand, the engineer’s career.
For research needs more than ideas just drifting in the air;
it needs the ones who shape the tools that make discovery FAIR.&lt;/p&gt;
&lt;p&gt;So here’s an ode to those who bridge two worlds with practiced grace:
who think in algorithms yet they keep the human pace.
Who build, maintain, refactor, teach, who safeguard truth with care,
the research software engineers, the heroes unaware.&lt;/p&gt;
&lt;p&gt;And as the Sint sails home again across December seas,
he leaves one final message carried softly by the breeze:
“Good science thrives when code is sound, transparent, shared, and clear,
so honour those who make it so; support them through the year.”&lt;/p&gt;
&lt;p&gt;This poem has been crafted in collaboration with AI-Piet*&lt;/p&gt;</description><pubDate>Fri, 05 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;ode-to-the-research-software-engineer&quot;&gt;Ode to the research software engineer&lt;/h2&gt;
&lt;p&gt;8&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sinterklaas is a Dutch tradition featuring Saint Nicholas, who is said to arrive from Spain with his helpers and travel across rooftops to deliver small gifts and poems. Today, the Sint is visiting the eScience Center.&lt;/p&gt;
&lt;p&gt;As days are getting colder and the nights becoming long,
we make our office cozy with hot chocolate and song.
The fireplace is lit albeit on the conference screen;
it is an office atmosphere unlike you’ve ever seen.&lt;/p&gt;
&lt;p&gt;We sit together ‘round the fire and wait for what’s to come,
when suddenly we hear a heavy beating, like a drum.
We chase towards the office entrance seeing who is there,
but nothing’s to be seen except a letter near the stairs.&lt;/p&gt;
&lt;p&gt;The letter reads “My dearest friends and fellow RSEs,
please go back to your conference room and make yourself at ease.
You’ve made me feel so welcome and I brought you in return
a bundle of delights for you to live and love and learn.”&lt;/p&gt;
&lt;p&gt;Curious we sat once more around the makeshift fire,
stunned to find some gifts that any scientist should desire.
A bag full of best practices to make your software shine,
sparked with digital literacy and beautiful design.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A special gift (December 5th)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-special-gift-december-5th-d7100f1d.BgmdqWgn_21oTQh.webp&quot; srcset=&quot;&quot;&gt;
Chocolate letters are part of the traditionTo start it off we first unpacked a gift so smart and bright:
a coffee mug for every soul who codes late in the night.
On it was a text that read “your 9 to 5 is fine,
but if you rather work at night, some caffeine’s divine”.&lt;/p&gt;
&lt;p&gt;The next gift comes in handy for a project big or small
a touch of git to help you keep your code under control.
A branching scheme, a tidy diff, a history clear and clean
A present many researchers admit they’ve never seen.&lt;/p&gt;
&lt;p&gt;Then slips beneath the office door a test suite neatly wrapped,
with unit tests and fixtures all meticulously mapped.
“Oh generous Sint,” we all proclaim, “now bugs no more appear!”
(Though secretly he knows they will, but less, and less severe.)&lt;/p&gt;
&lt;p&gt;A handbook tied with twine he leaves, with pretty illustrations
on licenses and versioning and good documentation.
For knowledge lost is hard to find when months have come and gone,
but with this helpful guide the happy coding can go on.&lt;/p&gt;
&lt;p&gt;Sint conjures CI pipelines high above us in the cloud,
where automated checks and builds assemble clean and proud
A magical parade of green ticks marching in a row,
the sweetest sight for anyone who’s watched code fail to grow.&lt;/p&gt;
&lt;p&gt;But most of all, the Sint bestows a gift both rare and dear:
the quiet craft, the steady hand, the engineer’s career.
For research needs more than ideas just drifting in the air;
it needs the ones who shape the tools that make discovery FAIR.&lt;/p&gt;
&lt;p&gt;So here’s an ode to those who bridge two worlds with practiced grace:
who think in algorithms yet they keep the human pace.
Who build, maintain, refactor, teach, who safeguard truth with care,
the research software engineers, the heroes unaware.&lt;/p&gt;
&lt;p&gt;And as the Sint sails home again across December seas,
he leaves one final message carried softly by the breeze:
“Good science thrives when code is sound, transparent, shared, and clear,
so honour those who make it so; support them through the year.”&lt;/p&gt;
&lt;p&gt;This poem has been crafted in collaboration with AI-Piet*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-special-gift-december-5th-d7100f1d.BgmdqWgn.jpeg" medium="image"/><author>Peter Kalverla</author></item><item><title>The story map</title><link>https://blog.esciencecenter.nl/posts/2025-11-26---the-story-map</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-11-26---the-story-map</guid><description>&lt;p&gt;A framework for story-building&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-2090d51d.29pOVV-H_Z1ciFKC.webp&quot; srcset=&quot;&quot;&gt;
We are all natural-born storytellers. Or at the very least, storylisteners. The same drive lies behind a gathering around the fireplace, a night at the movies or listening to a podcast on your morning run: our brain’s hunger for narratives.&lt;/p&gt;
&lt;p&gt;Our brains are literally wired for storytelling, and yet creating a story can be challenging.&lt;/p&gt;
&lt;p&gt;This tutorial presents a strategy for simplifying the creative process of building a story. And as in any good story, we have to start from the beginning.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-story&quot;&gt;What is a story?&lt;/h2&gt;
&lt;p&gt;If you ever experienced the so-called &lt;em&gt;“blank page syndrome”&lt;/em&gt;, chances are that it originated not from a lack of ideas to write about, but from an overwhelming, chaotic pile of them.&lt;/p&gt;
&lt;p&gt;A story, any story, is linear. It doesn’t matter if it is a text, a speech, a movie or even a scientific publication: it will progress from a beginning to an end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;More specifically, any story will be &lt;strong&gt;consumed&lt;/strong&gt;&lt;/em&gt;* on a linear way. Even a story which content is structured in a non-chronological order has a beginning and an end.*&lt;/p&gt;
&lt;p&gt;And here comes the challenge: our thoughts are rarely that linear. Most people entertain multiple thoughts simultaneously, or quickly switch from one to the other. It takes a conscious effort to order them into a coherent narrative.&lt;/p&gt;
&lt;h2 id=&quot;embracing-chaos&quot;&gt;Embracing chaos&lt;/h2&gt;
&lt;p&gt;Instead of getting frustrated about the chaotic nature of our thoughts, let’s just embrace it. Our thoughts are fine just how they are.&lt;/p&gt;
&lt;p&gt;Of course, it is not that practical to have our working memory juggling them all at once. So let’s free our memory and outsource them to… a piece of paper! Just write them down.&lt;/p&gt;
&lt;p&gt;My advice is to do it like in the figure below, in small squares, with no pre-defined order. Just drop them around as if they were LEGO bricks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-4c4616af.DDI9Un7Q_1n2PSp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;structuring-your-thoughts-the-building-blocks&quot;&gt;Structuring your thoughts: the building blocks&lt;/h2&gt;
&lt;p&gt;The challenge is set! Our goal is to build something with these bricks. But first we have to see our bricks, identify them, make sure we’re not missing any. Almost &lt;em&gt;feel&lt;/em&gt; them.&lt;/p&gt;
&lt;p&gt;Take a moment to look at your building blocks. Very likely, you’ll notice some of them are related. This relationship can be logical, narrative, chronological, … Draw a line between them if that’s the case.&lt;/p&gt;
&lt;p&gt;I suggest using &lt;strong&gt;solid lines for strong relatedness&lt;/strong&gt;, and &lt;strong&gt;dashed lines for less clear relatedness&lt;/strong&gt;. We are starting to have &lt;strong&gt;some&lt;/strong&gt; structure! We are slowly creating order out of chaos!¹&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-2090d51d.29pOVV-H_Z1ciFKC.webp&quot; srcset=&quot;&quot;&gt;
At this stage, you might realize some building blocks are missing. When that’s the case, just add them. You might also notice some building blocks are redundant. Well, just merge those together. You might even judge some of the blocks to be unnecessary. Drop those without hesitation! Nothing creates more order out of chaos than reducing the amount of moving parts!&lt;/p&gt;
&lt;h2 id=&quot;navigating-your-thoughts-the-story-map&quot;&gt;Navigating your thoughts: the story map&lt;/h2&gt;
&lt;p&gt;The ultimate goal would be to navigate your thoughts. And I don’t use the verb navigate lightly: you literally want to create a route from the beginning to the end. The diagram above will be very useful for achieving this.&lt;/p&gt;
&lt;p&gt;To begin with, the diagram shows clearly what the core topics are. This allows for drawing a first, straightforward route that covers just the basics. If your audience is already knowledgeable about the topic and your time is limited, this route is an excellent choice:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-07f540b2.6KPo7hGG_2bI9Do.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For many people, especially in academia, skipping information feels wrong. In the verge of immoral.*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;What we did above is tailoring your materials to our audience (sounds better than skipping, doesn’t it?). And yes, we did it by eliminating some of them. Actually, this is going to happen often, and it is very good news. Less complexity, less moving parts; less is more, remember?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Effective communication is not about turning everything that we write or say into a self-contained compendium, but about providing chunks that can be reasonably digested in whatever context they are delivered.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If your time is less limited, you can consider taking a detour and dropping an anecdote to make the experience more enjoyable:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-d2a0192d.DrWYqMrK_ZvO4Ro.webp&quot; srcset=&quot;&quot;&gt;
Last but not least, if you have the possibility of expanding as much as you want, you might want to cover all the topics. In such a case, a reasonable route will look like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-363e168b.B9ZQjHOK_oudXO.webp&quot; srcset=&quot;&quot;&gt;
In the figure below we summarize three possible routes we could envision for the same material:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-60695bb7.DPKFnKkk_Z1KjG0F.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;applications&quot;&gt;Applications&lt;/h2&gt;
&lt;p&gt;I’ve used the described framework in many settings where storytelling played a role. Perhaps this sounds limited, but believe me: storytelling is everywhere. I used it for, among others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scientific presentations&lt;/li&gt;
&lt;li&gt;Comedy monologues&lt;/li&gt;
&lt;li&gt;Software tutorials&lt;/li&gt;
&lt;li&gt;My own PhD dissertation&lt;/li&gt;
&lt;li&gt;Blog posts&lt;/li&gt;
&lt;li&gt;A strategic plan for a research institution&lt;/li&gt;
&lt;li&gt;Publications in research journals (real-life example &lt;a href=&quot;https://fuga.naukas.com/files/2021/03/IMG_20190301_091759-768x404.jpg&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A theater play&lt;/li&gt;
&lt;li&gt;And also for this text you are reading now&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I honestly encourage you to give it a try next time you face a blank page. It works wonders!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;This piece was born in the context of the &lt;a href=&quot;https://research-software-directory.org/projects/data-storytelling&quot;&gt;Data Storytelling project&lt;/a&gt;. Thanks to &lt;a href=&quot;https://www.esciencecenter.nl/team/jesse-gonzalez/&quot;&gt;Jesse González&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/kody-moodley/&quot;&gt;Kody Moodley&lt;/a&gt; for their feedback.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For those of you interested in knowledge management, chances are this method will remind you of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Zettelkasten&quot;&gt;Zettelkasten note-taking method&lt;/a&gt;, a strong, even more structured form of the ideas presented here. Also, you’d be interested in knowing that some software applications, such as &lt;a href=&quot;https://logseq.com/&quot;&gt;logseq&lt;/a&gt; or &lt;a href=&quot;https://obsidian.md/&quot;&gt;Obsidian&lt;/a&gt;, are designed with this model in mind.↩&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A framework for story-building&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-2090d51d.29pOVV-H_Z1ciFKC.webp&quot; srcset=&quot;&quot;&gt;
We are all natural-born storytellers. Or at the very least, storylisteners. The same drive lies behind a gathering around the fireplace, a night at the movies or listening to a podcast on your morning run: our brain’s hunger for narratives.&lt;/p&gt;
&lt;p&gt;Our brains are literally wired for storytelling, and yet creating a story can be challenging.&lt;/p&gt;
&lt;p&gt;This tutorial presents a strategy for simplifying the creative process of building a story. And as in any good story, we have to start from the beginning.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-story&quot;&gt;What is a story?&lt;/h2&gt;
&lt;p&gt;If you ever experienced the so-called &lt;em&gt;“blank page syndrome”&lt;/em&gt;, chances are that it originated not from a lack of ideas to write about, but from an overwhelming, chaotic pile of them.&lt;/p&gt;
&lt;p&gt;A story, any story, is linear. It doesn’t matter if it is a text, a speech, a movie or even a scientific publication: it will progress from a beginning to an end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;More specifically, any story will be &lt;strong&gt;consumed&lt;/strong&gt;&lt;/em&gt;* on a linear way. Even a story which content is structured in a non-chronological order has a beginning and an end.*&lt;/p&gt;
&lt;p&gt;And here comes the challenge: our thoughts are rarely that linear. Most people entertain multiple thoughts simultaneously, or quickly switch from one to the other. It takes a conscious effort to order them into a coherent narrative.&lt;/p&gt;
&lt;h2 id=&quot;embracing-chaos&quot;&gt;Embracing chaos&lt;/h2&gt;
&lt;p&gt;Instead of getting frustrated about the chaotic nature of our thoughts, let’s just embrace it. Our thoughts are fine just how they are.&lt;/p&gt;
&lt;p&gt;Of course, it is not that practical to have our working memory juggling them all at once. So let’s free our memory and outsource them to… a piece of paper! Just write them down.&lt;/p&gt;
&lt;p&gt;My advice is to do it like in the figure below, in small squares, with no pre-defined order. Just drop them around as if they were LEGO bricks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-4c4616af.DDI9Un7Q_1n2PSp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;structuring-your-thoughts-the-building-blocks&quot;&gt;Structuring your thoughts: the building blocks&lt;/h2&gt;
&lt;p&gt;The challenge is set! Our goal is to build something with these bricks. But first we have to see our bricks, identify them, make sure we’re not missing any. Almost &lt;em&gt;feel&lt;/em&gt; them.&lt;/p&gt;
&lt;p&gt;Take a moment to look at your building blocks. Very likely, you’ll notice some of them are related. This relationship can be logical, narrative, chronological, … Draw a line between them if that’s the case.&lt;/p&gt;
&lt;p&gt;I suggest using &lt;strong&gt;solid lines for strong relatedness&lt;/strong&gt;, and &lt;strong&gt;dashed lines for less clear relatedness&lt;/strong&gt;. We are starting to have &lt;strong&gt;some&lt;/strong&gt; structure! We are slowly creating order out of chaos!¹&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-2090d51d.29pOVV-H_Z1ciFKC.webp&quot; srcset=&quot;&quot;&gt;
At this stage, you might realize some building blocks are missing. When that’s the case, just add them. You might also notice some building blocks are redundant. Well, just merge those together. You might even judge some of the blocks to be unnecessary. Drop those without hesitation! Nothing creates more order out of chaos than reducing the amount of moving parts!&lt;/p&gt;
&lt;h2 id=&quot;navigating-your-thoughts-the-story-map&quot;&gt;Navigating your thoughts: the story map&lt;/h2&gt;
&lt;p&gt;The ultimate goal would be to navigate your thoughts. And I don’t use the verb navigate lightly: you literally want to create a route from the beginning to the end. The diagram above will be very useful for achieving this.&lt;/p&gt;
&lt;p&gt;To begin with, the diagram shows clearly what the core topics are. This allows for drawing a first, straightforward route that covers just the basics. If your audience is already knowledgeable about the topic and your time is limited, this route is an excellent choice:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-07f540b2.6KPo7hGG_2bI9Do.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For many people, especially in academia, skipping information feels wrong. In the verge of immoral.*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;What we did above is tailoring your materials to our audience (sounds better than skipping, doesn’t it?). And yes, we did it by eliminating some of them. Actually, this is going to happen often, and it is very good news. Less complexity, less moving parts; less is more, remember?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Effective communication is not about turning everything that we write or say into a self-contained compendium, but about providing chunks that can be reasonably digested in whatever context they are delivered.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If your time is less limited, you can consider taking a detour and dropping an anecdote to make the experience more enjoyable:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-d2a0192d.DrWYqMrK_ZvO4Ro.webp&quot; srcset=&quot;&quot;&gt;
Last but not least, if you have the possibility of expanding as much as you want, you might want to cover all the topics. In such a case, a reasonable route will look like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-363e168b.B9ZQjHOK_oudXO.webp&quot; srcset=&quot;&quot;&gt;
In the figure below we summarize three possible routes we could envision for the same material:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The story map&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;507&quot; height=&quot;411&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-story-map-60695bb7.DPKFnKkk_Z1KjG0F.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;applications&quot;&gt;Applications&lt;/h2&gt;
&lt;p&gt;I’ve used the described framework in many settings where storytelling played a role. Perhaps this sounds limited, but believe me: storytelling is everywhere. I used it for, among others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scientific presentations&lt;/li&gt;
&lt;li&gt;Comedy monologues&lt;/li&gt;
&lt;li&gt;Software tutorials&lt;/li&gt;
&lt;li&gt;My own PhD dissertation&lt;/li&gt;
&lt;li&gt;Blog posts&lt;/li&gt;
&lt;li&gt;A strategic plan for a research institution&lt;/li&gt;
&lt;li&gt;Publications in research journals (real-life example &lt;a href=&quot;https://fuga.naukas.com/files/2021/03/IMG_20190301_091759-768x404.jpg&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A theater play&lt;/li&gt;
&lt;li&gt;And also for this text you are reading now&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I honestly encourage you to give it a try next time you face a blank page. It works wonders!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;This piece was born in the context of the &lt;a href=&quot;https://research-software-directory.org/projects/data-storytelling&quot;&gt;Data Storytelling project&lt;/a&gt;. Thanks to &lt;a href=&quot;https://www.esciencecenter.nl/team/jesse-gonzalez/&quot;&gt;Jesse González&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/kody-moodley/&quot;&gt;Kody Moodley&lt;/a&gt; for their feedback.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For those of you interested in knowledge management, chances are this method will remind you of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Zettelkasten&quot;&gt;Zettelkasten note-taking method&lt;/a&gt;, a strong, even more structured form of the ideas presented here. Also, you’d be interested in knowing that some software applications, such as &lt;a href=&quot;https://logseq.com/&quot;&gt;logseq&lt;/a&gt; or &lt;a href=&quot;https://obsidian.md/&quot;&gt;Obsidian&lt;/a&gt;, are designed with this model in mind.↩&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-story-map-4c4616af.DDI9Un7Q.png" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.</title><link>https://blog.esciencecenter.nl/posts/2025-11-06---from-phd-student-to-auto-tuning-gpu-expert-meet-floris-jan</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-11-06---from-phd-student-to-auto-tuning-gpu-expert-meet-floris-jan</guid><description>&lt;p&gt;Floris-Jan Willemsen has been a PhD student at the Netherlands eScience Center since 2021, working on auto-tuning GPU software as part of the &lt;a href=&quot;https://research-software-directory.org/projects/cortex&quot;&gt;CORTEX&lt;/a&gt; project under the supervision of Rob van Nieuwpoort (Professor in Computer Science at Leiden University) and Ben van Werkhoven (Assistant Professor at Leiden University and former Research Software Engineer at the eScience Center).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;222&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-e9522c8e.C_BHgcx8_uedXd.webp&quot; srcset=&quot;&quot;&gt;
Why auto-tune GPUs?**&lt;/p&gt;
&lt;p&gt;“My research focuses on auto-tuning: creating software and algorithms to optimize performance on hardware. Smarter and faster auto-tuning not only leads to quicker results but also consumes less energy, making it a more sustainable option. We did this within the context of a project where we, together with other institutes like ASTRON, want to investigate the ‘explosive universe’. To observe the universe at that scale means a lot of data, which requires big computers, but even that is not enough — we need to be smart about what data we focus on and how we process it. That requires auto-tuning, which essentially is like a panel of many different knobs and sliders, with only one combination of millions leading to optimal performance. Therefore, we first focused on creating an algorithm that was able to find those combinations in very few attempts.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-3fb6b98d.CN7VbsN6_1VIvDz.webp&quot; srcset=&quot;&quot;&gt;
Van Leeuwen/ASTRON (bron: NOS Nieuws)&lt;strong&gt;What were some challenges you experienced?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“This part of the project was itself a challenge, but the difficulty didn’t end when it was finished. The next step was to develop a uniform methodology. Each research group working with auto-tuning has a different way of visualizing and comparing data, as well as of reporting results. In 2022, we organized a Lorentz workshop to compare all these different methodologies and to design a new, uniform one. The major win was receiving the community’s mandate to spearhead this new methodology, which allows everyone to fairly compare auto-tuning performance — a significant breakthrough.&lt;/p&gt;
&lt;p&gt;After this, I removed a major bottleneck in the auto-tuning process. This, together with other important advances, ultimately allowed me to optimize the optimization algorithms themselves — ‘tuning the tuner’ if you will.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who can use this tool?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;311&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-5a2375db.BVyIPWij_1wazqK.webp&quot; srcset=&quot;&quot;&gt;
ESiWACE3What was special about doing your PhD at the Netherlands eScience Center?**&lt;/p&gt;
&lt;p&gt;“It allowed us to design tools that simply didn’t exist before. Building on the expertise of the Research Software Engineers at the Netherlands eScience Center, we were able to build high-quality software that is both at the cutting edge of research as well as user-friendly and stable. This is a combination that is rarely seen and allows us to put what we research today in the hands of scientists and developers tomorrow. Another perk was the focus on meeting with user bases through tutorials at a variety of international conferences like SuperComputing. At such conferences, we taught them new ways to get the most out of their hardware from us and we learned how users interacted with our software and how we could improve it further.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are your plans for the near future?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“I’m starting a new position as a Postdoctoral researcher at the Leiden Institute of Advanced Computer Science (LIACS) at Leiden University, where I’ll continue to build on the research I did during my Ph.D. and explore exciting new directions for auto-tuning. I’m looking forward to leveraging the experience I gained in building high-quality software in all future projects!”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What made working at the eScience Center a unique experience?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“The priority at universities is to always get the research done first, which tends to lead to software that gets the job done but is not accessible, maintainable, or usable outside of the exact scope of the research. The eScience Center has the combination of people experienced in both the academic and the software side of things, which puts it at a unique intersection to create sustainable scientific software. What I created during my time at the eScience Center is not limited to one specific purpose and can immediately be deployed in other people’s research. I’m proud to have been able to make an impact in that way.”&lt;/p&gt;
&lt;p&gt;Read the article the NOS wrote about the &lt;em&gt;&lt;a href=&quot;https://nos.nl/artikel/2552914-astronomen-westerbork-ontrafelen-lichtflits-mysterie-in-de-ruimte&quot;&gt;&lt;em&gt;CORTEX Project&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (link in Dutch) in January 2025.*&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who are we?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center is a research organization dedicated to applying research software to answer research questions in any scientific domain through project collaborations. It has the largest concentration of dedicated, high-level research software expertise in the Netherlands. The eScience Center also has a &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;fellowship programme&lt;/a&gt; and makes all of its software and training materials openly available online. For more information about what we offer, visit &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Floris-Jan Willemsen has been a PhD student at the Netherlands eScience Center since 2021, working on auto-tuning GPU software as part of the &lt;a href=&quot;https://research-software-directory.org/projects/cortex&quot;&gt;CORTEX&lt;/a&gt; project under the supervision of Rob van Nieuwpoort (Professor in Computer Science at Leiden University) and Ben van Werkhoven (Assistant Professor at Leiden University and former Research Software Engineer at the eScience Center).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;222&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-e9522c8e.C_BHgcx8_uedXd.webp&quot; srcset=&quot;&quot;&gt;
Why auto-tune GPUs?**&lt;/p&gt;
&lt;p&gt;“My research focuses on auto-tuning: creating software and algorithms to optimize performance on hardware. Smarter and faster auto-tuning not only leads to quicker results but also consumes less energy, making it a more sustainable option. We did this within the context of a project where we, together with other institutes like ASTRON, want to investigate the ‘explosive universe’. To observe the universe at that scale means a lot of data, which requires big computers, but even that is not enough — we need to be smart about what data we focus on and how we process it. That requires auto-tuning, which essentially is like a panel of many different knobs and sliders, with only one combination of millions leading to optimal performance. Therefore, we first focused on creating an algorithm that was able to find those combinations in very few attempts.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-3fb6b98d.CN7VbsN6_1VIvDz.webp&quot; srcset=&quot;&quot;&gt;
Van Leeuwen/ASTRON (bron: NOS Nieuws)&lt;strong&gt;What were some challenges you experienced?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“This part of the project was itself a challenge, but the difficulty didn’t end when it was finished. The next step was to develop a uniform methodology. Each research group working with auto-tuning has a different way of visualizing and comparing data, as well as of reporting results. In 2022, we organized a Lorentz workshop to compare all these different methodologies and to design a new, uniform one. The major win was receiving the community’s mandate to spearhead this new methodology, which allows everyone to fairly compare auto-tuning performance — a significant breakthrough.&lt;/p&gt;
&lt;p&gt;After this, I removed a major bottleneck in the auto-tuning process. This, together with other important advances, ultimately allowed me to optimize the optimization algorithms themselves — ‘tuning the tuner’ if you will.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who can use this tool?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From PhD Student to Auto-Tuning GPU Expert. Meet Floris-Jan.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;311&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-5a2375db.BVyIPWij_1wazqK.webp&quot; srcset=&quot;&quot;&gt;
ESiWACE3What was special about doing your PhD at the Netherlands eScience Center?**&lt;/p&gt;
&lt;p&gt;“It allowed us to design tools that simply didn’t exist before. Building on the expertise of the Research Software Engineers at the Netherlands eScience Center, we were able to build high-quality software that is both at the cutting edge of research as well as user-friendly and stable. This is a combination that is rarely seen and allows us to put what we research today in the hands of scientists and developers tomorrow. Another perk was the focus on meeting with user bases through tutorials at a variety of international conferences like SuperComputing. At such conferences, we taught them new ways to get the most out of their hardware from us and we learned how users interacted with our software and how we could improve it further.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are your plans for the near future?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“I’m starting a new position as a Postdoctoral researcher at the Leiden Institute of Advanced Computer Science (LIACS) at Leiden University, where I’ll continue to build on the research I did during my Ph.D. and explore exciting new directions for auto-tuning. I’m looking forward to leveraging the experience I gained in building high-quality software in all future projects!”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What made working at the eScience Center a unique experience?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“The priority at universities is to always get the research done first, which tends to lead to software that gets the job done but is not accessible, maintainable, or usable outside of the exact scope of the research. The eScience Center has the combination of people experienced in both the academic and the software side of things, which puts it at a unique intersection to create sustainable scientific software. What I created during my time at the eScience Center is not limited to one specific purpose and can immediately be deployed in other people’s research. I’m proud to have been able to make an impact in that way.”&lt;/p&gt;
&lt;p&gt;Read the article the NOS wrote about the &lt;em&gt;&lt;a href=&quot;https://nos.nl/artikel/2552914-astronomen-westerbork-ontrafelen-lichtflits-mysterie-in-de-ruimte&quot;&gt;&lt;em&gt;CORTEX Project&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; (link in Dutch) in January 2025.*&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who are we?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center is a research organization dedicated to applying research software to answer research questions in any scientific domain through project collaborations. It has the largest concentration of dedicated, high-level research software expertise in the Netherlands. The eScience Center also has a &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;fellowship programme&lt;/a&gt; and makes all of its software and training materials openly available online. For more information about what we offer, visit &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/from-phd-student-to-auto-tuning-gpu-expe-e9522c8e.C_BHgcx8.jpeg" medium="image"/><author>Netherlands eScience Center</author></item><item><title>Why companies win by investing in Open-Source Software</title><link>https://blog.esciencecenter.nl/posts/2025-10-23---why-companies-win-by-investing-in-open-source-software</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-10-23---why-companies-win-by-investing-in-open-source-software</guid><description>&lt;p&gt;Why would a for-profit company want to invest in Open-Source Software? Our collaborator, prof. Eric-Jan Wagenmakers will tell you why.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why companies win by investing in Open-Source Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;370&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-companies-win-by-investing-in-open-s-bfa19698.CtXRQL3T_18SmN6.webp&quot; srcset=&quot;&quot;&gt;
CC-BY license from: Kojima T, Oishi K, Matsubara Y, Uchiyama Y, Fukushima Y, Aoki N, et al. (2019) Cows painted with zebra-like striping can avoid biting fly attack. PLoS ONE 14(10): e0223447. &lt;a href=&quot;https://doi.org/10.1371/journal.pone.0223447&quot;&gt;https://doi.org/10.1371/journal.pone.0223447&lt;/a&gt;In 2025, the &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Ig_Nobel_Prize_winners&quot;&gt;IgNobel prize&lt;/a&gt; in Biology went to research on “&lt;a href=&quot;http://doi.org/10.1371/journal.pone.0223447&quot;&gt;whether cows painted with zebra-like striping can avoid being bitten by flies&lt;/a&gt;“. Suppose a fictitious company, ZebraCows, wishes to exploit the insights from this groundbreaking work, and adopts &lt;a href=&quot;https://jasp-stats.org/&quot;&gt;JASP&lt;/a&gt; for their quality control analyses.&lt;/p&gt;
&lt;p&gt;The head of the data-analytics department at ZebraCows is unfamiliar with open-source software, and two surprises await them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Their first surprise is that JASP can be freely installed on &lt;em&gt;all&lt;/em&gt; company computers, no strings attached. ZebraCows considers this a big win. Open-source is awesome, they think.&lt;/li&gt;
&lt;li&gt;To receive support and connect JASP even more closely to their needs, ZebraCows starts working together with the JASP Services company through one of their &lt;a href=&quot;https://www.jasp-services.com/service-plans-2/&quot;&gt;service plans&lt;/a&gt;. However, when they read the contracts they are in for a second surprise: all new features that a company requests are immediately added to the JASP open-source code base; this means that everybody in the whole wide world –students, researchers, unrelated and even rival companies– gets to profit from improvements that were requested and paid for by ZebraCows. That seems unfair to ZebraCows, who would prefer the new features to be exclusively available to employees from ZebraCows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below, I briefly outline why ZebraCows should in fact be &lt;em&gt;thrilled&lt;/em&gt; that the code they paid for is available to the whole world instead of only to them. Essentially, ZebraCows stands to profit from JASP being developed, extended, and improved by others –for free!–, while ZebraCows retains maximum digital autonomy**.&lt;/p&gt;
&lt;p&gt;Below is a non-exhaustive list of arguments in favor of open-source software (specifically, JASP) for companies:&lt;/p&gt;
&lt;h2 id=&quot;1-unlimited-free-installation&quot;&gt;1. Unlimited, Free Installation&lt;/h2&gt;
&lt;p&gt;Open-source software such as JASP can be installed on every computer in ZebraCows business network at zero cost. There are no license fees. There is no per-user pricing, and scalability is complete.&lt;/p&gt;
&lt;h2 id=&quot;2-continuous-improvement-at-no-extra-cost&quot;&gt;2. Continuous Improvement at No Extra Cost&lt;/h2&gt;
&lt;p&gt;Open-source features are visible to the &lt;a href=&quot;https://jasp-stats.org/world-map/&quot;&gt;global JASP community&lt;/a&gt;. External contributors (researchers, developers, students) can refine, extend, and maintain the features that ZebraCows cares about, for decades to come — and all for free.&lt;/p&gt;
&lt;h2 id=&quot;3-shared-development-pool&quot;&gt;3. Shared Development Pool&lt;/h2&gt;
&lt;p&gt;Other companies who also want additional features will invest in JASP too. ZebraCows automatically gains access to their improvements, without paying extra.&lt;/p&gt;
&lt;h2 id=&quot;4-no-vendor-lock-in&quot;&gt;4. No Vendor Lock-In&lt;/h2&gt;
&lt;p&gt;With closed-source software, ZebraCows may need to keep paying for updates just to keep their features working. With open-source, the code is available to ZebraCows forever. Nobody can take it away, restrict access, or increase license fees.&lt;/p&gt;
&lt;h2 id=&quot;5-transparency&quot;&gt;5. Transparency&lt;/h2&gt;
&lt;p&gt;Adoption of JASP means that ZebraCows attains complete transparency on the process by which JASP produces its results. In contrast to closed-source software, all the code that JASP uses is available for external inspection and public scrutiny. ZebraCows is not forced to rely exclusively on the documentation or the helpdesk and “take their word for it”.&lt;/p&gt;
&lt;h2 id=&quot;6-limited-costs-for-superior-service&quot;&gt;6. Limited Costs for Superior Service&lt;/h2&gt;
&lt;p&gt;Most open-source service contracts –and certainly those of JASP– are simply a great deal financially. A large commercial software product does not adjust or improve its code to accommodate the wishes of a medium-sized company such as ZebraCows. For only a modest investment, ZebraCows can interact with the JASP Services team and initiate improvements that benefit ZebraCows specifically. Try doing this with &amp;#x3C;insert the name of any large commercial program here*&gt;!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By investing in the development of open-source software such as JASP, companies gain much more than just the features they pay to see implemented. Companies also gain access to a continual, indefinite stream of free improvements, while being protected from lock-in or forced upgrade costs. This way companies profit from unlimited, future-proof access to a program that is designed to meet their needs.&lt;/p&gt;
&lt;p&gt;This piece is a repost (with minor adaptations) from &lt;a href=&quot;https://www.jasp-services.com/why-companies-win-by-investing-in-open-source-software/&quot;&gt;the JASP blog&lt;/a&gt;, reproduced here with permission (and encouragement) from the author, &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Professor Wagenmakers is a mathematical psychologist at the University of Amsterdam, the CEO of &lt;a href=&quot;https://jasp-stats.org/&quot;&gt;JASP&lt;/a&gt; (a popular open-source statistical software), and the proud owner of an IgNobel Prize (2024). Currently he is collaborating with the eScience Center in improving the user experience of the JASP module-making community.&lt;/p&gt;</description><pubDate>Thu, 23 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why would a for-profit company want to invest in Open-Source Software? Our collaborator, prof. Eric-Jan Wagenmakers will tell you why.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why companies win by investing in Open-Source Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;370&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-companies-win-by-investing-in-open-s-bfa19698.CtXRQL3T_18SmN6.webp&quot; srcset=&quot;&quot;&gt;
CC-BY license from: Kojima T, Oishi K, Matsubara Y, Uchiyama Y, Fukushima Y, Aoki N, et al. (2019) Cows painted with zebra-like striping can avoid biting fly attack. PLoS ONE 14(10): e0223447. &lt;a href=&quot;https://doi.org/10.1371/journal.pone.0223447&quot;&gt;https://doi.org/10.1371/journal.pone.0223447&lt;/a&gt;In 2025, the &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Ig_Nobel_Prize_winners&quot;&gt;IgNobel prize&lt;/a&gt; in Biology went to research on “&lt;a href=&quot;http://doi.org/10.1371/journal.pone.0223447&quot;&gt;whether cows painted with zebra-like striping can avoid being bitten by flies&lt;/a&gt;“. Suppose a fictitious company, ZebraCows, wishes to exploit the insights from this groundbreaking work, and adopts &lt;a href=&quot;https://jasp-stats.org/&quot;&gt;JASP&lt;/a&gt; for their quality control analyses.&lt;/p&gt;
&lt;p&gt;The head of the data-analytics department at ZebraCows is unfamiliar with open-source software, and two surprises await them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Their first surprise is that JASP can be freely installed on &lt;em&gt;all&lt;/em&gt; company computers, no strings attached. ZebraCows considers this a big win. Open-source is awesome, they think.&lt;/li&gt;
&lt;li&gt;To receive support and connect JASP even more closely to their needs, ZebraCows starts working together with the JASP Services company through one of their &lt;a href=&quot;https://www.jasp-services.com/service-plans-2/&quot;&gt;service plans&lt;/a&gt;. However, when they read the contracts they are in for a second surprise: all new features that a company requests are immediately added to the JASP open-source code base; this means that everybody in the whole wide world –students, researchers, unrelated and even rival companies– gets to profit from improvements that were requested and paid for by ZebraCows. That seems unfair to ZebraCows, who would prefer the new features to be exclusively available to employees from ZebraCows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below, I briefly outline why ZebraCows should in fact be &lt;em&gt;thrilled&lt;/em&gt; that the code they paid for is available to the whole world instead of only to them. Essentially, ZebraCows stands to profit from JASP being developed, extended, and improved by others –for free!–, while ZebraCows retains maximum digital autonomy**.&lt;/p&gt;
&lt;p&gt;Below is a non-exhaustive list of arguments in favor of open-source software (specifically, JASP) for companies:&lt;/p&gt;
&lt;h2 id=&quot;1-unlimited-free-installation&quot;&gt;1. Unlimited, Free Installation&lt;/h2&gt;
&lt;p&gt;Open-source software such as JASP can be installed on every computer in ZebraCows business network at zero cost. There are no license fees. There is no per-user pricing, and scalability is complete.&lt;/p&gt;
&lt;h2 id=&quot;2-continuous-improvement-at-no-extra-cost&quot;&gt;2. Continuous Improvement at No Extra Cost&lt;/h2&gt;
&lt;p&gt;Open-source features are visible to the &lt;a href=&quot;https://jasp-stats.org/world-map/&quot;&gt;global JASP community&lt;/a&gt;. External contributors (researchers, developers, students) can refine, extend, and maintain the features that ZebraCows cares about, for decades to come — and all for free.&lt;/p&gt;
&lt;h2 id=&quot;3-shared-development-pool&quot;&gt;3. Shared Development Pool&lt;/h2&gt;
&lt;p&gt;Other companies who also want additional features will invest in JASP too. ZebraCows automatically gains access to their improvements, without paying extra.&lt;/p&gt;
&lt;h2 id=&quot;4-no-vendor-lock-in&quot;&gt;4. No Vendor Lock-In&lt;/h2&gt;
&lt;p&gt;With closed-source software, ZebraCows may need to keep paying for updates just to keep their features working. With open-source, the code is available to ZebraCows forever. Nobody can take it away, restrict access, or increase license fees.&lt;/p&gt;
&lt;h2 id=&quot;5-transparency&quot;&gt;5. Transparency&lt;/h2&gt;
&lt;p&gt;Adoption of JASP means that ZebraCows attains complete transparency on the process by which JASP produces its results. In contrast to closed-source software, all the code that JASP uses is available for external inspection and public scrutiny. ZebraCows is not forced to rely exclusively on the documentation or the helpdesk and “take their word for it”.&lt;/p&gt;
&lt;h2 id=&quot;6-limited-costs-for-superior-service&quot;&gt;6. Limited Costs for Superior Service&lt;/h2&gt;
&lt;p&gt;Most open-source service contracts –and certainly those of JASP– are simply a great deal financially. A large commercial software product does not adjust or improve its code to accommodate the wishes of a medium-sized company such as ZebraCows. For only a modest investment, ZebraCows can interact with the JASP Services team and initiate improvements that benefit ZebraCows specifically. Try doing this with &amp;#x3C;insert the name of any large commercial program here*&gt;!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By investing in the development of open-source software such as JASP, companies gain much more than just the features they pay to see implemented. Companies also gain access to a continual, indefinite stream of free improvements, while being protected from lock-in or forced upgrade costs. This way companies profit from unlimited, future-proof access to a program that is designed to meet their needs.&lt;/p&gt;
&lt;p&gt;This piece is a repost (with minor adaptations) from &lt;a href=&quot;https://www.jasp-services.com/why-companies-win-by-investing-in-open-source-software/&quot;&gt;the JASP blog&lt;/a&gt;, reproduced here with permission (and encouragement) from the author, &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Professor Wagenmakers is a mathematical psychologist at the University of Amsterdam, the CEO of &lt;a href=&quot;https://jasp-stats.org/&quot;&gt;JASP&lt;/a&gt; (a popular open-source statistical software), and the proud owner of an IgNobel Prize (2024). Currently he is collaborating with the eScience Center in improving the user experience of the JASP module-making community.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/why-companies-win-by-investing-in-open-s-bfa19698.CtXRQL3T.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Why teach calculus in the age of AI</title><link>https://blog.esciencecenter.nl/posts/2025-10-09---why-teach-calculus-in-the-age-of-ai</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-10-09---why-teach-calculus-in-the-age-of-ai</guid><description>&lt;p&gt;Why would I learn to compute a derivative by hand when Artificial Intelligence can do it for me?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why teach calculus in the age of AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-teach-calculus-in-the-age-of-ai-603e031b.bNi5rz1v_Z1aoeB5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@shubhamsharan?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Shubham Sharan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you’re reading this, you’ve probably taken a calculus course before. How was it? Chances are you found it frustrating or, at least, complicated.&lt;/p&gt;
&lt;p&gt;You may remember one of the most feared parts of calculus courses: the computation of derivatives and integrals. For most students, this is the first time they face a mathematical problem whose solution is not a number, but a much more complicated object: a function. Computing derivatives and integrals involves memorizing tables, applying complicated composition rules and avoiding sneaky arithmetic errors. In short, it is hard.&lt;/p&gt;
&lt;h2 id=&quot;enters-technology&quot;&gt;Enters technology&lt;/h2&gt;
&lt;p&gt;For several decades now, it is possible to solve these problems using symbolic computation software packages, available for computers and even for some pocket calculators. Since the explosion of Artificial Intelligence (AI) engines, access to such tools is easier than ever. So, if you want to know the derivative of some function, you can just ask your favourite AI engine via your smartphone, and you’ll (most likely) get the correct answer.&lt;/p&gt;
&lt;p&gt;All of this raises a valid question: why bother learning all those tedious methods?&lt;/p&gt;
&lt;h2 id=&quot;calculus-is-not-only-about-calculations&quot;&gt;Calculus is not only about calculations&lt;/h2&gt;
&lt;p&gt;One of the reasons is that differentiation and integration involve much more than the algorithms. Like all mathematical operations, they have a meaning and applications. As a matter of fact, a huge number of applications: basically all physics and engineering relies on them.&lt;/p&gt;
&lt;p&gt;While it’s true that one doesn’t need to know how to compute derivatives or integrals in order to understand their meaning, it is quite hard to do it without wrestling with some exercises. They are a great way to internalize and create a solid understanding.&lt;/p&gt;
&lt;p&gt;For instance, by learning some of the algorithmic rules, we’ll also learn that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integration by substitution is just the chain rule for derivatives, read backwards.&lt;/li&gt;
&lt;li&gt;Integration by parts is the product rule for derivatives, just written differently.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even the quintessential tedious task, that of reading (and eventually) memorizing the tables, can teach valuable lessons, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A table of integrals is basically a table of derivatives read backwards.&lt;/li&gt;
&lt;li&gt;Derivatives destroy information, hence the arbitrary constant in the table of integrals.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other concepts that are difficult to grasp without “getting your hands dirty” are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integrals and derivatives can be estimated.&lt;/li&gt;
&lt;li&gt;Mathematics can manipulate objects more complicated than numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perhaps more importantly, if you look deeper, you’ll see that studying calculus teaches you more than just mathematics. For instance, solving calculus problems shows you that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some questions have a clear, uncontroversial and verifiable answer.&lt;/li&gt;
&lt;li&gt;You can find out the solution to complicated-looking problems by yourself, using nothing more than pen and paper.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AI is here to stay, and it is a wonderful tool for many applications. But it comes with some dangers too. One of the main criticisms that AI engines receive from the scientific and teaching communities is that they work as black boxes: they spit out results and encourage users to accept them without further scrutiny.&lt;/p&gt;
&lt;p&gt;Being able to reach conclusions with pen and paper (quite the opposite of a black box) is certainly not less important now than before. It is a crucial skill for responsibly using AI as a learning companion.&lt;/p&gt;
&lt;p&gt;Education is not only about getting the right answers. Education is also about learning how to ask the right questions, to reason clearly and to trust your own judgment.&lt;/p&gt;
&lt;p&gt;Technology can solve problems for you. Calculus teaches that, at least some of them, you can solve yourself. That kind of confidence, curiosity, and mental discipline is something no black box can give you.&lt;/p&gt;
&lt;p&gt;You earn it.&lt;/p&gt;
&lt;p&gt;This piece appeared first in &lt;em&gt;&lt;a href=&quot;https://mappingignorance.org/2025/08/18/why-teach-calculus-in-the-age-of-ai/&quot;&gt;&lt;em&gt;mappingignorance.org&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;</description><pubDate>Thu, 09 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why would I learn to compute a derivative by hand when Artificial Intelligence can do it for me?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why teach calculus in the age of AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-teach-calculus-in-the-age-of-ai-603e031b.bNi5rz1v_Z1aoeB5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@shubhamsharan?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Shubham Sharan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you’re reading this, you’ve probably taken a calculus course before. How was it? Chances are you found it frustrating or, at least, complicated.&lt;/p&gt;
&lt;p&gt;You may remember one of the most feared parts of calculus courses: the computation of derivatives and integrals. For most students, this is the first time they face a mathematical problem whose solution is not a number, but a much more complicated object: a function. Computing derivatives and integrals involves memorizing tables, applying complicated composition rules and avoiding sneaky arithmetic errors. In short, it is hard.&lt;/p&gt;
&lt;h2 id=&quot;enters-technology&quot;&gt;Enters technology&lt;/h2&gt;
&lt;p&gt;For several decades now, it is possible to solve these problems using symbolic computation software packages, available for computers and even for some pocket calculators. Since the explosion of Artificial Intelligence (AI) engines, access to such tools is easier than ever. So, if you want to know the derivative of some function, you can just ask your favourite AI engine via your smartphone, and you’ll (most likely) get the correct answer.&lt;/p&gt;
&lt;p&gt;All of this raises a valid question: why bother learning all those tedious methods?&lt;/p&gt;
&lt;h2 id=&quot;calculus-is-not-only-about-calculations&quot;&gt;Calculus is not only about calculations&lt;/h2&gt;
&lt;p&gt;One of the reasons is that differentiation and integration involve much more than the algorithms. Like all mathematical operations, they have a meaning and applications. As a matter of fact, a huge number of applications: basically all physics and engineering relies on them.&lt;/p&gt;
&lt;p&gt;While it’s true that one doesn’t need to know how to compute derivatives or integrals in order to understand their meaning, it is quite hard to do it without wrestling with some exercises. They are a great way to internalize and create a solid understanding.&lt;/p&gt;
&lt;p&gt;For instance, by learning some of the algorithmic rules, we’ll also learn that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integration by substitution is just the chain rule for derivatives, read backwards.&lt;/li&gt;
&lt;li&gt;Integration by parts is the product rule for derivatives, just written differently.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even the quintessential tedious task, that of reading (and eventually) memorizing the tables, can teach valuable lessons, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A table of integrals is basically a table of derivatives read backwards.&lt;/li&gt;
&lt;li&gt;Derivatives destroy information, hence the arbitrary constant in the table of integrals.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other concepts that are difficult to grasp without “getting your hands dirty” are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integrals and derivatives can be estimated.&lt;/li&gt;
&lt;li&gt;Mathematics can manipulate objects more complicated than numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perhaps more importantly, if you look deeper, you’ll see that studying calculus teaches you more than just mathematics. For instance, solving calculus problems shows you that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some questions have a clear, uncontroversial and verifiable answer.&lt;/li&gt;
&lt;li&gt;You can find out the solution to complicated-looking problems by yourself, using nothing more than pen and paper.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AI is here to stay, and it is a wonderful tool for many applications. But it comes with some dangers too. One of the main criticisms that AI engines receive from the scientific and teaching communities is that they work as black boxes: they spit out results and encourage users to accept them without further scrutiny.&lt;/p&gt;
&lt;p&gt;Being able to reach conclusions with pen and paper (quite the opposite of a black box) is certainly not less important now than before. It is a crucial skill for responsibly using AI as a learning companion.&lt;/p&gt;
&lt;p&gt;Education is not only about getting the right answers. Education is also about learning how to ask the right questions, to reason clearly and to trust your own judgment.&lt;/p&gt;
&lt;p&gt;Technology can solve problems for you. Calculus teaches that, at least some of them, you can solve yourself. That kind of confidence, curiosity, and mental discipline is something no black box can give you.&lt;/p&gt;
&lt;p&gt;You earn it.&lt;/p&gt;
&lt;p&gt;This piece appeared first in &lt;em&gt;&lt;a href=&quot;https://mappingignorance.org/2025/08/18/why-teach-calculus-in-the-age-of-ai/&quot;&gt;&lt;em&gt;mappingignorance.org&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/why-teach-calculus-in-the-age-of-ai-603e031b.bNi5rz1v.jpg" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Be like Jurriaan</title><link>https://blog.esciencecenter.nl/posts/2025-09-25---be-like-jurriaan</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-09-25---be-like-jurriaan</guid><description>&lt;h2 id=&quot;write-copy-pasteable-readmes-for-developers&quot;&gt;Write copy-pasteable READMEs for developers&lt;/h2&gt;
&lt;p&gt;The main message of this post is short:&lt;/p&gt;
&lt;p&gt;Thank you,&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/fd96a2a5f9bc?source=post_page---user_mention--ac9e8926d1b3---------------------------------------&quot;&gt;Jurriaan H. Spaaks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, for including developer’s READMEs in the &lt;a href=&quot;https://github.com/zenodraft/zenodraft&quot;&gt;zenodraft&lt;/a&gt; and the &lt;a href=&quot;https://github.com/zenodraft/action&quot;&gt;zenodraft GitHub action&lt;/a&gt; repos!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Zenodraft automates uploading releases of your repository to Zenodo. This story applies to any similar tool.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In particular, having copy-pasteable commands ready to get going saved my week. Without them, I would have dropped any hope of &lt;a href=&quot;https://github.com/NLeSC/guide/pull/443&quot;&gt;fixing the issues I had running a CI workflow&lt;/a&gt; … or worse, I would have had to rebuild something like zenodraft from scratch!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1141&quot; height=&quot;969&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SP0juQAauTLoEAw6Scb8RQ-1a7e6e06.BxgtAdcf_Z6b3kU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It doesn’t have to be long and complicated. Just having those commands ready to copy is all I need.&lt;/p&gt;
&lt;p&gt;Zenodraft is written in TypeScript, which is a foreign language to me. I’m unfamiliar with the tools necessary to make it work. The &lt;a href=&quot;https://github.com/zenodraft/action/blob/main/README.dev.md&quot;&gt;developer’s README&lt;/a&gt; file exactly fixed that issue, allowing me, a TypeScript-noob (but otherwise experienced programmer), to dive in and fix my problems within a few hours of building up the courage to even try. I was even able to contribute a &lt;a href=&quot;https://github.com/zenodraft/action/pull/31&quot;&gt;PR&lt;/a&gt;, my first one in a TypeScript project!&lt;/p&gt;
&lt;p&gt;In the world of open source (research) software, where ambitions are high and budgets are low, it turns out that such documentation can mean the difference between life and death for the software.&lt;/p&gt;
&lt;p&gt;If you are the owner of a package and expect to be unavailable to maintain your code, the best thing you can do is to enable the random passer-by to independently fix their own problems.&lt;/p&gt;
&lt;p&gt;Be like Jurriaan. Write developer’s READMEs!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;503&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_xNfeV7xNnIrP31fx-c6c80d22.VWF9S1Sp_cBNay.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you had asked me a week ago whether such documentation is necessary I would have shrugged. This experience made me change my mind. A lazy, clutter-averse and/or “minimalist” person could argue that most development ecosystem tools are well documented on their own, and technically they might even be right (although rants on how soul-crushingly horrible Python’s or Javascript’s developers’ ecosystems are aren’t hard to find). Why duplicate efforts?&lt;/p&gt;
&lt;p&gt;Just ask yourself: would you take the effort of reading up on the current state of such an ecosystem just to make random-tool-on-GitHub do what you want? Even if it’s just a minor tweak in the code, the effort necessary to get that tweak into production can easily put developers off.&lt;/p&gt;
&lt;p&gt;So, just copy-paste the minimal commands you need to get a working development environment set up into a README file. You probably have these commands set up in your CI build job already, so it’s really not that much effort. And you might gain a new contributor…&lt;/p&gt;</description><pubDate>Thu, 25 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;write-copy-pasteable-readmes-for-developers&quot;&gt;Write copy-pasteable READMEs for developers&lt;/h2&gt;
&lt;p&gt;The main message of this post is short:&lt;/p&gt;
&lt;p&gt;Thank you,&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/fd96a2a5f9bc?source=post_page---user_mention--ac9e8926d1b3---------------------------------------&quot;&gt;Jurriaan H. Spaaks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, for including developer’s READMEs in the &lt;a href=&quot;https://github.com/zenodraft/zenodraft&quot;&gt;zenodraft&lt;/a&gt; and the &lt;a href=&quot;https://github.com/zenodraft/action&quot;&gt;zenodraft GitHub action&lt;/a&gt; repos!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Zenodraft automates uploading releases of your repository to Zenodo. This story applies to any similar tool.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In particular, having copy-pasteable commands ready to get going saved my week. Without them, I would have dropped any hope of &lt;a href=&quot;https://github.com/NLeSC/guide/pull/443&quot;&gt;fixing the issues I had running a CI workflow&lt;/a&gt; … or worse, I would have had to rebuild something like zenodraft from scratch!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1141&quot; height=&quot;969&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SP0juQAauTLoEAw6Scb8RQ-1a7e6e06.BxgtAdcf_Z6b3kU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It doesn’t have to be long and complicated. Just having those commands ready to copy is all I need.&lt;/p&gt;
&lt;p&gt;Zenodraft is written in TypeScript, which is a foreign language to me. I’m unfamiliar with the tools necessary to make it work. The &lt;a href=&quot;https://github.com/zenodraft/action/blob/main/README.dev.md&quot;&gt;developer’s README&lt;/a&gt; file exactly fixed that issue, allowing me, a TypeScript-noob (but otherwise experienced programmer), to dive in and fix my problems within a few hours of building up the courage to even try. I was even able to contribute a &lt;a href=&quot;https://github.com/zenodraft/action/pull/31&quot;&gt;PR&lt;/a&gt;, my first one in a TypeScript project!&lt;/p&gt;
&lt;p&gt;In the world of open source (research) software, where ambitions are high and budgets are low, it turns out that such documentation can mean the difference between life and death for the software.&lt;/p&gt;
&lt;p&gt;If you are the owner of a package and expect to be unavailable to maintain your code, the best thing you can do is to enable the random passer-by to independently fix their own problems.&lt;/p&gt;
&lt;p&gt;Be like Jurriaan. Write developer’s READMEs!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;503&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_xNfeV7xNnIrP31fx-c6c80d22.VWF9S1Sp_cBNay.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you had asked me a week ago whether such documentation is necessary I would have shrugged. This experience made me change my mind. A lazy, clutter-averse and/or “minimalist” person could argue that most development ecosystem tools are well documented on their own, and technically they might even be right (although rants on how soul-crushingly horrible Python’s or Javascript’s developers’ ecosystems are aren’t hard to find). Why duplicate efforts?&lt;/p&gt;
&lt;p&gt;Just ask yourself: would you take the effort of reading up on the current state of such an ecosystem just to make random-tool-on-GitHub do what you want? Even if it’s just a minor tweak in the code, the effort necessary to get that tweak into production can easily put developers off.&lt;/p&gt;
&lt;p&gt;So, just copy-paste the minimal commands you need to get a working development environment set up into a README file. You probably have these commands set up in your CI build job already, so it’s really not that much effort. And you might gain a new contributor…&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_SP0juQAauTLoEAw6Scb8RQ-1a7e6e06.BxgtAdcf.png" medium="image"/><author>Patrick Bos</author></item><item><title>5 tips for writing a successful eScience Center proposal</title><link>https://blog.esciencecenter.nl/posts/2025-08-28---5-tips-for-writing-a-successful-escience-center-proposal</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-08-28---5-tips-for-writing-a-successful-escience-center-proposal</guid><description>&lt;p&gt;22&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Over the years, we’ve worked on a wide range of collaborative projects through our open calls. The most successful ones? They tend to have a few things in common right from the proposal stage. Here are five tips to help your proposal lay the foundation for a smooth, impactful, and genuinely rewarding collaboration.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;5 tips for writing a successful eScience Center proposal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/5-tips-for-writing-a-successful-escience-f7ee65e6.DCBqA6Y7_ZxiNhL.webp&quot; srcset=&quot;&quot;&gt;
Image adapted from &lt;a href=&quot;https://unsplash.com/photos/a-red-and-white-rocket-ship-flying-through-the-sky-O1jUvZX9DOA&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-describe-the-challenge-not-the-solution&quot;&gt;1. Describe the challenge, not the solution&lt;/h3&gt;
&lt;p&gt;We love a good challenge. If the technical solution is already fully defined, there’s less room for us to contribute meaningfully. For example, instead of saying &lt;em&gt;“we need a dashboard that does X”&lt;/em&gt;, describe the challenge: &lt;em&gt;“we struggle to analyze Y because current tools can’t handle Z.”&lt;/em&gt; That kind of framing sparks our curiosity and drives the creative collaboration we love.&lt;/p&gt;
&lt;h3 id=&quot;2-dedicate-real-time-to-the-project&quot;&gt;2. Dedicate real time to the project&lt;/h3&gt;
&lt;p&gt;We’re looking for genuine teamwork — whether that’s you, your postdocs, or PhD students. The best projects have collaborators who test the software as it is built. For example: &lt;em&gt;“we tried the new analysis module this week, here’s where it’s slow, and here’s a feature we hadn’t thought of before.”&lt;/em&gt; Aligning your proposal with existing commitments makes this kind of feedback loop much easier.&lt;/p&gt;
&lt;h3 id=&quot;3-be-realistic&quot;&gt;3. Be realistic&lt;/h3&gt;
&lt;p&gt;Ambition gets projects funded. And we love bold ideas — but bold doesn’t mean bloated. Make sure your proposal has a solid core to build on, and leave room for exploration, iteration — even failure. A focused project with space to explore usually delivers more than an overpacked one that runs out of steam.&lt;/p&gt;
&lt;h3 id=&quot;4-build-on-what-you-have&quot;&gt;4. Build on what you have&lt;/h3&gt;
&lt;p&gt;We love improving workflows and building better tools — but starting from scratch rarely works in one project. If the data is missing, the workflow doesn’t exist, or the whole thing is still hypothetical, that’s a red flag. Don’t think what might be useful for &lt;em&gt;someone, someday&lt;/em&gt;. Instead, think what would help *you, today, *and make your code and data available before submitting the proposal. Even a messy dataset or clunky script gives us a real starting point, so we can hit the ground running.&lt;/p&gt;
&lt;h3 id=&quot;5-think-beyond-the-project&quot;&gt;5. Think beyond the project&lt;/h3&gt;
&lt;p&gt;A successful project doesn’t stop when the funding ends. Our calls require a sustainability plan — and for good &lt;a href=&quot;https://doi.org/10.5281/zenodo.15646827&quot;&gt;reason&lt;/a&gt;. The tools that have the biggest impact are those that become part of daily workflows and get shared, adapted, and improved over time by a community of users. So think about how your software fits into your everyday research, and who else might use or build on it after the project wraps up. Check out the &lt;a href=&quot;https://smp.research.software/&quot;&gt;SMP tool&lt;/a&gt; to get a jump start.&lt;/p&gt;
&lt;p&gt;Ready to collaborate? Check our &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/calls-for-proposals/&quot;&gt;&lt;em&gt;website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for an up-to-date overview of past and open calls, or simply &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/contact-us/&quot;&gt;&lt;em&gt;get in touch&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post represents original content created with AI assistance.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 28 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;22&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Over the years, we’ve worked on a wide range of collaborative projects through our open calls. The most successful ones? They tend to have a few things in common right from the proposal stage. Here are five tips to help your proposal lay the foundation for a smooth, impactful, and genuinely rewarding collaboration.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;5 tips for writing a successful eScience Center proposal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/5-tips-for-writing-a-successful-escience-f7ee65e6.DCBqA6Y7_ZxiNhL.webp&quot; srcset=&quot;&quot;&gt;
Image adapted from &lt;a href=&quot;https://unsplash.com/photos/a-red-and-white-rocket-ship-flying-through-the-sky-O1jUvZX9DOA&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-describe-the-challenge-not-the-solution&quot;&gt;1. Describe the challenge, not the solution&lt;/h3&gt;
&lt;p&gt;We love a good challenge. If the technical solution is already fully defined, there’s less room for us to contribute meaningfully. For example, instead of saying &lt;em&gt;“we need a dashboard that does X”&lt;/em&gt;, describe the challenge: &lt;em&gt;“we struggle to analyze Y because current tools can’t handle Z.”&lt;/em&gt; That kind of framing sparks our curiosity and drives the creative collaboration we love.&lt;/p&gt;
&lt;h3 id=&quot;2-dedicate-real-time-to-the-project&quot;&gt;2. Dedicate real time to the project&lt;/h3&gt;
&lt;p&gt;We’re looking for genuine teamwork — whether that’s you, your postdocs, or PhD students. The best projects have collaborators who test the software as it is built. For example: &lt;em&gt;“we tried the new analysis module this week, here’s where it’s slow, and here’s a feature we hadn’t thought of before.”&lt;/em&gt; Aligning your proposal with existing commitments makes this kind of feedback loop much easier.&lt;/p&gt;
&lt;h3 id=&quot;3-be-realistic&quot;&gt;3. Be realistic&lt;/h3&gt;
&lt;p&gt;Ambition gets projects funded. And we love bold ideas — but bold doesn’t mean bloated. Make sure your proposal has a solid core to build on, and leave room for exploration, iteration — even failure. A focused project with space to explore usually delivers more than an overpacked one that runs out of steam.&lt;/p&gt;
&lt;h3 id=&quot;4-build-on-what-you-have&quot;&gt;4. Build on what you have&lt;/h3&gt;
&lt;p&gt;We love improving workflows and building better tools — but starting from scratch rarely works in one project. If the data is missing, the workflow doesn’t exist, or the whole thing is still hypothetical, that’s a red flag. Don’t think what might be useful for &lt;em&gt;someone, someday&lt;/em&gt;. Instead, think what would help *you, today, *and make your code and data available before submitting the proposal. Even a messy dataset or clunky script gives us a real starting point, so we can hit the ground running.&lt;/p&gt;
&lt;h3 id=&quot;5-think-beyond-the-project&quot;&gt;5. Think beyond the project&lt;/h3&gt;
&lt;p&gt;A successful project doesn’t stop when the funding ends. Our calls require a sustainability plan — and for good &lt;a href=&quot;https://doi.org/10.5281/zenodo.15646827&quot;&gt;reason&lt;/a&gt;. The tools that have the biggest impact are those that become part of daily workflows and get shared, adapted, and improved over time by a community of users. So think about how your software fits into your everyday research, and who else might use or build on it after the project wraps up. Check out the &lt;a href=&quot;https://smp.research.software/&quot;&gt;SMP tool&lt;/a&gt; to get a jump start.&lt;/p&gt;
&lt;p&gt;Ready to collaborate? Check our &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/calls-for-proposals/&quot;&gt;&lt;em&gt;website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for an up-to-date overview of past and open calls, or simply &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/contact-us/&quot;&gt;&lt;em&gt;get in touch&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post represents original content created with AI assistance.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/5-tips-for-writing-a-successful-escience-f7ee65e6.DCBqA6Y7.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Could AI be (in) FAIR?</title><link>https://blog.esciencecenter.nl/posts/2025-07-10---could-ai-be-in-fair</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-07-10---could-ai-be-in-fair</guid><description>&lt;p&gt;&lt;em&gt;Open Science is driven by FAIR principles. Made for data, adapted for software, how can they survive the current wave of “Artificial Intelligence”? Resistance from those selling it as a solution for all problems is to be expected.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scientific progress is actively hindered if research data is stored on inaccessible servers or private hard disks, in proprietary formats, or preprocessed in unknown ways. The authors of the &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;original FAIR&lt;/a&gt; &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;paper&lt;/a&gt; have therefore demanded to leave non-collaborative practices behind: instead, make data F**indable, &lt;strong&gt;A&lt;/strong&gt;ccessible, &lt;strong&gt;I&lt;/strong&gt;nteroperable and &lt;strong&gt;R&lt;/strong&gt;eusable (FAIR)!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-4309ea06.BpquOFT5_2wdBHI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@theshantanukr?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Shantanu Kumar&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;The underlying ideas have been pillars of scientific methodology &lt;a href=&quot;https://blog.esciencecenter.nl/fair-principles-5000-years-of-common-sense-ba85086ba79c&quot;&gt;for thousands of years&lt;/a&gt;, but the rise of computerized methods in practically all research fields has created the need to make the FAIR principles explicit. The increase of computational processing power and algorithms to make efficient use of it have interwoven disciplines including Natural Language Processing, Information Retrieval, Information Science, and Computer Science. Artificial Intelligence is one of the products and has now impacted not only academic research, but also medicine, [education](&lt;a href=&quot;https://doi.org/10.48550/ar&quot;&gt;https://doi.org/10.48550/ar&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Xiv.2412.06651), libraries and archives, and even &lt;a href=&quot;https://www.rollingstone.com/culture/culture-features/ai-spiritual-delusions-destroying-human-relationships-1235330175/&quot;&gt;spirituality&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fair-vs-ai&quot;&gt;Fair vs. AI&lt;/h2&gt;
&lt;p&gt;Not reinventing the wheel for each study is the essence of scientific progress; hence, reusability is the primary goal of the FAIR principles. Promises about advances to be expected by current AI generations are bold. Supposedly, they achieve “&lt;a href=&quot;https://arxiv.org/abs/2311.12022&quot;&gt;PhD-level intelligence&lt;/a&gt;” already, even though a closer look reveals that this merely refers to the ability to fill in exam questions accurately. Anyway, the FAIR principles seem to be falling off the wagon, as ChatGPT and its colleagues are happy to confirm (see Figures 1–3).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;621&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-9836fa99.BECPsWIg_Z2b781H.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: According to ChatGPT, the letters “A” and “I” do not appear in FAIR.The paper “&lt;a href=&quot;https://www.nature.com/articles/s41597-023-02298-6&quot;&gt;FAIR for AI: An interdisciplinary and international community building perspective&lt;/a&gt;” proposed the following definitions for FAIR AI models:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AI model is &lt;strong&gt;Findable&lt;/strong&gt; when a digital object identifier (DOI) can direct a human or machine to a digital resource […];&lt;/li&gt;
&lt;li&gt;it is &lt;strong&gt;Accessible&lt;/strong&gt; when it and its metadata may be readily downloaded […];&lt;/li&gt;
&lt;li&gt;it is &lt;strong&gt;Interoperable&lt;/strong&gt; when it can seamlessly interact with other models, data, software, and hardware architectures;&lt;/li&gt;
&lt;li&gt;and it is &lt;strong&gt;Reusable&lt;/strong&gt; when it can be used by humans, machines and other models to reproduce its expected inference capabilities […].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These definitions are a promising step forward, but apply to models as static artifacts. However, they do not address the methodology that uses AI.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;207&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-4394aa7c.Ca9SB3Hi_Z2oEBSa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Gemini cannot see the “AI” in “FAIR”, either.&lt;/p&gt;
&lt;h2 id=&quot;fair-software&quot;&gt;FAIR Software&lt;/h2&gt;
&lt;p&gt;Software did not fit into the original FAIR principles that assumed static data sets, hence specific FAIR principles for research software were &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;introduced&lt;/a&gt;, along with a &lt;a href=&quot;https://fairsoftwarechecklist.net/&quot;&gt;checklist&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;F&lt;/strong&gt;indable: the software should have a globally unique identifier and be registered in e.g. the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;, […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;/strong&gt;ccessible: users can access the software, including its source code […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;nteroperable: the software should read and write open data formats, […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eusable: all information to compile the software is provided, […].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together with DANS, we have also provided &lt;a href=&quot;https://fair-software.eu/&quot;&gt;recommendations&lt;/a&gt; on how to practically implement these criteria using available services.&lt;/p&gt;
&lt;h2 id=&quot;ai-in-science&quot;&gt;AI in Science&lt;/h2&gt;
&lt;p&gt;AI impacts scientific methods in different ways than software did, though. A &lt;a href=&quot;https://royalsociety.org/news-resources/projects/science-in-the-age-of-ai/&quot;&gt;report by the Royal Society&lt;/a&gt; lists six use cases for AI in research:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract and learn features from raw data and extensive datasets&lt;/li&gt;
&lt;li&gt;Gain insights from unstructured, multi-modal and fragmented data&lt;/li&gt;
&lt;li&gt;Generate predictions and synthetic data from existing content&lt;/li&gt;
&lt;li&gt;Information synthesis in academic writing, literature reviews and summarization&lt;/li&gt;
&lt;li&gt;Generate software code&lt;/li&gt;
&lt;li&gt;Automate labour-intensive tasks to test diverse hypotheses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In these examples, machine learning and language models are not the subject of research but instead serve as means to various ends.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;203&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-fc40bcad.Db99iNnf_Z2seaDg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: the Llama model is certain that there is no AI in FAIR.Computational linguists have shown that (Large) Language Models serve as &lt;a href=&quot;https://doi.org/10.1145/3442188.3445922&quot;&gt;parrots&lt;/a&gt; that remix the data they have been trained on in unpredictable ways, which entails risks including ecological harm, economic monopolization and encoded biases. When putting those aside for a moment, ‘parroting’ might not sound too bad from a reproducibility point of view. However, nobody knows what a generative language model is parroting exactly. Not even the developers, let alone the users, can trace back the &lt;a href=&quot;https://suchir.net/fair_use.html&quot;&gt;impact of specific data samples on the weights of a model&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://doi.org/10.1145/3442188.3445922&quot;&gt;Royal Society report&lt;/a&gt; lists additional concerns, for instance, researchers with misconceptions about statistics, overreliance on machine learning outputs, and a lack of skills and incentives for academic researchers. Lack of transparency is often built into proprietary products, but LLMs are a particularly hard-to-open black box, as they involve complex stochastic processes. Misleading marketing claims and bold promises from the companies behind the chatbots increase transparency even more, rather than mitigating them.&lt;/p&gt;
&lt;h2 id=&quot;new-fair-principles&quot;&gt;New FAIR Principles&lt;/h2&gt;
&lt;p&gt;FAIR principles for AI must make sure that all information about AI-based research is provided so that other researchers can understand, verify and reproduce the results of a colleague. The enormous resources required to develop a new language model make reusability particularly relevant. Reinventing a wheel of that size again and again is too costly for any society.&lt;/p&gt;
&lt;p&gt;The fuzziness of the decades&lt;a href=&quot;https://doi.org/10.3233/HSM-1985-5207&quot;&gt;-old term Artificial Intelligence&lt;/a&gt;, as well as its misuse &lt;a href=&quot;https://bookshop.org/p/books/empire-of-ai-dreams-and-nightmares-in-sam-altman-s-openai-karen-hao/22156498&quot;&gt;for utopian and dystopian myths&lt;/a&gt; and &lt;a href=&quot;https://thecon.ai/&quot;&gt;cons,&lt;/a&gt; has created a semantic fog around AI that is counterproductive for spreading technical understanding, sometimes causing &lt;a href=&quot;https://www.theatlantic.com/culture/archive/2025/06/artificial-intelligence-illiteracy/683021/&quot;&gt;catastrophic consequences for the users&lt;/a&gt;. Recent studies have shown how the most recent trend within the AI community, “reasoning models”, creates an &lt;a href=&quot;https://substack.com/inbox/post/166103484&quot;&gt;illusion of thinking&lt;/a&gt;. At the same time, the go-to methods for evaluating Chatbots have turned out to be misleading, as shown in the &lt;a href=&quot;http://arxiv.org/abs/2504.20879&quot;&gt;Leaderboard Illusion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1293&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-b427a737.Bdkc9wXy_1VP1Ap.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: LLMs tend to fail on reasoning tasks if they do not exactly match the training data.Those who sell the promise of redemption through AGI (Artificial General Intelligence*) are not interested in transparency or Open Science. Bringing FAIRness into the field, on the other hand, facilitates scientific progress. FAIR principles for AI must allow researchers to understand AI and enable them to make informed decisions about how to incorporate it into their research.&lt;/p&gt;
&lt;p&gt;The first step is to move away from referring to LLM-based, generative AI in a mystifying manner. Instead, researchers must discuss tangible tasks and techniques that can be evaluated objectively. Only this will allow us to define FAIR principles for AI: how can we make sure, LLM outputs can be f**ound by anyone, are &lt;strong&gt;a&lt;/strong&gt;ccessible through open protocols, &lt;strong&gt;i&lt;/strong&gt;nteroperable with other research data, and — perhaps most importantly — become &lt;strong&gt;r&lt;/strong&gt;eproducible?&lt;/p&gt;</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Open Science is driven by FAIR principles. Made for data, adapted for software, how can they survive the current wave of “Artificial Intelligence”? Resistance from those selling it as a solution for all problems is to be expected.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scientific progress is actively hindered if research data is stored on inaccessible servers or private hard disks, in proprietary formats, or preprocessed in unknown ways. The authors of the &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;original FAIR&lt;/a&gt; &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;paper&lt;/a&gt; have therefore demanded to leave non-collaborative practices behind: instead, make data F**indable, &lt;strong&gt;A&lt;/strong&gt;ccessible, &lt;strong&gt;I&lt;/strong&gt;nteroperable and &lt;strong&gt;R&lt;/strong&gt;eusable (FAIR)!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-4309ea06.BpquOFT5_2wdBHI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@theshantanukr?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Shantanu Kumar&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;The underlying ideas have been pillars of scientific methodology &lt;a href=&quot;https://blog.esciencecenter.nl/fair-principles-5000-years-of-common-sense-ba85086ba79c&quot;&gt;for thousands of years&lt;/a&gt;, but the rise of computerized methods in practically all research fields has created the need to make the FAIR principles explicit. The increase of computational processing power and algorithms to make efficient use of it have interwoven disciplines including Natural Language Processing, Information Retrieval, Information Science, and Computer Science. Artificial Intelligence is one of the products and has now impacted not only academic research, but also medicine, [education](&lt;a href=&quot;https://doi.org/10.48550/ar&quot;&gt;https://doi.org/10.48550/ar&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Xiv.2412.06651), libraries and archives, and even &lt;a href=&quot;https://www.rollingstone.com/culture/culture-features/ai-spiritual-delusions-destroying-human-relationships-1235330175/&quot;&gt;spirituality&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fair-vs-ai&quot;&gt;Fair vs. AI&lt;/h2&gt;
&lt;p&gt;Not reinventing the wheel for each study is the essence of scientific progress; hence, reusability is the primary goal of the FAIR principles. Promises about advances to be expected by current AI generations are bold. Supposedly, they achieve “&lt;a href=&quot;https://arxiv.org/abs/2311.12022&quot;&gt;PhD-level intelligence&lt;/a&gt;” already, even though a closer look reveals that this merely refers to the ability to fill in exam questions accurately. Anyway, the FAIR principles seem to be falling off the wagon, as ChatGPT and its colleagues are happy to confirm (see Figures 1–3).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;621&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-9836fa99.BECPsWIg_Z2b781H.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: According to ChatGPT, the letters “A” and “I” do not appear in FAIR.The paper “&lt;a href=&quot;https://www.nature.com/articles/s41597-023-02298-6&quot;&gt;FAIR for AI: An interdisciplinary and international community building perspective&lt;/a&gt;” proposed the following definitions for FAIR AI models:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AI model is &lt;strong&gt;Findable&lt;/strong&gt; when a digital object identifier (DOI) can direct a human or machine to a digital resource […];&lt;/li&gt;
&lt;li&gt;it is &lt;strong&gt;Accessible&lt;/strong&gt; when it and its metadata may be readily downloaded […];&lt;/li&gt;
&lt;li&gt;it is &lt;strong&gt;Interoperable&lt;/strong&gt; when it can seamlessly interact with other models, data, software, and hardware architectures;&lt;/li&gt;
&lt;li&gt;and it is &lt;strong&gt;Reusable&lt;/strong&gt; when it can be used by humans, machines and other models to reproduce its expected inference capabilities […].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These definitions are a promising step forward, but apply to models as static artifacts. However, they do not address the methodology that uses AI.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;207&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-4394aa7c.Ca9SB3Hi_Z2oEBSa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Gemini cannot see the “AI” in “FAIR”, either.&lt;/p&gt;
&lt;h2 id=&quot;fair-software&quot;&gt;FAIR Software&lt;/h2&gt;
&lt;p&gt;Software did not fit into the original FAIR principles that assumed static data sets, hence specific FAIR principles for research software were &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;introduced&lt;/a&gt;, along with a &lt;a href=&quot;https://fairsoftwarechecklist.net/&quot;&gt;checklist&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;F&lt;/strong&gt;indable: the software should have a globally unique identifier and be registered in e.g. the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;, […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;/strong&gt;ccessible: users can access the software, including its source code […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;nteroperable: the software should read and write open data formats, […].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eusable: all information to compile the software is provided, […].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together with DANS, we have also provided &lt;a href=&quot;https://fair-software.eu/&quot;&gt;recommendations&lt;/a&gt; on how to practically implement these criteria using available services.&lt;/p&gt;
&lt;h2 id=&quot;ai-in-science&quot;&gt;AI in Science&lt;/h2&gt;
&lt;p&gt;AI impacts scientific methods in different ways than software did, though. A &lt;a href=&quot;https://royalsociety.org/news-resources/projects/science-in-the-age-of-ai/&quot;&gt;report by the Royal Society&lt;/a&gt; lists six use cases for AI in research:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract and learn features from raw data and extensive datasets&lt;/li&gt;
&lt;li&gt;Gain insights from unstructured, multi-modal and fragmented data&lt;/li&gt;
&lt;li&gt;Generate predictions and synthetic data from existing content&lt;/li&gt;
&lt;li&gt;Information synthesis in academic writing, literature reviews and summarization&lt;/li&gt;
&lt;li&gt;Generate software code&lt;/li&gt;
&lt;li&gt;Automate labour-intensive tasks to test diverse hypotheses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In these examples, machine learning and language models are not the subject of research but instead serve as means to various ends.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;203&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-fc40bcad.Db99iNnf_Z2seaDg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: the Llama model is certain that there is no AI in FAIR.Computational linguists have shown that (Large) Language Models serve as &lt;a href=&quot;https://doi.org/10.1145/3442188.3445922&quot;&gt;parrots&lt;/a&gt; that remix the data they have been trained on in unpredictable ways, which entails risks including ecological harm, economic monopolization and encoded biases. When putting those aside for a moment, ‘parroting’ might not sound too bad from a reproducibility point of view. However, nobody knows what a generative language model is parroting exactly. Not even the developers, let alone the users, can trace back the &lt;a href=&quot;https://suchir.net/fair_use.html&quot;&gt;impact of specific data samples on the weights of a model&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://doi.org/10.1145/3442188.3445922&quot;&gt;Royal Society report&lt;/a&gt; lists additional concerns, for instance, researchers with misconceptions about statistics, overreliance on machine learning outputs, and a lack of skills and incentives for academic researchers. Lack of transparency is often built into proprietary products, but LLMs are a particularly hard-to-open black box, as they involve complex stochastic processes. Misleading marketing claims and bold promises from the companies behind the chatbots increase transparency even more, rather than mitigating them.&lt;/p&gt;
&lt;h2 id=&quot;new-fair-principles&quot;&gt;New FAIR Principles&lt;/h2&gt;
&lt;p&gt;FAIR principles for AI must make sure that all information about AI-based research is provided so that other researchers can understand, verify and reproduce the results of a colleague. The enormous resources required to develop a new language model make reusability particularly relevant. Reinventing a wheel of that size again and again is too costly for any society.&lt;/p&gt;
&lt;p&gt;The fuzziness of the decades&lt;a href=&quot;https://doi.org/10.3233/HSM-1985-5207&quot;&gt;-old term Artificial Intelligence&lt;/a&gt;, as well as its misuse &lt;a href=&quot;https://bookshop.org/p/books/empire-of-ai-dreams-and-nightmares-in-sam-altman-s-openai-karen-hao/22156498&quot;&gt;for utopian and dystopian myths&lt;/a&gt; and &lt;a href=&quot;https://thecon.ai/&quot;&gt;cons,&lt;/a&gt; has created a semantic fog around AI that is counterproductive for spreading technical understanding, sometimes causing &lt;a href=&quot;https://www.theatlantic.com/culture/archive/2025/06/artificial-intelligence-illiteracy/683021/&quot;&gt;catastrophic consequences for the users&lt;/a&gt;. Recent studies have shown how the most recent trend within the AI community, “reasoning models”, creates an &lt;a href=&quot;https://substack.com/inbox/post/166103484&quot;&gt;illusion of thinking&lt;/a&gt;. At the same time, the go-to methods for evaluating Chatbots have turned out to be misleading, as shown in the &lt;a href=&quot;http://arxiv.org/abs/2504.20879&quot;&gt;Leaderboard Illusion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Could AI be (in) FAIR?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1293&quot; src=&quot;https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-b427a737.Bdkc9wXy_1VP1Ap.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: LLMs tend to fail on reasoning tasks if they do not exactly match the training data.Those who sell the promise of redemption through AGI (Artificial General Intelligence*) are not interested in transparency or Open Science. Bringing FAIRness into the field, on the other hand, facilitates scientific progress. FAIR principles for AI must allow researchers to understand AI and enable them to make informed decisions about how to incorporate it into their research.&lt;/p&gt;
&lt;p&gt;The first step is to move away from referring to LLM-based, generative AI in a mystifying manner. Instead, researchers must discuss tangible tasks and techniques that can be evaluated objectively. Only this will allow us to define FAIR principles for AI: how can we make sure, LLM outputs can be f**ound by anyone, are &lt;strong&gt;a&lt;/strong&gt;ccessible through open protocols, &lt;strong&gt;i&lt;/strong&gt;nteroperable with other research data, and — perhaps most importantly — become &lt;strong&gt;r&lt;/strong&gt;eproducible?&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/could-ai-be-in-fair-4309ea06.BpquOFT5.jpg" medium="image"/><author>Carsten Schnober</author></item><item><title>Empirically evaluating privacy in machine learning I: Introduction</title><link>https://blog.esciencecenter.nl/posts/2025-06-27---empirically-evaluating-privacy-in-machine-learning-i-introdu</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-06-27---empirically-evaluating-privacy-in-machine-learning-i-introdu</guid><description>&lt;p&gt;Research in the social and health sciences often relies on accessing data sourced from statistical agencies or healthcare organizations. Such data sets contain sensitive information, which requires restrictions on who can access the data. This can slow down not only scientific progress — if data were completely open, more researchers could investigate them — , but also the translation of progress to applications — for instance, machine learning models trained on medical data cannot easily be shared and re-used for personalized treatments.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;445&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-4e61e1c6.CszbPpVQ_Z14axac.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nci?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;National Cancer Institute&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Differential privacy is one technology that aims to solve this problem. Intuitively, it is a method that adds calibrated noise to the data, and so prevents a malevolent actor from learning sensitive attributes about any person in the underlying data. But because statistical noise makes statistical inference harder, there is an inherent trade-off between statistical utility and privacy — making differential privacy challenging to deploy in practice (&lt;a href=&quot;https://arxiv.org/abs/2406.12103&quot;&gt;Cummings &amp;#x26; Sarathy, 2023&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In addition, using differential privacy in machine learning has its own challenges. First, often it’s impossible to have reasonable privacy and utility at the same time. Second, differential privacy for machine learning makes strong assumptions about the capabilities of the malevolent actor. Third, implementing it in software is not straightforward, and there is evidence of bugs (&lt;a href=&quot;https://arxiv.org/abs/2304.06929&quot;&gt;Cummings et al, 2023&lt;/a&gt;; &lt;a href=&quot;https://arxiv.org/abs/2302.07956&quot;&gt;Nasr et al, 2023&lt;/a&gt;; &lt;a href=&quot;https://arxiv.org/abs/2303.00654&quot;&gt;Ponomareva et al, 2023&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For this reason, empirically evaluating the privacy of machine learning models has become an important field of research. Privacy testing probes whether a trained machine learning model leaks sensitive information. It can be an important indicator for model developers and owners of sensitive data whether the privacy-preserving training mechanism can be trusted.&lt;/p&gt;
&lt;h3 id=&quot;the-plan-for-this-series-of-blog-posts&quot;&gt;The plan for this series of blog posts&lt;/h3&gt;
&lt;p&gt;Despite this, most resources in this topic are in research articles. The goal of this series of blog posts is to make the topic more accessible. We will build knowledge from the ground up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first blog posts introduces differential privacy, and gives some economic intuition. It is aimed at readers unfamiliar with differential privacy.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;second&lt;/a&gt; post explains how differential privacy can be interpreted from a perspective of statistical hypothesis testing. It is aimed at readers familiar with differential privacy and some concepts from statistics and machine learning.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-iii-functional-gaussian-differential-privacy-ccef13153e12&quot;&gt;third&lt;/a&gt; post discusses how the hypothesis testing perspective has been used to reformulate differential privacy with functional differential privacy and Gaussian differential privacy. It is aimed at readers interested in understanding privacy testing of machine learning.&lt;/li&gt;
&lt;li&gt;The fourth blog post discusses some recent papers that audit machine learning models and make use of Gaussian differential privacy. It is aimed at an audience similar to the third post.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6ef4dfa5.C41y5zu0_Z2omCrL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@tobiastu?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tobias Tullius&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-short-introduction-with-an-example&quot;&gt;A short introduction with an example&lt;/h2&gt;
&lt;p&gt;This section builds on &lt;a href=&quot;https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf&quot;&gt;Dwork &amp;#x26; Roth (2013)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;randomized-response&quot;&gt;Randomized response&lt;/h3&gt;
&lt;p&gt;Imagine a researcher wants to know the fraction of people that engage in a behavior that is illegal or socially not accepted — for instance, if they have income that they do not declare to the tax agency. The researcher runs a survey and asks people whether they have such income. Denote this behavior by the variable &lt;em&gt;X&lt;/em&gt;, and let’s say it can take values 0 or 1, where 1 indicates the person earns undeclared income, and 0 indicates the person does not.&lt;/p&gt;
&lt;p&gt;How can the researcher ensure that people are willing to share this sensitive information with them? To solve this problem, social scientists have developed a method called &lt;em&gt;randomized response&lt;/em&gt;, which gives survey participants the following instructions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flip a coin privately&lt;/li&gt;
&lt;li&gt;If it comes up heads, answer truthfully&lt;/li&gt;
&lt;li&gt;If it comes up tails, flip again. If the second flip is heads, answer with “1”, if the second flip is tails, answer with “0”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach strikes a balance between privacy and statistical utility. First, privacy comes from plausible deniability — anyone can always plausibly claim not to engage in behavior *X, *independently of the answer they have given. Second, statistical accuracy comes from understanding how the noise was generated: because we know the response mechanism, we can infer the mean of &lt;em&gt;X&lt;/em&gt; in the population.&lt;/p&gt;
&lt;p&gt;In addition, in a more general setting, one could replace the first coin flip with a draw from a continuous random variable that takes values between 0 and 1, and instruct people to respond truthfully if the random variable is above some threshold &lt;code&gt;p&lt;/code&gt;. Varying &lt;code&gt;p&lt;/code&gt; amounts to varying the amount of noise we introduce to the response. On one hand, if &lt;code&gt;p=0&lt;/code&gt; , we have perfect accuracy but no privacy. If &lt;code&gt;p=1&lt;/code&gt; , we have perfect privacy but no accuracy.&lt;/p&gt;
&lt;h3 id=&quot;formal-definition-of-differential-privacy&quot;&gt;Formal definition of differential privacy&lt;/h3&gt;
&lt;p&gt;Define &lt;code&gt;db&lt;/code&gt; as a tabular database where each row corresponds to the data of one person. We call &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt; neighboring databases when they differ by one record: they hold the exact same information, except for one person called Anne. For instance, it can be that Anne is not present in database &lt;code&gt;db0&lt;/code&gt; but in &lt;code&gt;db1&lt;/code&gt;, or that some column in Anne’s row is altered in &lt;code&gt;db1&lt;/code&gt; but not &lt;code&gt;db0&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Now, consider an algorithm &lt;code&gt;M&lt;/code&gt; that takes &lt;code&gt;db&lt;/code&gt; as input and creates some output. The algorithm is randomized because its outcome is not deterministic, but drawn from some distribution: The distribution of outcomes of the algorithm when fed with &lt;code&gt;db&lt;/code&gt; is denoted &lt;code&gt;M(db)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Such an algorithm is called &lt;code&gt;(epsilon,0)&lt;/code&gt; -differentially private** if the distribution of &lt;code&gt;M(db0)&lt;/code&gt; and the distribution &lt;code&gt;M(db1)&lt;/code&gt; are not too different from each other — formally, if the log odds of observing any outcome from &lt;code&gt;M(db0)&lt;/code&gt; vs &lt;code&gt;M(db1)&lt;/code&gt; are not larger than &lt;code&gt;epsilon&lt;/code&gt;. The &lt;code&gt;0&lt;/code&gt; in the &lt;code&gt;(epsilon,0)&lt;/code&gt; expression is a second parameter called &lt;code&gt;delta&lt;/code&gt;, which denotes the probability that this guarantee fails. It is typically a very small number that decreases in the size of the database &lt;code&gt;db&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacy-of-randomized-response&quot;&gt;Differential Privacy of randomized response&lt;/h3&gt;
&lt;p&gt;This is an abstract definition, but we now show that randomized response satisfies differential privacy. To do so, we assume that the database &lt;code&gt;db&lt;/code&gt; only consists of one person — one row — , and one variable — the answer to the survey. We will relax this assumption later.&lt;/p&gt;
&lt;p&gt;Let &lt;code&gt;y_i = M(x_i)=1&lt;/code&gt; denoting that person &lt;code&gt;i &lt;/code&gt;with attribute &lt;code&gt;x_i&lt;/code&gt; answers 1 to the survey. Note that we only observe &lt;code&gt;y_i&lt;/code&gt; and &lt;code&gt;x_i&lt;/code&gt; is kept private. The randomized mechanism &lt;code&gt;M&lt;/code&gt; is the protocol that instructs people to flip coins and respond accordingly; &lt;code&gt;M&lt;/code&gt; generates a Bernoulli distribution of outcomes over neighboring databases with the following probabilities.&lt;/p&gt;
&lt;p&gt;We can construct neighboring databases by varying person &lt;code&gt;i&lt;/code&gt;‘s sensitive attribute &lt;code&gt;x_i&lt;/code&gt;: One input database has &lt;code&gt;x_i=1&lt;/code&gt;, and the other has &lt;code&gt;x_i=0&lt;/code&gt; . Running randomized response, what are the probabilities of &lt;code&gt;y_i=1&lt;/code&gt; given values for &lt;code&gt;x&lt;/code&gt; ? If &lt;code&gt;x_i=1&lt;/code&gt;, the person answers “1” with probability 0.75; if &lt;code&gt;x_i=0&lt;/code&gt; , the person answers “1” with probability 0.25. In other words, for person&lt;code&gt;i&lt;/code&gt; , the odds ratio for randomized response returning &lt;code&gt;y_i=1&lt;/code&gt; when having &lt;code&gt;x_i=1&lt;/code&gt; as opposed to having &lt;code&gt;x_i=0&lt;/code&gt; is &lt;code&gt;P[y_i=1|x_i=1]/P[y_i=1|x_i=0]=(3/4)/(1/4)=3&lt;/code&gt; . We can do a similar analysis for the outcome &lt;code&gt;y_i=0&lt;/code&gt; . Therefore, randomized response satisfies &lt;code&gt;(ln(3),0)&lt;/code&gt; differential privacy.&lt;/p&gt;
&lt;h3 id=&quot;economic-intuition&quot;&gt;Economic intuition&lt;/h3&gt;
&lt;p&gt;What does differential privacy promise? Let’s continue with the example of undeclared income. Suppose the researcher publishes the finding that 50% of people have some undeclared income. In response, the tax agency improves their enforcement, finds the people that do not declare income, and fines them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;473&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-c531cffb.iqzll6ry_ZFHth2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nypl?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;The New York Public Library&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pick one person, Bob, who is a tax dodger and who participated in the original survey of the researcher. Because of better enforcement, he gets caught by the tax office and needs to pay a fine. Does differential privacy guarantee that Bob is not being penalized for his behavior?&lt;/p&gt;
&lt;p&gt;No. Recall that differential privacy guarantees a similar distribution of outcomes under two neighboring databases. Releasing the survey result does impact Bob’s utility, but it does so independently of whether Bob is in the data or not: Even if Bob did not participate in the original survey, the tax office would have learned that many people do not declare their income, and started stronger enforcement, possibly leading to Bob being caught and fined.&lt;/p&gt;
&lt;p&gt;In other words, Bob’s expected utility is similar in the two scenarios considered, and no differential harm* is caused to Bob from releasing the survey results. This highlights a crucial aspect of differential privacy: &lt;strong&gt;what matters is the difference in outcomes from being in the database and from not being in the database&lt;/strong&gt;. Differential privacy makes no guarantees about the &lt;em&gt;level&lt;/em&gt; of utility of records in the database. And in consequence, “Statistical Inference is Not a Privacy Violation” (&lt;a href=&quot;https://differentialprivacy.org/inference-is-not-a-privacy-violation/&quot;&gt;Bun et. al., 2021&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;the-limits-of-this-example&quot;&gt;The limits of this example&lt;/h2&gt;
&lt;p&gt;Above, we made the simplifying assumption that a database consists only of one row and one column. In real life, databases have multiple rows and columns. That’s why it is common to define neighboring databases by taking two databases that vary exactly by one row, but are otherwise identical.&lt;/p&gt;
&lt;p&gt;But working with this definition, applying randomized response to the sensitive attribute &lt;code&gt;x_i&lt;/code&gt; is not enough anymore to guarantee the privacy of each person in the survey. For instance, if for each person, the researcher published the randomized response &lt;code&gt;y_i&lt;/code&gt; along with some of their true identifying information — for instance their address and age — , it would be possible for the tax office to prosecute people with &lt;code&gt;y_i=1&lt;/code&gt;, since they are more likely to have &lt;code&gt;x_i=1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead, the researcher needs to collect the real answers of all participants, decide which statistic to use for publishing the results, and apply a respective algorithm that satisfies differential privacy. But this then also requires that the survey participants trust the researcher that they will not use the sensitive data against them.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacys-model-of-computation&quot;&gt;Differential privacy’s model of computation&lt;/h3&gt;
&lt;p&gt;These questions bring us to two important assumptions behind the theory of differential privacy. The first assumption is that there is a &lt;strong&gt;trusted curator&lt;/strong&gt; of the data — in our case the researcher that holds the individual survey responses are trusted to not leak the individual responses to the tax office.&lt;/p&gt;
&lt;p&gt;The second assumption is that only results to &lt;strong&gt;queries&lt;/strong&gt; are released — in our case, a relevant statistic of the survey such as “the fraction of people that have undeclared income”.&lt;/p&gt;
&lt;p&gt;Another important aspect of differential privacy is that multiple queries of the same data weaken privacy, even if each query itself satisfies differential privacy. For instance, suppose the researcher allowed the tax office to get multiple differentially private queries of the original data. Then, the tax office could gradually refine their queries and potentially identify a certain person that does not pay their taxes.&lt;/p&gt;
&lt;p&gt;This problem is known as &lt;strong&gt;composition&lt;/strong&gt;, and differential privacy provides mathematical tools to study how exactly privacy degrades with composition. We will touch on it again in the context of differentially private machine learning.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We used an example from social science research to illustrate how differential privacy can strike a trade-off between utility and privacy. The example helped illustrate the assumptions that are important for privacy guarantees. In the &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;next&lt;/a&gt; blog post, we will look at the hypothesis testing interpretation of differential privacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</description><pubDate>Fri, 27 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Research in the social and health sciences often relies on accessing data sourced from statistical agencies or healthcare organizations. Such data sets contain sensitive information, which requires restrictions on who can access the data. This can slow down not only scientific progress — if data were completely open, more researchers could investigate them — , but also the translation of progress to applications — for instance, machine learning models trained on medical data cannot easily be shared and re-used for personalized treatments.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;445&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-4e61e1c6.CszbPpVQ_Z14axac.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nci?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;National Cancer Institute&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Differential privacy is one technology that aims to solve this problem. Intuitively, it is a method that adds calibrated noise to the data, and so prevents a malevolent actor from learning sensitive attributes about any person in the underlying data. But because statistical noise makes statistical inference harder, there is an inherent trade-off between statistical utility and privacy — making differential privacy challenging to deploy in practice (&lt;a href=&quot;https://arxiv.org/abs/2406.12103&quot;&gt;Cummings &amp;#x26; Sarathy, 2023&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In addition, using differential privacy in machine learning has its own challenges. First, often it’s impossible to have reasonable privacy and utility at the same time. Second, differential privacy for machine learning makes strong assumptions about the capabilities of the malevolent actor. Third, implementing it in software is not straightforward, and there is evidence of bugs (&lt;a href=&quot;https://arxiv.org/abs/2304.06929&quot;&gt;Cummings et al, 2023&lt;/a&gt;; &lt;a href=&quot;https://arxiv.org/abs/2302.07956&quot;&gt;Nasr et al, 2023&lt;/a&gt;; &lt;a href=&quot;https://arxiv.org/abs/2303.00654&quot;&gt;Ponomareva et al, 2023&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For this reason, empirically evaluating the privacy of machine learning models has become an important field of research. Privacy testing probes whether a trained machine learning model leaks sensitive information. It can be an important indicator for model developers and owners of sensitive data whether the privacy-preserving training mechanism can be trusted.&lt;/p&gt;
&lt;h3 id=&quot;the-plan-for-this-series-of-blog-posts&quot;&gt;The plan for this series of blog posts&lt;/h3&gt;
&lt;p&gt;Despite this, most resources in this topic are in research articles. The goal of this series of blog posts is to make the topic more accessible. We will build knowledge from the ground up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first blog posts introduces differential privacy, and gives some economic intuition. It is aimed at readers unfamiliar with differential privacy.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;second&lt;/a&gt; post explains how differential privacy can be interpreted from a perspective of statistical hypothesis testing. It is aimed at readers familiar with differential privacy and some concepts from statistics and machine learning.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-iii-functional-gaussian-differential-privacy-ccef13153e12&quot;&gt;third&lt;/a&gt; post discusses how the hypothesis testing perspective has been used to reformulate differential privacy with functional differential privacy and Gaussian differential privacy. It is aimed at readers interested in understanding privacy testing of machine learning.&lt;/li&gt;
&lt;li&gt;The fourth blog post discusses some recent papers that audit machine learning models and make use of Gaussian differential privacy. It is aimed at an audience similar to the third post.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6ef4dfa5.C41y5zu0_Z2omCrL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@tobiastu?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tobias Tullius&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-short-introduction-with-an-example&quot;&gt;A short introduction with an example&lt;/h2&gt;
&lt;p&gt;This section builds on &lt;a href=&quot;https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf&quot;&gt;Dwork &amp;#x26; Roth (2013)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;randomized-response&quot;&gt;Randomized response&lt;/h3&gt;
&lt;p&gt;Imagine a researcher wants to know the fraction of people that engage in a behavior that is illegal or socially not accepted — for instance, if they have income that they do not declare to the tax agency. The researcher runs a survey and asks people whether they have such income. Denote this behavior by the variable &lt;em&gt;X&lt;/em&gt;, and let’s say it can take values 0 or 1, where 1 indicates the person earns undeclared income, and 0 indicates the person does not.&lt;/p&gt;
&lt;p&gt;How can the researcher ensure that people are willing to share this sensitive information with them? To solve this problem, social scientists have developed a method called &lt;em&gt;randomized response&lt;/em&gt;, which gives survey participants the following instructions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flip a coin privately&lt;/li&gt;
&lt;li&gt;If it comes up heads, answer truthfully&lt;/li&gt;
&lt;li&gt;If it comes up tails, flip again. If the second flip is heads, answer with “1”, if the second flip is tails, answer with “0”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach strikes a balance between privacy and statistical utility. First, privacy comes from plausible deniability — anyone can always plausibly claim not to engage in behavior *X, *independently of the answer they have given. Second, statistical accuracy comes from understanding how the noise was generated: because we know the response mechanism, we can infer the mean of &lt;em&gt;X&lt;/em&gt; in the population.&lt;/p&gt;
&lt;p&gt;In addition, in a more general setting, one could replace the first coin flip with a draw from a continuous random variable that takes values between 0 and 1, and instruct people to respond truthfully if the random variable is above some threshold &lt;code&gt;p&lt;/code&gt;. Varying &lt;code&gt;p&lt;/code&gt; amounts to varying the amount of noise we introduce to the response. On one hand, if &lt;code&gt;p=0&lt;/code&gt; , we have perfect accuracy but no privacy. If &lt;code&gt;p=1&lt;/code&gt; , we have perfect privacy but no accuracy.&lt;/p&gt;
&lt;h3 id=&quot;formal-definition-of-differential-privacy&quot;&gt;Formal definition of differential privacy&lt;/h3&gt;
&lt;p&gt;Define &lt;code&gt;db&lt;/code&gt; as a tabular database where each row corresponds to the data of one person. We call &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt; neighboring databases when they differ by one record: they hold the exact same information, except for one person called Anne. For instance, it can be that Anne is not present in database &lt;code&gt;db0&lt;/code&gt; but in &lt;code&gt;db1&lt;/code&gt;, or that some column in Anne’s row is altered in &lt;code&gt;db1&lt;/code&gt; but not &lt;code&gt;db0&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Now, consider an algorithm &lt;code&gt;M&lt;/code&gt; that takes &lt;code&gt;db&lt;/code&gt; as input and creates some output. The algorithm is randomized because its outcome is not deterministic, but drawn from some distribution: The distribution of outcomes of the algorithm when fed with &lt;code&gt;db&lt;/code&gt; is denoted &lt;code&gt;M(db)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Such an algorithm is called &lt;code&gt;(epsilon,0)&lt;/code&gt; -differentially private** if the distribution of &lt;code&gt;M(db0)&lt;/code&gt; and the distribution &lt;code&gt;M(db1)&lt;/code&gt; are not too different from each other — formally, if the log odds of observing any outcome from &lt;code&gt;M(db0)&lt;/code&gt; vs &lt;code&gt;M(db1)&lt;/code&gt; are not larger than &lt;code&gt;epsilon&lt;/code&gt;. The &lt;code&gt;0&lt;/code&gt; in the &lt;code&gt;(epsilon,0)&lt;/code&gt; expression is a second parameter called &lt;code&gt;delta&lt;/code&gt;, which denotes the probability that this guarantee fails. It is typically a very small number that decreases in the size of the database &lt;code&gt;db&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacy-of-randomized-response&quot;&gt;Differential Privacy of randomized response&lt;/h3&gt;
&lt;p&gt;This is an abstract definition, but we now show that randomized response satisfies differential privacy. To do so, we assume that the database &lt;code&gt;db&lt;/code&gt; only consists of one person — one row — , and one variable — the answer to the survey. We will relax this assumption later.&lt;/p&gt;
&lt;p&gt;Let &lt;code&gt;y_i = M(x_i)=1&lt;/code&gt; denoting that person &lt;code&gt;i &lt;/code&gt;with attribute &lt;code&gt;x_i&lt;/code&gt; answers 1 to the survey. Note that we only observe &lt;code&gt;y_i&lt;/code&gt; and &lt;code&gt;x_i&lt;/code&gt; is kept private. The randomized mechanism &lt;code&gt;M&lt;/code&gt; is the protocol that instructs people to flip coins and respond accordingly; &lt;code&gt;M&lt;/code&gt; generates a Bernoulli distribution of outcomes over neighboring databases with the following probabilities.&lt;/p&gt;
&lt;p&gt;We can construct neighboring databases by varying person &lt;code&gt;i&lt;/code&gt;‘s sensitive attribute &lt;code&gt;x_i&lt;/code&gt;: One input database has &lt;code&gt;x_i=1&lt;/code&gt;, and the other has &lt;code&gt;x_i=0&lt;/code&gt; . Running randomized response, what are the probabilities of &lt;code&gt;y_i=1&lt;/code&gt; given values for &lt;code&gt;x&lt;/code&gt; ? If &lt;code&gt;x_i=1&lt;/code&gt;, the person answers “1” with probability 0.75; if &lt;code&gt;x_i=0&lt;/code&gt; , the person answers “1” with probability 0.25. In other words, for person&lt;code&gt;i&lt;/code&gt; , the odds ratio for randomized response returning &lt;code&gt;y_i=1&lt;/code&gt; when having &lt;code&gt;x_i=1&lt;/code&gt; as opposed to having &lt;code&gt;x_i=0&lt;/code&gt; is &lt;code&gt;P[y_i=1|x_i=1]/P[y_i=1|x_i=0]=(3/4)/(1/4)=3&lt;/code&gt; . We can do a similar analysis for the outcome &lt;code&gt;y_i=0&lt;/code&gt; . Therefore, randomized response satisfies &lt;code&gt;(ln(3),0)&lt;/code&gt; differential privacy.&lt;/p&gt;
&lt;h3 id=&quot;economic-intuition&quot;&gt;Economic intuition&lt;/h3&gt;
&lt;p&gt;What does differential privacy promise? Let’s continue with the example of undeclared income. Suppose the researcher publishes the finding that 50% of people have some undeclared income. In response, the tax agency improves their enforcement, finds the people that do not declare income, and fines them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning I: Introduction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;473&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-c531cffb.iqzll6ry_ZFHth2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nypl?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;The New York Public Library&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pick one person, Bob, who is a tax dodger and who participated in the original survey of the researcher. Because of better enforcement, he gets caught by the tax office and needs to pay a fine. Does differential privacy guarantee that Bob is not being penalized for his behavior?&lt;/p&gt;
&lt;p&gt;No. Recall that differential privacy guarantees a similar distribution of outcomes under two neighboring databases. Releasing the survey result does impact Bob’s utility, but it does so independently of whether Bob is in the data or not: Even if Bob did not participate in the original survey, the tax office would have learned that many people do not declare their income, and started stronger enforcement, possibly leading to Bob being caught and fined.&lt;/p&gt;
&lt;p&gt;In other words, Bob’s expected utility is similar in the two scenarios considered, and no differential harm* is caused to Bob from releasing the survey results. This highlights a crucial aspect of differential privacy: &lt;strong&gt;what matters is the difference in outcomes from being in the database and from not being in the database&lt;/strong&gt;. Differential privacy makes no guarantees about the &lt;em&gt;level&lt;/em&gt; of utility of records in the database. And in consequence, “Statistical Inference is Not a Privacy Violation” (&lt;a href=&quot;https://differentialprivacy.org/inference-is-not-a-privacy-violation/&quot;&gt;Bun et. al., 2021&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;the-limits-of-this-example&quot;&gt;The limits of this example&lt;/h2&gt;
&lt;p&gt;Above, we made the simplifying assumption that a database consists only of one row and one column. In real life, databases have multiple rows and columns. That’s why it is common to define neighboring databases by taking two databases that vary exactly by one row, but are otherwise identical.&lt;/p&gt;
&lt;p&gt;But working with this definition, applying randomized response to the sensitive attribute &lt;code&gt;x_i&lt;/code&gt; is not enough anymore to guarantee the privacy of each person in the survey. For instance, if for each person, the researcher published the randomized response &lt;code&gt;y_i&lt;/code&gt; along with some of their true identifying information — for instance their address and age — , it would be possible for the tax office to prosecute people with &lt;code&gt;y_i=1&lt;/code&gt;, since they are more likely to have &lt;code&gt;x_i=1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead, the researcher needs to collect the real answers of all participants, decide which statistic to use for publishing the results, and apply a respective algorithm that satisfies differential privacy. But this then also requires that the survey participants trust the researcher that they will not use the sensitive data against them.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacys-model-of-computation&quot;&gt;Differential privacy’s model of computation&lt;/h3&gt;
&lt;p&gt;These questions bring us to two important assumptions behind the theory of differential privacy. The first assumption is that there is a &lt;strong&gt;trusted curator&lt;/strong&gt; of the data — in our case the researcher that holds the individual survey responses are trusted to not leak the individual responses to the tax office.&lt;/p&gt;
&lt;p&gt;The second assumption is that only results to &lt;strong&gt;queries&lt;/strong&gt; are released — in our case, a relevant statistic of the survey such as “the fraction of people that have undeclared income”.&lt;/p&gt;
&lt;p&gt;Another important aspect of differential privacy is that multiple queries of the same data weaken privacy, even if each query itself satisfies differential privacy. For instance, suppose the researcher allowed the tax office to get multiple differentially private queries of the original data. Then, the tax office could gradually refine their queries and potentially identify a certain person that does not pay their taxes.&lt;/p&gt;
&lt;p&gt;This problem is known as &lt;strong&gt;composition&lt;/strong&gt;, and differential privacy provides mathematical tools to study how exactly privacy degrades with composition. We will touch on it again in the context of differentially private machine learning.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We used an example from social science research to illustrate how differential privacy can strike a trade-off between utility and privacy. The example helped illustrate the assumptions that are important for privacy guarantees. In the &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;next&lt;/a&gt; blog post, we will look at the hypothesis testing interpretation of differential privacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-4e61e1c6.CszbPpVQ.jpg" medium="image"/><author>Flavio Hafner</author></item><item><title>Empirically evaluating privacy in machine learning II: Hypothesis testing</title><link>https://blog.esciencecenter.nl/posts/2025-06-17---empirically-evaluating-privacy-in-machine-learning-ii-hypoth</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-06-17---empirically-evaluating-privacy-in-machine-learning-ii-hypoth</guid><description>&lt;p&gt;Using statistics to think like a hacker, so we can avoid them!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;348&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-597dd224.B0jnjMFF_1md9I8.webp&quot; srcset=&quot;&quot;&gt;
Image from page 182 of “Elements of statistics” (1954). Licensed under creative commons.This post is the second in a series on evaluating privacy in machine learning models (see first episode &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;here&lt;/a&gt;). It explains the hypothesis testing interpretation of differential privacy by showing how differential privacy constrains the success of any attacker in finding out about the underlying data.&lt;/p&gt;
&lt;p&gt;The post assumes readers are familiar with differential privacy and some concepts in statistics and machine learning. In addition, it keeps concepts such as an “input database” and a “data release” abstract. If you are unfamiliar with either of these terms, you can have a look at the &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;previous post&lt;/a&gt;. It introduces differential privacy and has a specific example for an input database and a data release.&lt;/p&gt;
&lt;h2 id=&quot;differential-privacy-through-the-lens-of-hypothesis-testing&quot;&gt;Differential privacy through the lens of hypothesis testing&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;first blog post&lt;/a&gt; of this series showed that differential privacy has adversarial thinking built-in: Leaking sensitive information may allow a malevolent actor to use the information to the disadvantage of a person in the database. In a differentially private mechanism, the more noise is added, the less any adversary can learn about any particular record in the database.&lt;/p&gt;
&lt;h3 id=&quot;adversarial-inference-as-a-hypothesis-test&quot;&gt;Adversarial inference as a hypothesis test&lt;/h3&gt;
&lt;p&gt;This intuition was formalized by &lt;a href=&quot;https://arxiv.org/abs/0811.2501&quot;&gt;Wasserman &amp;#x26; Zou (2009)&lt;/a&gt;. Imagine an adversary has access to a differentially private data release &lt;code&gt;Y&lt;/code&gt; from a tabular database &lt;code&gt;db&lt;/code&gt;. And suppose the adversary wants to find out if a particular person &lt;code&gt;i&lt;/code&gt; was part of the database &lt;code&gt;db&lt;/code&gt;. Define the neighboring databases &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt;, where &lt;code&gt;i&lt;/code&gt; is only in &lt;code&gt;db1&lt;/code&gt; but not in &lt;code&gt;db0&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Then, the adversary faces the following hypothesis testing problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;H0: &lt;code&gt;Y&lt;/code&gt; was drawn from &lt;code&gt;db0&lt;/code&gt;, so that &lt;code&gt;i&lt;/code&gt; was not in the input data for &lt;code&gt;Y&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;H1: &lt;code&gt;Y&lt;/code&gt; was drawn from &lt;code&gt;db1&lt;/code&gt;, so that &lt;code&gt;i&lt;/code&gt; was in the input data for &lt;code&gt;Y&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When seeing the data, the adversary needs to make an inference about the true state of &lt;code&gt;db&lt;/code&gt; , having seen only &lt;code&gt;Y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are four possible scenarios.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The adversary correctly predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db0&lt;/code&gt;. This is a true negative.&lt;/li&gt;
&lt;li&gt;The adversary correctly predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db1&lt;/code&gt;. This is a true positive.&lt;/li&gt;
&lt;li&gt;The adversary predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db0&lt;/code&gt;, but in truth it was based on &lt;code&gt;db1&lt;/code&gt;. This is a false negative.&lt;/li&gt;
&lt;li&gt;The adversary predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db1&lt;/code&gt;, but in truth it was based on &lt;code&gt;db0&lt;/code&gt;. This is a false positive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deriving-the-roc-curve&quot;&gt;Deriving the ROC curve&lt;/h3&gt;
&lt;p&gt;How does the adversary make their inference? They need a decision rule that takes the observed data &lt;code&gt;Y&lt;/code&gt; and returns an output that is &lt;code&gt;db0&lt;/code&gt; or &lt;code&gt;db1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In a future blog post, we will be more specific on what such a rule can look like and how one can derive it. For now, we assume the adversary has the following decision rule: First, they have a trained logistic regression model that takes &lt;code&gt;Y&lt;/code&gt; as input and returns a score. Second, the adversary decides on a threshold: if the score is above the threshold, the decision rule returns &lt;code&gt;db1&lt;/code&gt;, and &lt;code&gt;db0&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;p&gt;In other words, the adversary rejects H0 in favor of H1 if the score is above the threshold. Then, lowering the threshold means rejecting H0 more often, and so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The adversary is more likely to detect cases when &lt;code&gt;Y&lt;/code&gt; is based on &lt;code&gt;db1&lt;/code&gt;. This means a higher true positive rate, which is good for the adversary.&lt;/li&gt;
&lt;li&gt;But the adversary is also more likely to predict that &lt;code&gt;Y&lt;/code&gt; is based on &lt;code&gt;db1&lt;/code&gt; when in truth it is based on &lt;code&gt;db0&lt;/code&gt;. This means a higher false positive rate, which is bad for the adversary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can visualize this trade-off with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Receiver_operating_characteristic&quot;&gt;Receiver Operating Characteristic curve&lt;/a&gt;, or ROC curve:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;537&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-921b027b.XiBibI1p_ZysgiE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: The blue line is an ROC curve. The distinguishing between H0 and H1 becomes easier as the True Positive Rate increases and the False Positive Rate decreases, thus moving North-West n the figure.In the figure above, the blue line defines the trade-off between the False Positive Rate &lt;code&gt;FPR&lt;/code&gt; and the True Positive Rate &lt;code&gt;TPR&lt;/code&gt; for a given prediction model. Lowering the &lt;code&gt;FPR&lt;/code&gt; comes at the cost of a lower &lt;code&gt;TPR&lt;/code&gt;, and vice-versa.&lt;/p&gt;
&lt;p&gt;Moreover, the red arrow indicates the direction in which it becomes easier to distinguish between H0 and H1, meaning a lower &lt;code&gt;FPR&lt;/code&gt; and a higher &lt;code&gt;TPR&lt;/code&gt;: An ideal decision rule gives an &lt;code&gt;FPR&lt;/code&gt; of 0 and a &lt;code&gt;TPR&lt;/code&gt; of 1. On the other hand, the dotted line indicates the performance of a decision rule that randomly rejects or does not reject H0.&lt;/p&gt;
&lt;p&gt;The ROC curve is a standard tool in machine learning for binary classification — and from here it is only a few steps to visualizing how differential privacy restricts the amount of information an adversary can learn from a data release.&lt;/p&gt;
&lt;h3 id=&quot;flipping-the-roc-curve&quot;&gt;Flipping the ROC curve&lt;/h3&gt;
&lt;p&gt;To start, let’s flip the y-axis in the above figure, and recognize that &lt;code&gt;1-TPR&lt;/code&gt; is the False Negative Rate &lt;code&gt;FNR&lt;/code&gt;. Thus, we have a curve in the &lt;code&gt;FPR-FNR&lt;/code&gt; space:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;568&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-57b92446.C8NgN7dQ_ZPkyQT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: The blue line is an ROC’ curve, which is the ROC curve with a flipped y-axis. The hypothesis test gets easier as we move South-West.This figure shows the same information as the previous figure. Importantly, the hypothesis test is easier the closer the blue &lt;code&gt;ROC&lt;/code&gt; curve follows the two axes— in other words, the more convex the curve is.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacy-puts-constraints-on-the-best-possible-roc-curve&quot;&gt;Differential privacy puts constraints on the best possible ROC curve**&lt;/h3&gt;
&lt;p&gt;Next, &lt;a href=&quot;https://arxiv.org/abs/1311.0776&quot;&gt;Kairouz et al (2015)&lt;/a&gt; show that if an algorithm satisfies &lt;code&gt;(epsilon, delta)&lt;/code&gt; differential privacy, then the adversary’s success in the hypothesis testing problem is bounded by a function of &lt;code&gt;epsilon&lt;/code&gt; and &lt;code&gt;delta&lt;/code&gt;. Specifically, this bound can be drawn in the &lt;code&gt;FPR-FNR&lt;/code&gt; space as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;540&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-281169dd.CpvFrWOn_Z2aqDrX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: The performance boundaries of a hypothesis test for two differentially private mechanisms: The blue is from a mechanism that is (epsilon1, delta) differentially private. The red is from a mechanism that is (epsilon2, delta) differentially private. The latter allows for a more convex ROC’ curve of the adversary, and therefore provides less privacy than the first mechanism.First, the blue line indicates the best possible performance any adversary can achieve in the hypothesis testing problem when the data satisfy &lt;code&gt;(epsilon1, delta)&lt;/code&gt; differential privacy. This means the &lt;code&gt;ROC&apos;&lt;/code&gt; curve from the previous figure, cannot cross the blue line — for any* adversarial decision rule. As before, the dotted line shows the performance of a decision rule that is completely random.&lt;/p&gt;
&lt;p&gt;Second, the figure illustrates that the parameter &lt;code&gt;delta&lt;/code&gt; defines the intercepts of the line on both the &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;FNR&lt;/code&gt; axes. Intuitively, &lt;code&gt;delta&lt;/code&gt; defines an area where the adversary’s trade-off is not bounded — for instance, they can lower the &lt;code&gt;FNR&lt;/code&gt; without increasing the &lt;code&gt;FPR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lastly, the figure illustrates how &lt;code&gt;epsilon&lt;/code&gt; defines the slope of the constraint. Consider two mechanisms with equal &lt;code&gt;delta&lt;/code&gt; , but varying &lt;code&gt;epsilon&lt;/code&gt;parameters — denoted &lt;code&gt;epsilon1&lt;/code&gt; and &lt;code&gt;epsilon2&lt;/code&gt; with &lt;code&gt;epsilon1 &amp;#x26;lt; epsilon2&lt;/code&gt; . Then, we see that the constraint for &lt;code&gt;epsilon2&lt;/code&gt; is closer to the origin of the diagram — showing that a higher &lt;code&gt;epsilon&lt;/code&gt; means lower privacy and an easier business for an adversary to make inferences about the underlying data.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-learn&quot;&gt;What do we learn?&lt;/h2&gt;
&lt;p&gt;Starting from the ROC curve in machine learning, we saw how differential privacy restricts the success of an adversary trying to infer whether a certain record was part of a differentially private data release.&lt;/p&gt;
&lt;p&gt;In the next post, we will see how these insights lead to the notions of functional and Gaussian differential privacy, which are more handy to work with for certain analyses of privacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</description><pubDate>Tue, 17 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Using statistics to think like a hacker, so we can avoid them!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;348&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-597dd224.B0jnjMFF_1md9I8.webp&quot; srcset=&quot;&quot;&gt;
Image from page 182 of “Elements of statistics” (1954). Licensed under creative commons.This post is the second in a series on evaluating privacy in machine learning models (see first episode &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;here&lt;/a&gt;). It explains the hypothesis testing interpretation of differential privacy by showing how differential privacy constrains the success of any attacker in finding out about the underlying data.&lt;/p&gt;
&lt;p&gt;The post assumes readers are familiar with differential privacy and some concepts in statistics and machine learning. In addition, it keeps concepts such as an “input database” and a “data release” abstract. If you are unfamiliar with either of these terms, you can have a look at the &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;previous post&lt;/a&gt;. It introduces differential privacy and has a specific example for an input database and a data release.&lt;/p&gt;
&lt;h2 id=&quot;differential-privacy-through-the-lens-of-hypothesis-testing&quot;&gt;Differential privacy through the lens of hypothesis testing&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://blog.esciencecenter.nl/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;first blog post&lt;/a&gt; of this series showed that differential privacy has adversarial thinking built-in: Leaking sensitive information may allow a malevolent actor to use the information to the disadvantage of a person in the database. In a differentially private mechanism, the more noise is added, the less any adversary can learn about any particular record in the database.&lt;/p&gt;
&lt;h3 id=&quot;adversarial-inference-as-a-hypothesis-test&quot;&gt;Adversarial inference as a hypothesis test&lt;/h3&gt;
&lt;p&gt;This intuition was formalized by &lt;a href=&quot;https://arxiv.org/abs/0811.2501&quot;&gt;Wasserman &amp;#x26; Zou (2009)&lt;/a&gt;. Imagine an adversary has access to a differentially private data release &lt;code&gt;Y&lt;/code&gt; from a tabular database &lt;code&gt;db&lt;/code&gt;. And suppose the adversary wants to find out if a particular person &lt;code&gt;i&lt;/code&gt; was part of the database &lt;code&gt;db&lt;/code&gt;. Define the neighboring databases &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt;, where &lt;code&gt;i&lt;/code&gt; is only in &lt;code&gt;db1&lt;/code&gt; but not in &lt;code&gt;db0&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Then, the adversary faces the following hypothesis testing problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;H0: &lt;code&gt;Y&lt;/code&gt; was drawn from &lt;code&gt;db0&lt;/code&gt;, so that &lt;code&gt;i&lt;/code&gt; was not in the input data for &lt;code&gt;Y&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;H1: &lt;code&gt;Y&lt;/code&gt; was drawn from &lt;code&gt;db1&lt;/code&gt;, so that &lt;code&gt;i&lt;/code&gt; was in the input data for &lt;code&gt;Y&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When seeing the data, the adversary needs to make an inference about the true state of &lt;code&gt;db&lt;/code&gt; , having seen only &lt;code&gt;Y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are four possible scenarios.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The adversary correctly predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db0&lt;/code&gt;. This is a true negative.&lt;/li&gt;
&lt;li&gt;The adversary correctly predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db1&lt;/code&gt;. This is a true positive.&lt;/li&gt;
&lt;li&gt;The adversary predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db0&lt;/code&gt;, but in truth it was based on &lt;code&gt;db1&lt;/code&gt;. This is a false negative.&lt;/li&gt;
&lt;li&gt;The adversary predicts that &lt;code&gt;Y&lt;/code&gt; was based on &lt;code&gt;db1&lt;/code&gt;, but in truth it was based on &lt;code&gt;db0&lt;/code&gt;. This is a false positive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deriving-the-roc-curve&quot;&gt;Deriving the ROC curve&lt;/h3&gt;
&lt;p&gt;How does the adversary make their inference? They need a decision rule that takes the observed data &lt;code&gt;Y&lt;/code&gt; and returns an output that is &lt;code&gt;db0&lt;/code&gt; or &lt;code&gt;db1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In a future blog post, we will be more specific on what such a rule can look like and how one can derive it. For now, we assume the adversary has the following decision rule: First, they have a trained logistic regression model that takes &lt;code&gt;Y&lt;/code&gt; as input and returns a score. Second, the adversary decides on a threshold: if the score is above the threshold, the decision rule returns &lt;code&gt;db1&lt;/code&gt;, and &lt;code&gt;db0&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;p&gt;In other words, the adversary rejects H0 in favor of H1 if the score is above the threshold. Then, lowering the threshold means rejecting H0 more often, and so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The adversary is more likely to detect cases when &lt;code&gt;Y&lt;/code&gt; is based on &lt;code&gt;db1&lt;/code&gt;. This means a higher true positive rate, which is good for the adversary.&lt;/li&gt;
&lt;li&gt;But the adversary is also more likely to predict that &lt;code&gt;Y&lt;/code&gt; is based on &lt;code&gt;db1&lt;/code&gt; when in truth it is based on &lt;code&gt;db0&lt;/code&gt;. This means a higher false positive rate, which is bad for the adversary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can visualize this trade-off with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Receiver_operating_characteristic&quot;&gt;Receiver Operating Characteristic curve&lt;/a&gt;, or ROC curve:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;537&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-921b027b.XiBibI1p_ZysgiE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: The blue line is an ROC curve. The distinguishing between H0 and H1 becomes easier as the True Positive Rate increases and the False Positive Rate decreases, thus moving North-West n the figure.In the figure above, the blue line defines the trade-off between the False Positive Rate &lt;code&gt;FPR&lt;/code&gt; and the True Positive Rate &lt;code&gt;TPR&lt;/code&gt; for a given prediction model. Lowering the &lt;code&gt;FPR&lt;/code&gt; comes at the cost of a lower &lt;code&gt;TPR&lt;/code&gt;, and vice-versa.&lt;/p&gt;
&lt;p&gt;Moreover, the red arrow indicates the direction in which it becomes easier to distinguish between H0 and H1, meaning a lower &lt;code&gt;FPR&lt;/code&gt; and a higher &lt;code&gt;TPR&lt;/code&gt;: An ideal decision rule gives an &lt;code&gt;FPR&lt;/code&gt; of 0 and a &lt;code&gt;TPR&lt;/code&gt; of 1. On the other hand, the dotted line indicates the performance of a decision rule that randomly rejects or does not reject H0.&lt;/p&gt;
&lt;p&gt;The ROC curve is a standard tool in machine learning for binary classification — and from here it is only a few steps to visualizing how differential privacy restricts the amount of information an adversary can learn from a data release.&lt;/p&gt;
&lt;h3 id=&quot;flipping-the-roc-curve&quot;&gt;Flipping the ROC curve&lt;/h3&gt;
&lt;p&gt;To start, let’s flip the y-axis in the above figure, and recognize that &lt;code&gt;1-TPR&lt;/code&gt; is the False Negative Rate &lt;code&gt;FNR&lt;/code&gt;. Thus, we have a curve in the &lt;code&gt;FPR-FNR&lt;/code&gt; space:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;568&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-57b92446.C8NgN7dQ_ZPkyQT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: The blue line is an ROC’ curve, which is the ROC curve with a flipped y-axis. The hypothesis test gets easier as we move South-West.This figure shows the same information as the previous figure. Importantly, the hypothesis test is easier the closer the blue &lt;code&gt;ROC&lt;/code&gt; curve follows the two axes— in other words, the more convex the curve is.&lt;/p&gt;
&lt;h3 id=&quot;differential-privacy-puts-constraints-on-the-best-possible-roc-curve&quot;&gt;Differential privacy puts constraints on the best possible ROC curve**&lt;/h3&gt;
&lt;p&gt;Next, &lt;a href=&quot;https://arxiv.org/abs/1311.0776&quot;&gt;Kairouz et al (2015)&lt;/a&gt; show that if an algorithm satisfies &lt;code&gt;(epsilon, delta)&lt;/code&gt; differential privacy, then the adversary’s success in the hypothesis testing problem is bounded by a function of &lt;code&gt;epsilon&lt;/code&gt; and &lt;code&gt;delta&lt;/code&gt;. Specifically, this bound can be drawn in the &lt;code&gt;FPR-FNR&lt;/code&gt; space as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning II: Hypothesis testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;540&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-281169dd.CpvFrWOn_Z2aqDrX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: The performance boundaries of a hypothesis test for two differentially private mechanisms: The blue is from a mechanism that is (epsilon1, delta) differentially private. The red is from a mechanism that is (epsilon2, delta) differentially private. The latter allows for a more convex ROC’ curve of the adversary, and therefore provides less privacy than the first mechanism.First, the blue line indicates the best possible performance any adversary can achieve in the hypothesis testing problem when the data satisfy &lt;code&gt;(epsilon1, delta)&lt;/code&gt; differential privacy. This means the &lt;code&gt;ROC&apos;&lt;/code&gt; curve from the previous figure, cannot cross the blue line — for any* adversarial decision rule. As before, the dotted line shows the performance of a decision rule that is completely random.&lt;/p&gt;
&lt;p&gt;Second, the figure illustrates that the parameter &lt;code&gt;delta&lt;/code&gt; defines the intercepts of the line on both the &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;FNR&lt;/code&gt; axes. Intuitively, &lt;code&gt;delta&lt;/code&gt; defines an area where the adversary’s trade-off is not bounded — for instance, they can lower the &lt;code&gt;FNR&lt;/code&gt; without increasing the &lt;code&gt;FPR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lastly, the figure illustrates how &lt;code&gt;epsilon&lt;/code&gt; defines the slope of the constraint. Consider two mechanisms with equal &lt;code&gt;delta&lt;/code&gt; , but varying &lt;code&gt;epsilon&lt;/code&gt;parameters — denoted &lt;code&gt;epsilon1&lt;/code&gt; and &lt;code&gt;epsilon2&lt;/code&gt; with &lt;code&gt;epsilon1 &amp;#x26;lt; epsilon2&lt;/code&gt; . Then, we see that the constraint for &lt;code&gt;epsilon2&lt;/code&gt; is closer to the origin of the diagram — showing that a higher &lt;code&gt;epsilon&lt;/code&gt; means lower privacy and an easier business for an adversary to make inferences about the underlying data.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-learn&quot;&gt;What do we learn?&lt;/h2&gt;
&lt;p&gt;Starting from the ROC curve in machine learning, we saw how differential privacy restricts the success of an adversary trying to infer whether a certain record was part of a differentially private data release.&lt;/p&gt;
&lt;p&gt;In the next post, we will see how these insights lead to the notions of functional and Gaussian differential privacy, which are more handy to work with for certain analyses of privacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-921b027b.XiBibI1p.jpeg" medium="image"/><author>Flavio Hafner</author></item><item><title>Empirically evaluating privacy in machine learning III: functional &amp;amp; gaussian differential privacy</title><link>https://blog.esciencecenter.nl/posts/2025-06-17---empirically-evaluating-privacy-in-machine-learning-iii-funct</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-06-17---empirically-evaluating-privacy-in-machine-learning-iii-funct</guid><description>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;Using statistics to think like a hacker, so we can avoid them!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;204&quot; height=&quot;300&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6832bdd1.GsqkO5bw_TCw62.webp&quot; srcset=&quot;&quot;&gt;
The Greek letter lambda, symbol of functional programming.This post is the third in a series on differential privacy and machine learning (see here episodes &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;I&lt;/a&gt; and &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;II&lt;/a&gt;). It takes a big step towards understanding how to assess privacy properties of machine learning algorithms: It introduces functional and gaussian differential privacy as defined by &lt;a href=&quot;https://academic.oup.com/jrsssb/article/84/1/3/7056089&quot;&gt;Dong et al. (2022)&lt;/a&gt;. This definition helps reasoning about differential privacy in some contexts, and in particular it has been useful for recent work in auditing machine learning algorithms with differential privacy.&lt;/p&gt;
&lt;p&gt;When reading this post, the reader should be familiar with &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;the previous post&lt;/a&gt; in this series. That post showed that differential privacy constrains the success of an attacker in inferring whether a particular record was included in a differentially private data release.&lt;/p&gt;
&lt;h2 id=&quot;functional-differential-privacy&quot;&gt;Functional Differential Privacy&lt;/h2&gt;
&lt;h3 id=&quot;trade-off-functions&quot;&gt;Trade-off functions&lt;/h3&gt;
&lt;p&gt;So far, we have derived the boundary for the best possible performance of any adversary in the original case of &lt;code&gt;(epsilon,delta)&lt;/code&gt; differential privacy. It turns out this function is an instance of what Dong et al. (2022) define as a &lt;em&gt;trade-off function.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Remember that a differentially private mechanism &lt;code&gt;M&lt;/code&gt; induces two different distributions of data under the two competing hypotheses H0 and H1. A trade-off function &lt;code&gt;T(P,Q)(alpha)&lt;/code&gt; defines the difficulty in distinguishing the two distributions: it is defined over any two probability distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;, and tells us the lowest achievable type-II error rate &lt;code&gt;beta&lt;/code&gt; (= False Negative Rate &lt;code&gt;FNR&lt;/code&gt;) an adversary can achieve with a type-I error rate (= False Positive Rate &lt;code&gt;FPR&lt;/code&gt;) of at most &lt;code&gt;alpha&lt;/code&gt;. The higher this function, the higher the lowest achievable type-II error rate for any &lt;code&gt;alpha&lt;/code&gt;, thus the harder it is to distinguish the two distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As a concrete example, a trade-off function &lt;code&gt;TP(P,Q)(0.05)=0.1&lt;/code&gt; tells us that distinguishing &lt;code&gt;P&lt;/code&gt; from &lt;code&gt;Q&lt;/code&gt; with a type-I error of at most 0.05 cannot have a type-II error of less than 0.1.&lt;/p&gt;
&lt;p&gt;A trade-off function has the following mathematical properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It takes inputs &lt;code&gt;alpha&lt;/code&gt; that range from 0 to 1.&lt;/li&gt;
&lt;li&gt;It has domain &lt;code&gt;beta&lt;/code&gt; that range from 0 to 1.&lt;/li&gt;
&lt;li&gt;It is convex, continuous, non-increasing.&lt;/li&gt;
&lt;li&gt;For all &lt;code&gt;alpha&lt;/code&gt;, &lt;code&gt;beta&lt;/code&gt; lies on or below the line &lt;code&gt;1-alpha&lt;/code&gt;. The dotted line in figure 2 of &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;the previous blog post&lt;/a&gt; represents the line &lt;code&gt;1-alpha&lt;/code&gt; , indicating that the distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt; are indistinguishable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;functional-differential-privacy-1&quot;&gt;Functional Differential Privacy&lt;/h3&gt;
&lt;p&gt;Instead with parameters &lt;code&gt;(epsilon, delta)&lt;/code&gt;, it is now possible to define differential privacy in terms of a function — and is thus called functional differential privacy.&lt;/p&gt;
&lt;p&gt;According to the definition, a mechanism &lt;code&gt;M&lt;/code&gt; is &lt;code&gt;f&lt;/code&gt;-differentially private if it creates, for all neighboring databases &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt;, a trade-off function over &lt;code&gt;M(db0)&lt;/code&gt; and &lt;code&gt;M(db1)&lt;/code&gt; that is bounded by the trade-off function &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The definition is best illustrated with this figure from Dong et al (2022):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;361&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-741bba85.Djav_Y5I_Z13jbdU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Functional differential privacy. The solid line is a trade-off function for &lt;code&gt;f&lt;/code&gt; differential privacy. Only the dashed line above the solid line satisfies f-differential privacy. Source: Dong et al (2022).The figure has the same x- and y-axes as the figures in the previous blog post: On the x-axis is the false positive rate, or type I error; on the y-axis is the false negative rate, or type II error.&lt;/p&gt;
&lt;p&gt;The solid line is the trade-off function &lt;code&gt;f&lt;/code&gt;. The other lines represent trade-off functions from differentially private mechanisms. Among them, only the dashed line that never crosses the solid line is &lt;code&gt;f&lt;/code&gt;-DP; the other lines do not always lie above the line defined by &lt;code&gt;f&lt;/code&gt;, and thus do not satisfy &lt;code&gt;f&lt;/code&gt;-differential privacy. For reference, the kinked line could have come from an &lt;code&gt;(epsilon, delta)&lt;/code&gt; -differentially private mechanism we discussed in the previous post.&lt;/p&gt;
&lt;h3 id=&quot;analyzing-composition&quot;&gt;Analyzing composition&lt;/h3&gt;
&lt;p&gt;A first advantage of functional differential privacy is that it makes it easier to analyze properties such as composition. Composition handles the question of how sequentially querying a dataset with a private mechanism impacts the overall privacy of the original dataset, after all queries are applied. As an example, take an analyst that sequentially queries a private dataset: they query the data with a private mechanism, explore the result, and query the data in a way that depends on the result of the first query. The question arises: how does this sequential and adaptive querying of the data degrade overall privacy? If the person is adversarial, they may try to refine the queries step by step until they found the answer to their question.&lt;/p&gt;
&lt;p&gt;A key result in Dong et al (2022) is that the &lt;code&gt;n&lt;/code&gt;-fold composition of mechanisms that are &lt;code&gt;f_i&lt;/code&gt; differentially private is &lt;code&gt;f*&lt;/code&gt; -differentially private. The precise level of privacy &lt;code&gt;f*&lt;/code&gt; depends on the privacy of each individual mechanism &lt;code&gt;f_i&lt;/code&gt;, and details can be found in section 3 of the paper. Importantly, this privacy bound is &lt;em&gt;tight&lt;/em&gt;: &lt;code&gt;f*&lt;/code&gt; is the most precise bound possible, informally meaning that we cannot move the function &lt;code&gt;f*&lt;/code&gt; further away from the x-y origin without making the &lt;code&gt;f*&lt;/code&gt; function crossing the trade-off function of the composed mechanism.&lt;/p&gt;
&lt;p&gt;This contrasts with &lt;code&gt;(epsilon,delta)&lt;/code&gt; differential privacy, where composition cannot be bounded as tightly.&lt;/p&gt;
&lt;h2 id=&quot;gaussian-differential-privacy&quot;&gt;Gaussian differential privacy&lt;/h2&gt;
&lt;p&gt;A special case of &lt;code&gt;f&lt;/code&gt;-differential privacy is Gaussian differential privacy. In this definition, the trade-off function is defined over two unit-variance normal distributions — one with mean 0, the other with mean &lt;code&gt;mu&lt;/code&gt;. In other words, under H0, the private mechanism generates a standard normal distribution, and under H1, it generates a normal distribution with mean &lt;code&gt;mu&lt;/code&gt; and variance 1. This is shown in the following figure:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;342&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-4c7801e8.BaRsgnrn_1ojanv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Two normal distributions. Under H0, X is generated with mean 0 and standard deviation 1. Under H1, X is generated with mean mu and standard deviation 1.While this definition makes assumptions about the functional form of the distribution, it is very useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It summarizes the adversary’s trade-off between false positives and false negatives with a single parameter, &lt;code&gt;mu&lt;/code&gt;. This makes it easy to describe and interpret privacy guarantees.&lt;/li&gt;
&lt;li&gt;It characterizes the &lt;a href=&quot;https://en.wikipedia.org/wiki/Additive_noise_differential_privacy_mechanisms&quot;&gt;Gaussian mechanism&lt;/a&gt;, one commonly used differentially private mechanism.&lt;/li&gt;
&lt;li&gt;As shown by Dong et al (2022), Gaussian differential privacy is the asymptotic limit when &lt;code&gt;f&lt;/code&gt;-differentially private mechanisms are applied repeatedly on the same dataset. This is useful for analyzing complex algorithms that consist of multiple, adaptive and individually private steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;relation-to-machine-learning-with-differential-privacy&quot;&gt;Relation to machine learning with differential privacy&lt;/h3&gt;
&lt;p&gt;It is this last result that has made Gaussian differential privacy an important tool for analyzing differentially private machine learning.&lt;/p&gt;
&lt;p&gt;While we discuss it in detail in a future blog post, a commonly-used algorithm in deep learning is Differentially Private Stochastic Gradient Descent (DP-SGD). It is a method for sequentially updating parameters in a complex neural network: Instead of directly updating parameters with the gradients in each batch, noise is added and the contribution of individual samples in the batch is constrained. This avoids that any individual sample contributes too much to the parameter update, and can be shown to satisfy differential privacy.&lt;/p&gt;
&lt;p&gt;Since each parameter update is differentially private, one can view the trained model that results after many iterations as an algorithm that composes multiple differentially-private queries on the training data. Therefore, one can use Gaussian differential privacy to derive tight privacy bounds of the DP-SGD algorithm, which was not possible before.&lt;/p&gt;
&lt;h3 id=&quot;trade-off-function-for-gaussian-differential-privacy&quot;&gt;Trade-off function for Gaussian differential privacy&lt;/h3&gt;
&lt;p&gt;Building on the previous figure, the following figure illustrates the trade-off between false positives and false negatives under Gaussian differential privacy.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;485&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-5f7a6d2f.Cp7wH9vX_1lELbs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: The likelihood-ratio test with normal distributions. If &lt;code&gt;X&lt;/code&gt; is higher than t, H0 is rejected in favor of H1, and vice-versa. The blue and green areas show the false positive and false negative rates, respectively.*The red line indicates a decision threshold. In particular, when conducting a hypothesis test, the [Neyman-Pearson lemma](&lt;a href=&quot;https://en.wikipedia.org/wiki/Neyman%E2%80%93&quot;&gt;https://en.wikipedia.org/wiki/Neyman%E2%80%93&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pearson_lemma) says that the best test statistic is the likelihood ratio test: Given a sample &lt;code&gt;X&lt;/code&gt;, the likelihood ratio test compares the likelihood that the sample was generated under H1 vs H0. From the figure above, we see that because the likelihood ratio of H1 vs H0 is increasing in &lt;code&gt;X&lt;/code&gt;, the null hypothesis is rejected if &lt;code&gt;X&lt;/code&gt; is above some threshold &lt;code&gt;t&lt;/code&gt;, indicated in red.&lt;/p&gt;
&lt;p&gt;Given the decision threshold, we can derive the False Positive and the False Negative rates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The False Positive Rate is defined for cases when H0 is falsely rejected. This happens if &lt;code&gt;X&amp;#x26;gt;t&lt;/code&gt; but &lt;code&gt;X&lt;/code&gt; was generated under H0. This probability is shown by the blue area.&lt;/li&gt;
&lt;li&gt;The False Negative Rate is defined for cases when H0 is falsely not rejected. This happens if &lt;code&gt;X&amp;#x26;lt;t&lt;/code&gt; but &lt;code&gt;X&lt;/code&gt; was generated under H1. This probability is shown by the green area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have an analytical expression for both &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;FNR&lt;/code&gt;, we can derive the trade-off function — the &lt;code&gt;FNR&lt;/code&gt; as a function of the &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;mu&lt;/code&gt;: We rearrange the equation for the &lt;code&gt;FPR&lt;/code&gt; for &lt;code&gt;t&lt;/code&gt; and then plug in &lt;code&gt;t&lt;/code&gt; to the equation for &lt;code&gt;FNR&lt;/code&gt;. This yields the following trade-off function:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;474&quot; height=&quot;81&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6e7a313f.C4N7fx_t_ZOLAMu.webp&quot; srcset=&quot;&quot;&gt;
Again, an illustration makes this easier to understand:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-f52a391d.BgttE1A6_Z2pT1W1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: The trade-off function for Gaussian differential privacy. Phi is the standard normal distribution. alpha is the false positive rate. beta is the false negative rate. a lower mu means more privacy.First, for a given false positive rate &lt;code&gt;alpha&lt;/code&gt;, the false negative rate is at least as large as the the green area. In line with the definition of a trade-off function, lowering the false positive rate makes the red area smaller, and pulls the boundary of the green area to the right, thus increasing the false negative rate.&lt;/p&gt;
&lt;p&gt;Second, a lower &lt;code&gt;mu&lt;/code&gt; is associated with more privacy: as &lt;code&gt;mu&lt;/code&gt; decreases, it pulls the boundaries either the false positive or false negative rate (or both) closer to the center, thereby making it harder to distinguish between the distributions generated by H0 and H1.&lt;/p&gt;
&lt;p&gt;Dong et al (2022) also illustrate the trade-off function for some values of &lt;code&gt;mu&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;390&quot; height=&quot;383&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-7dce8395.CfSk5ZTr_22BloS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Example trade-off functions for different values of mu. Source: Dong et al (2022).Here, for instance &lt;code&gt;G_{0.5}&lt;/code&gt; is the trade-off function for Gaussian differential privacy with &lt;code&gt;mu=0.5&lt;/code&gt; . Reasonable privacy is given for &lt;code&gt;mu=0.5&lt;/code&gt;, whereas for &lt;code&gt;mu=6&lt;/code&gt; the trade-off function almost coincides with the x- and y-axis, thus giving virtually no privacy.&lt;/p&gt;
&lt;h3 id=&quot;connections-between-definitions-of-privacy&quot;&gt;Connections between definitions of privacy&lt;/h3&gt;
&lt;p&gt;Another insight from Dong et al (2022) is that one can convert between&lt;code&gt;(epsilon, delta)&lt;/code&gt; -differential privacy and &lt;code&gt;f&lt;/code&gt;-differential privacy, and thus also Gaussian differential privacy. This is useful for two reasons. First, it means existing results from &lt;code&gt;(epsilon, delta)&lt;/code&gt;-differential privacy apply also to the definitions here. Second, for certain analyses, it is more convenient to work with one definition than the other, but results derived from one hold for the other. For instance, one can analyze composition more easily with &lt;code&gt;f&lt;/code&gt;-differential privacy, but analyze the privacy properties of mechanisms with data sub-sampling (discussed in the paper) more easily with &lt;code&gt;(epsilon,delta)&lt;/code&gt;-differential privacy.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We saw that the hypothesis testing interpretation gives rise to new notions of privacy such as &lt;code&gt;f&lt;/code&gt;- and Gaussian differential privacy, which are more handy to work with for certain analyses of privacy.&lt;/p&gt;
&lt;p&gt;We now have the foundations to understand privacy testing in machine learning. Both the hypothesis testing interpretation and Gaussian differential privacy have been useful to empirically check the privacy-preserving properties of machine learning algorithms. This will be covered in a future article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</description><pubDate>Tue, 17 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;Using statistics to think like a hacker, so we can avoid them!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;204&quot; height=&quot;300&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6832bdd1.GsqkO5bw_TCw62.webp&quot; srcset=&quot;&quot;&gt;
The Greek letter lambda, symbol of functional programming.This post is the third in a series on differential privacy and machine learning (see here episodes &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-i-introduction-de5fe808d186&quot;&gt;I&lt;/a&gt; and &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;II&lt;/a&gt;). It takes a big step towards understanding how to assess privacy properties of machine learning algorithms: It introduces functional and gaussian differential privacy as defined by &lt;a href=&quot;https://academic.oup.com/jrsssb/article/84/1/3/7056089&quot;&gt;Dong et al. (2022)&lt;/a&gt;. This definition helps reasoning about differential privacy in some contexts, and in particular it has been useful for recent work in auditing machine learning algorithms with differential privacy.&lt;/p&gt;
&lt;p&gt;When reading this post, the reader should be familiar with &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;the previous post&lt;/a&gt; in this series. That post showed that differential privacy constrains the success of an attacker in inferring whether a particular record was included in a differentially private data release.&lt;/p&gt;
&lt;h2 id=&quot;functional-differential-privacy&quot;&gt;Functional Differential Privacy&lt;/h2&gt;
&lt;h3 id=&quot;trade-off-functions&quot;&gt;Trade-off functions&lt;/h3&gt;
&lt;p&gt;So far, we have derived the boundary for the best possible performance of any adversary in the original case of &lt;code&gt;(epsilon,delta)&lt;/code&gt; differential privacy. It turns out this function is an instance of what Dong et al. (2022) define as a &lt;em&gt;trade-off function.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Remember that a differentially private mechanism &lt;code&gt;M&lt;/code&gt; induces two different distributions of data under the two competing hypotheses H0 and H1. A trade-off function &lt;code&gt;T(P,Q)(alpha)&lt;/code&gt; defines the difficulty in distinguishing the two distributions: it is defined over any two probability distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;, and tells us the lowest achievable type-II error rate &lt;code&gt;beta&lt;/code&gt; (= False Negative Rate &lt;code&gt;FNR&lt;/code&gt;) an adversary can achieve with a type-I error rate (= False Positive Rate &lt;code&gt;FPR&lt;/code&gt;) of at most &lt;code&gt;alpha&lt;/code&gt;. The higher this function, the higher the lowest achievable type-II error rate for any &lt;code&gt;alpha&lt;/code&gt;, thus the harder it is to distinguish the two distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As a concrete example, a trade-off function &lt;code&gt;TP(P,Q)(0.05)=0.1&lt;/code&gt; tells us that distinguishing &lt;code&gt;P&lt;/code&gt; from &lt;code&gt;Q&lt;/code&gt; with a type-I error of at most 0.05 cannot have a type-II error of less than 0.1.&lt;/p&gt;
&lt;p&gt;A trade-off function has the following mathematical properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It takes inputs &lt;code&gt;alpha&lt;/code&gt; that range from 0 to 1.&lt;/li&gt;
&lt;li&gt;It has domain &lt;code&gt;beta&lt;/code&gt; that range from 0 to 1.&lt;/li&gt;
&lt;li&gt;It is convex, continuous, non-increasing.&lt;/li&gt;
&lt;li&gt;For all &lt;code&gt;alpha&lt;/code&gt;, &lt;code&gt;beta&lt;/code&gt; lies on or below the line &lt;code&gt;1-alpha&lt;/code&gt;. The dotted line in figure 2 of &lt;a href=&quot;https://medium.com/escience-center/empirically-evaluating-privacy-in-machine-learning-ii-hypothesis-testing-647806e2985c&quot;&gt;the previous blog post&lt;/a&gt; represents the line &lt;code&gt;1-alpha&lt;/code&gt; , indicating that the distributions &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt; are indistinguishable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;functional-differential-privacy-1&quot;&gt;Functional Differential Privacy&lt;/h3&gt;
&lt;p&gt;Instead with parameters &lt;code&gt;(epsilon, delta)&lt;/code&gt;, it is now possible to define differential privacy in terms of a function — and is thus called functional differential privacy.&lt;/p&gt;
&lt;p&gt;According to the definition, a mechanism &lt;code&gt;M&lt;/code&gt; is &lt;code&gt;f&lt;/code&gt;-differentially private if it creates, for all neighboring databases &lt;code&gt;db0&lt;/code&gt; and &lt;code&gt;db1&lt;/code&gt;, a trade-off function over &lt;code&gt;M(db0)&lt;/code&gt; and &lt;code&gt;M(db1)&lt;/code&gt; that is bounded by the trade-off function &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The definition is best illustrated with this figure from Dong et al (2022):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;361&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-741bba85.Djav_Y5I_Z13jbdU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Functional differential privacy. The solid line is a trade-off function for &lt;code&gt;f&lt;/code&gt; differential privacy. Only the dashed line above the solid line satisfies f-differential privacy. Source: Dong et al (2022).The figure has the same x- and y-axes as the figures in the previous blog post: On the x-axis is the false positive rate, or type I error; on the y-axis is the false negative rate, or type II error.&lt;/p&gt;
&lt;p&gt;The solid line is the trade-off function &lt;code&gt;f&lt;/code&gt;. The other lines represent trade-off functions from differentially private mechanisms. Among them, only the dashed line that never crosses the solid line is &lt;code&gt;f&lt;/code&gt;-DP; the other lines do not always lie above the line defined by &lt;code&gt;f&lt;/code&gt;, and thus do not satisfy &lt;code&gt;f&lt;/code&gt;-differential privacy. For reference, the kinked line could have come from an &lt;code&gt;(epsilon, delta)&lt;/code&gt; -differentially private mechanism we discussed in the previous post.&lt;/p&gt;
&lt;h3 id=&quot;analyzing-composition&quot;&gt;Analyzing composition&lt;/h3&gt;
&lt;p&gt;A first advantage of functional differential privacy is that it makes it easier to analyze properties such as composition. Composition handles the question of how sequentially querying a dataset with a private mechanism impacts the overall privacy of the original dataset, after all queries are applied. As an example, take an analyst that sequentially queries a private dataset: they query the data with a private mechanism, explore the result, and query the data in a way that depends on the result of the first query. The question arises: how does this sequential and adaptive querying of the data degrade overall privacy? If the person is adversarial, they may try to refine the queries step by step until they found the answer to their question.&lt;/p&gt;
&lt;p&gt;A key result in Dong et al (2022) is that the &lt;code&gt;n&lt;/code&gt;-fold composition of mechanisms that are &lt;code&gt;f_i&lt;/code&gt; differentially private is &lt;code&gt;f*&lt;/code&gt; -differentially private. The precise level of privacy &lt;code&gt;f*&lt;/code&gt; depends on the privacy of each individual mechanism &lt;code&gt;f_i&lt;/code&gt;, and details can be found in section 3 of the paper. Importantly, this privacy bound is &lt;em&gt;tight&lt;/em&gt;: &lt;code&gt;f*&lt;/code&gt; is the most precise bound possible, informally meaning that we cannot move the function &lt;code&gt;f*&lt;/code&gt; further away from the x-y origin without making the &lt;code&gt;f*&lt;/code&gt; function crossing the trade-off function of the composed mechanism.&lt;/p&gt;
&lt;p&gt;This contrasts with &lt;code&gt;(epsilon,delta)&lt;/code&gt; differential privacy, where composition cannot be bounded as tightly.&lt;/p&gt;
&lt;h2 id=&quot;gaussian-differential-privacy&quot;&gt;Gaussian differential privacy&lt;/h2&gt;
&lt;p&gt;A special case of &lt;code&gt;f&lt;/code&gt;-differential privacy is Gaussian differential privacy. In this definition, the trade-off function is defined over two unit-variance normal distributions — one with mean 0, the other with mean &lt;code&gt;mu&lt;/code&gt;. In other words, under H0, the private mechanism generates a standard normal distribution, and under H1, it generates a normal distribution with mean &lt;code&gt;mu&lt;/code&gt; and variance 1. This is shown in the following figure:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;342&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-4c7801e8.BaRsgnrn_1ojanv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Two normal distributions. Under H0, X is generated with mean 0 and standard deviation 1. Under H1, X is generated with mean mu and standard deviation 1.While this definition makes assumptions about the functional form of the distribution, it is very useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It summarizes the adversary’s trade-off between false positives and false negatives with a single parameter, &lt;code&gt;mu&lt;/code&gt;. This makes it easy to describe and interpret privacy guarantees.&lt;/li&gt;
&lt;li&gt;It characterizes the &lt;a href=&quot;https://en.wikipedia.org/wiki/Additive_noise_differential_privacy_mechanisms&quot;&gt;Gaussian mechanism&lt;/a&gt;, one commonly used differentially private mechanism.&lt;/li&gt;
&lt;li&gt;As shown by Dong et al (2022), Gaussian differential privacy is the asymptotic limit when &lt;code&gt;f&lt;/code&gt;-differentially private mechanisms are applied repeatedly on the same dataset. This is useful for analyzing complex algorithms that consist of multiple, adaptive and individually private steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;relation-to-machine-learning-with-differential-privacy&quot;&gt;Relation to machine learning with differential privacy&lt;/h3&gt;
&lt;p&gt;It is this last result that has made Gaussian differential privacy an important tool for analyzing differentially private machine learning.&lt;/p&gt;
&lt;p&gt;While we discuss it in detail in a future blog post, a commonly-used algorithm in deep learning is Differentially Private Stochastic Gradient Descent (DP-SGD). It is a method for sequentially updating parameters in a complex neural network: Instead of directly updating parameters with the gradients in each batch, noise is added and the contribution of individual samples in the batch is constrained. This avoids that any individual sample contributes too much to the parameter update, and can be shown to satisfy differential privacy.&lt;/p&gt;
&lt;p&gt;Since each parameter update is differentially private, one can view the trained model that results after many iterations as an algorithm that composes multiple differentially-private queries on the training data. Therefore, one can use Gaussian differential privacy to derive tight privacy bounds of the DP-SGD algorithm, which was not possible before.&lt;/p&gt;
&lt;h3 id=&quot;trade-off-function-for-gaussian-differential-privacy&quot;&gt;Trade-off function for Gaussian differential privacy&lt;/h3&gt;
&lt;p&gt;Building on the previous figure, the following figure illustrates the trade-off between false positives and false negatives under Gaussian differential privacy.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;485&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-5f7a6d2f.Cp7wH9vX_1lELbs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: The likelihood-ratio test with normal distributions. If &lt;code&gt;X&lt;/code&gt; is higher than t, H0 is rejected in favor of H1, and vice-versa. The blue and green areas show the false positive and false negative rates, respectively.*The red line indicates a decision threshold. In particular, when conducting a hypothesis test, the [Neyman-Pearson lemma](&lt;a href=&quot;https://en.wikipedia.org/wiki/Neyman%E2%80%93&quot;&gt;https://en.wikipedia.org/wiki/Neyman%E2%80%93&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pearson_lemma) says that the best test statistic is the likelihood ratio test: Given a sample &lt;code&gt;X&lt;/code&gt;, the likelihood ratio test compares the likelihood that the sample was generated under H1 vs H0. From the figure above, we see that because the likelihood ratio of H1 vs H0 is increasing in &lt;code&gt;X&lt;/code&gt;, the null hypothesis is rejected if &lt;code&gt;X&lt;/code&gt; is above some threshold &lt;code&gt;t&lt;/code&gt;, indicated in red.&lt;/p&gt;
&lt;p&gt;Given the decision threshold, we can derive the False Positive and the False Negative rates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The False Positive Rate is defined for cases when H0 is falsely rejected. This happens if &lt;code&gt;X&amp;#x26;gt;t&lt;/code&gt; but &lt;code&gt;X&lt;/code&gt; was generated under H0. This probability is shown by the blue area.&lt;/li&gt;
&lt;li&gt;The False Negative Rate is defined for cases when H0 is falsely not rejected. This happens if &lt;code&gt;X&amp;#x26;lt;t&lt;/code&gt; but &lt;code&gt;X&lt;/code&gt; was generated under H1. This probability is shown by the green area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have an analytical expression for both &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;FNR&lt;/code&gt;, we can derive the trade-off function — the &lt;code&gt;FNR&lt;/code&gt; as a function of the &lt;code&gt;FPR&lt;/code&gt; and &lt;code&gt;mu&lt;/code&gt;: We rearrange the equation for the &lt;code&gt;FPR&lt;/code&gt; for &lt;code&gt;t&lt;/code&gt; and then plug in &lt;code&gt;t&lt;/code&gt; to the equation for &lt;code&gt;FNR&lt;/code&gt;. This yields the following trade-off function:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;474&quot; height=&quot;81&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-6e7a313f.C4N7fx_t_ZOLAMu.webp&quot; srcset=&quot;&quot;&gt;
Again, an illustration makes this easier to understand:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;576&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-f52a391d.BgttE1A6_Z2pT1W1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: The trade-off function for Gaussian differential privacy. Phi is the standard normal distribution. alpha is the false positive rate. beta is the false negative rate. a lower mu means more privacy.First, for a given false positive rate &lt;code&gt;alpha&lt;/code&gt;, the false negative rate is at least as large as the the green area. In line with the definition of a trade-off function, lowering the false positive rate makes the red area smaller, and pulls the boundary of the green area to the right, thus increasing the false negative rate.&lt;/p&gt;
&lt;p&gt;Second, a lower &lt;code&gt;mu&lt;/code&gt; is associated with more privacy: as &lt;code&gt;mu&lt;/code&gt; decreases, it pulls the boundaries either the false positive or false negative rate (or both) closer to the center, thereby making it harder to distinguish between the distributions generated by H0 and H1.&lt;/p&gt;
&lt;p&gt;Dong et al (2022) also illustrate the trade-off function for some values of &lt;code&gt;mu&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empirically evaluating privacy in machine learning III: functional &amp;amp;#x26; gaussian differential privacy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;390&quot; height=&quot;383&quot; src=&quot;https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-7dce8395.CfSk5ZTr_22BloS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Example trade-off functions for different values of mu. Source: Dong et al (2022).Here, for instance &lt;code&gt;G_{0.5}&lt;/code&gt; is the trade-off function for Gaussian differential privacy with &lt;code&gt;mu=0.5&lt;/code&gt; . Reasonable privacy is given for &lt;code&gt;mu=0.5&lt;/code&gt;, whereas for &lt;code&gt;mu=6&lt;/code&gt; the trade-off function almost coincides with the x- and y-axis, thus giving virtually no privacy.&lt;/p&gt;
&lt;h3 id=&quot;connections-between-definitions-of-privacy&quot;&gt;Connections between definitions of privacy&lt;/h3&gt;
&lt;p&gt;Another insight from Dong et al (2022) is that one can convert between&lt;code&gt;(epsilon, delta)&lt;/code&gt; -differential privacy and &lt;code&gt;f&lt;/code&gt;-differential privacy, and thus also Gaussian differential privacy. This is useful for two reasons. First, it means existing results from &lt;code&gt;(epsilon, delta)&lt;/code&gt;-differential privacy apply also to the definitions here. Second, for certain analyses, it is more convenient to work with one definition than the other, but results derived from one hold for the other. For instance, one can analyze composition more easily with &lt;code&gt;f&lt;/code&gt;-differential privacy, but analyze the privacy properties of mechanisms with data sub-sampling (discussed in the paper) more easily with &lt;code&gt;(epsilon,delta)&lt;/code&gt;-differential privacy.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We saw that the hypothesis testing interpretation gives rise to new notions of privacy such as &lt;code&gt;f&lt;/code&gt;- and Gaussian differential privacy, which are more handy to work with for certain analyses of privacy.&lt;/p&gt;
&lt;p&gt;We now have the foundations to understand privacy testing in machine learning. Both the hypothesis testing interpretation and Gaussian differential privacy have been useful to empirically check the privacy-preserving properties of machine learning algorithms. This will be covered in a future article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Kody Moodley, Erik Tjong Kim Sang and Lourens Veen for commenting on and discussing an earlier draft.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/empirically-evaluating-privacy-in-machin-741bba85.Djav_Y5I.png" medium="image"/><author>Flavio Hafner</author></item><item><title>Scientific Community Building through Workshops: the NPLinker eScience experience</title><link>https://blog.esciencecenter.nl/posts/2025-05-20---scientific-community-building-through-workshops-the-nplinker</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-05-20---scientific-community-building-through-workshops-the-nplinker</guid><description>&lt;p&gt;&lt;em&gt;This blog post is written by Wageningen University &amp;#x26; Research Assistant Professor &lt;em&gt;&lt;a href=&quot;https://www.linkedin.com/in/jjjvanderhooft/&quot;&gt;&lt;em&gt;Justin van der Hooft&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, who participates in the Open eScience Call 2021. His project “A community-supported workflow connecting microbial genes and organisms to their molecular products” aims to facilitate the finding of novel bio-active molecules from nature. It does so by enabling the integrated use of various omics data types.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to know more of what Justin’s team is doing?! Check his team’s &lt;em&gt;&lt;a href=&quot;https://vdhooftcompmet.github.io/&quot;&gt;&lt;em&gt;website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-0741307b.Cd4Yi41s_Z2tvJya.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@vollkornapfel?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Adrian Lange&lt;/a&gt; on [Unsplash](&lt;a href=&quot;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&quot;&gt;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Text)&lt;/p&gt;
&lt;p&gt;Motivation for the workshop**&lt;/p&gt;
&lt;p&gt;Nature is still full of unknown chemistry with possible beneficial properties such as anti-inflammatory or antibiotic ones. Over the last decade, increasing numbers of genome sequences and metabolomics profiles have become available in public resources. Hence, the combination of genome mining and metabolome mining has gained traction in accelerating natural product discovery by linking biosynthetic genes to molecular scaffolds and structures, and associating producers with their products. However, effective integrative omics mining has proven challenging due to the various data types and tools involved. In 2021, &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008920&quot;&gt;NPLinker&lt;/a&gt; was proposed as a solution to streamline many aspects of integrative omics, so that researchers can focus on analyzing the possible matches between genes and molecules. Over the last years, the Open eScience Call project has further build on this solution to create &lt;a href=&quot;https://research-software-directory.org/software/nplinker&quot;&gt;a framework for paired omics analyses&lt;/a&gt;. To gain experience with the NPLinker framework and build an integrative omics mining community of talented, driven early-career researchers and knowledgeable instructors, Marnix Medema and I organized this second NPLinker-eScience workshop in Wageningen, the Netherlands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outline of the workshop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During this second workshop in a series of two, we again aimed to bring together researchers interested in integrative omics analysis, spanning various career stages, computational or the application-focused backgrounds, and diverse organisms they work on. Following a selection process, 38 participants were selected to come to Wageningen to learn about analyzing genomes and metabolomes, and to get an outlook towards the integration of the two. The general aims of &lt;a href=&quot;https://www.wur.nl/en/research-results/chair-groups/plant-sciences/bioinformatics/teaching/nplinker_workshop.htm&quot;&gt;the workshop&lt;/a&gt; were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce the NPLinker framework both conceptually and hands-on&lt;/li&gt;
&lt;li&gt;Educate and train natural product researchers and other interested scientists&lt;/li&gt;
&lt;li&gt;Extend the Integrative Omics Mining Community&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The workshop intended learning outcomes were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand the concepts of and motivations for paired omics analysis&lt;/li&gt;
&lt;li&gt;Apply NPLinker to a public paired omics dataset&lt;/li&gt;
&lt;li&gt;Understand the NPLinker scoring&lt;/li&gt;
&lt;li&gt;Evaluate NPLinker outcome in the web app&lt;/li&gt;
&lt;li&gt;Understand how to contribute to the NPLinker code base&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To stimulate networking amongst the participants and instructors, several measures were put in place: extended coffee and tea breaks, the opportunity to present a poster, and a social mixer at the start to get to know each other. Furthermore, Marnix and I organized a symposium on Wednesday to highlight exciting developments in genome mining, metabolome mining, integrative omics mining, and the reuse of public omics data. We are grateful for the financial support from the eScience Center, which helped to make the workshop affordable for participants from across the globe through a travel reimbursement scheme and enabled the participation of three international instructors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;669&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-0bf0eb4f.CUwTRxyS_Z85FHB.webp&quot; srcset=&quot;&quot;&gt;
All 38 participants from across the globe together with the instructors in front of the &lt;a href=&quot;https://www.wur.nl/en/location/omnia-2.htm&quot;&gt;Omnia building&lt;/a&gt; at the &lt;a href=&quot;https://www.wur.nl/en.htm&quot;&gt;Wageningen University &amp;#x26; Research&lt;/a&gt; campus.&lt;/p&gt;
&lt;p&gt;I am increasingly aware of how integrative omics mining brings together different disciplines — what’s in a name, one could say. Furthermore, the field connects both researchers using the omics tools and developers working on them. We intentionally invited participants from these two groups and various disciplines to foster connections and collectively gain experience with the latest developments in the field. One key insight is that the fields is moving rapidly: only two years ago, we explained the latest in genome mining and metabolome mining, and during this workshop, versions 2 of BiG-SCAPE and GNPS were on the menu, replacing the previous versions. From a user perspective, this means staying up-to-date with how to use these tools effectively is key to remain on top of the latest possibilities in omics mining. From a developer perspective, it is important to build integrative tools like NPLinker in a way that can keep pace with the fast-evolving omics landscape. Another key insight is that, given the diverse backgrounds of participants, it is challenging to fully cater everyone’s needs. Striking the right balance between fixed program components and more flexible ones may help–allowing the explanation and demonstration of concepts or tools to be targeted based on participants’ needs. A final key insight is that promoting the exchange of knowledge and expertise in between participants is crucial, as it accelerates the uptake of new skills and information and helps form the bonds that create a scientific community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;679&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-ef101463.nn9ZIVYM_nutVJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;677&quot; height=&quot;510&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-fe492552.DR1a_7tq_2uqmG7.webp&quot; srcset=&quot;&quot;&gt;
Participants have been working hands-on with BiG-SCAPE, GNPS, and NPLinker during the workshop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open Access Materials&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A tangible outcome of the workshop for the broader community is that the instructors all made as much as possible &lt;a href=&quot;https://doi.org/10.5281/zenodo.15281967&quot;&gt;the materials available under an open access license&lt;/a&gt;! I hope this initiative will help to further foster the teaching of the future generation of omics miners, support the development of educational resources for genome mining, metabolomics, and metabolome mining, and promote discussions and integration between the fields of genome mining and metabolome mining.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-a548f678.DscDT-pC_Z1pHYGC.webp&quot; srcset=&quot;&quot;&gt;
With huge thanks to all the NPLinker eScience Workshop instructors who came from across the globe to Wageningen to teach the participants many facets of integrative omics mining.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personal reflection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Altogether, I am happy that all participants and instructors enjoyed the workshop and gained something valuable from it. I am very pleased that everyone had a good time and that the location and catering was appreciated. Furthermore, it was great to organize the symposium with Marnix Medema that celebrated the work lustra of our teams in computational genomics (1o years) and metabolomics (5 years). Not only did we invite keynote speakers–Pieter Dorrestein, Tilmann Weber, and Margherita Sosio–but we also invited three workshop participants to showcase their work in a flash talk. In case you are curious, you can watch it back &lt;a href=&quot;https://wur.yuja.com/V/Video?v=885970&amp;#x26;node=4776818&amp;#x26;a=66183860&quot;&gt;here&lt;/a&gt;. I found it nice to read in the evaluations how the participants liked to see each others’ posters during the breaks, and how they liked the flash talks during the symposium.&lt;/p&gt;
&lt;p&gt;If there is one thing I would have changed looking back at the event, it would be to organize more structured parallel sessions to dive deeper into the application and development of NPLinker, for example by using two separate rooms and dividing participants and instructors accordingly. This would have allowed both groups (users and developers) to discuss their ideas and challenges in greater detail, without the feeling of disturbing each other.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-22f93410.DbJUW8l-_ZDPVU9.webp&quot; srcset=&quot;&quot;&gt;
Community building during the workshop dinner!&lt;/p&gt;
&lt;p&gt;What I really liked were the workshop keynotes–thanks again to Kate Duncan for setting the scene on Monday, to Margherita Sosio for showcasing how omics mining is applied in an industrial setting and how the Molecules Gateway operates, and to Kumar Saurabh Singh for sharing his perspective on multi-omics analyses. Further, thanks again to the eScience Center for supporting this workshop series, and to the Omnia and Orion teams for their support and efforts before and during the week. A big thank-you as well to Maria Augustijn and Marie-José van Iersel for their support in organizing various aspects of the workshop and symposium. Thanks to Marnix for your support and being co-organizer of this event. And finally, many thanks to all the participants for their open and constructive attitude during the workshop — much appreciated!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-a3b95cc3.C5BiktrF_ZyC2x6.webp&quot; srcset=&quot;&quot;&gt;
Marnix Medema (right) and myself (left) during the symposium we organized.&lt;/p&gt;
&lt;p&gt;Whilst this was the last workshop in a series of two, I hope to see the integrative omics community together on future occasions!&lt;/p&gt;</description><pubDate>Tue, 20 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog post is written by Wageningen University &amp;#x26; Research Assistant Professor &lt;em&gt;&lt;a href=&quot;https://www.linkedin.com/in/jjjvanderhooft/&quot;&gt;&lt;em&gt;Justin van der Hooft&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, who participates in the Open eScience Call 2021. His project “A community-supported workflow connecting microbial genes and organisms to their molecular products” aims to facilitate the finding of novel bio-active molecules from nature. It does so by enabling the integrated use of various omics data types.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to know more of what Justin’s team is doing?! Check his team’s &lt;em&gt;&lt;a href=&quot;https://vdhooftcompmet.github.io/&quot;&gt;&lt;em&gt;website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-0741307b.Cd4Yi41s_Z2tvJya.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@vollkornapfel?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Adrian Lange&lt;/a&gt; on [Unsplash](&lt;a href=&quot;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&quot;&gt;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Text)&lt;/p&gt;
&lt;p&gt;Motivation for the workshop**&lt;/p&gt;
&lt;p&gt;Nature is still full of unknown chemistry with possible beneficial properties such as anti-inflammatory or antibiotic ones. Over the last decade, increasing numbers of genome sequences and metabolomics profiles have become available in public resources. Hence, the combination of genome mining and metabolome mining has gained traction in accelerating natural product discovery by linking biosynthetic genes to molecular scaffolds and structures, and associating producers with their products. However, effective integrative omics mining has proven challenging due to the various data types and tools involved. In 2021, &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008920&quot;&gt;NPLinker&lt;/a&gt; was proposed as a solution to streamline many aspects of integrative omics, so that researchers can focus on analyzing the possible matches between genes and molecules. Over the last years, the Open eScience Call project has further build on this solution to create &lt;a href=&quot;https://research-software-directory.org/software/nplinker&quot;&gt;a framework for paired omics analyses&lt;/a&gt;. To gain experience with the NPLinker framework and build an integrative omics mining community of talented, driven early-career researchers and knowledgeable instructors, Marnix Medema and I organized this second NPLinker-eScience workshop in Wageningen, the Netherlands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outline of the workshop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During this second workshop in a series of two, we again aimed to bring together researchers interested in integrative omics analysis, spanning various career stages, computational or the application-focused backgrounds, and diverse organisms they work on. Following a selection process, 38 participants were selected to come to Wageningen to learn about analyzing genomes and metabolomes, and to get an outlook towards the integration of the two. The general aims of &lt;a href=&quot;https://www.wur.nl/en/research-results/chair-groups/plant-sciences/bioinformatics/teaching/nplinker_workshop.htm&quot;&gt;the workshop&lt;/a&gt; were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce the NPLinker framework both conceptually and hands-on&lt;/li&gt;
&lt;li&gt;Educate and train natural product researchers and other interested scientists&lt;/li&gt;
&lt;li&gt;Extend the Integrative Omics Mining Community&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The workshop intended learning outcomes were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand the concepts of and motivations for paired omics analysis&lt;/li&gt;
&lt;li&gt;Apply NPLinker to a public paired omics dataset&lt;/li&gt;
&lt;li&gt;Understand the NPLinker scoring&lt;/li&gt;
&lt;li&gt;Evaluate NPLinker outcome in the web app&lt;/li&gt;
&lt;li&gt;Understand how to contribute to the NPLinker code base&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To stimulate networking amongst the participants and instructors, several measures were put in place: extended coffee and tea breaks, the opportunity to present a poster, and a social mixer at the start to get to know each other. Furthermore, Marnix and I organized a symposium on Wednesday to highlight exciting developments in genome mining, metabolome mining, integrative omics mining, and the reuse of public omics data. We are grateful for the financial support from the eScience Center, which helped to make the workshop affordable for participants from across the globe through a travel reimbursement scheme and enabled the participation of three international instructors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;669&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-0bf0eb4f.CUwTRxyS_Z85FHB.webp&quot; srcset=&quot;&quot;&gt;
All 38 participants from across the globe together with the instructors in front of the &lt;a href=&quot;https://www.wur.nl/en/location/omnia-2.htm&quot;&gt;Omnia building&lt;/a&gt; at the &lt;a href=&quot;https://www.wur.nl/en.htm&quot;&gt;Wageningen University &amp;#x26; Research&lt;/a&gt; campus.&lt;/p&gt;
&lt;p&gt;I am increasingly aware of how integrative omics mining brings together different disciplines — what’s in a name, one could say. Furthermore, the field connects both researchers using the omics tools and developers working on them. We intentionally invited participants from these two groups and various disciplines to foster connections and collectively gain experience with the latest developments in the field. One key insight is that the fields is moving rapidly: only two years ago, we explained the latest in genome mining and metabolome mining, and during this workshop, versions 2 of BiG-SCAPE and GNPS were on the menu, replacing the previous versions. From a user perspective, this means staying up-to-date with how to use these tools effectively is key to remain on top of the latest possibilities in omics mining. From a developer perspective, it is important to build integrative tools like NPLinker in a way that can keep pace with the fast-evolving omics landscape. Another key insight is that, given the diverse backgrounds of participants, it is challenging to fully cater everyone’s needs. Striking the right balance between fixed program components and more flexible ones may help–allowing the explanation and demonstration of concepts or tools to be targeted based on participants’ needs. A final key insight is that promoting the exchange of knowledge and expertise in between participants is crucial, as it accelerates the uptake of new skills and information and helps form the bonds that create a scientific community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;679&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-ef101463.nn9ZIVYM_nutVJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;677&quot; height=&quot;510&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-fe492552.DR1a_7tq_2uqmG7.webp&quot; srcset=&quot;&quot;&gt;
Participants have been working hands-on with BiG-SCAPE, GNPS, and NPLinker during the workshop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open Access Materials&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A tangible outcome of the workshop for the broader community is that the instructors all made as much as possible &lt;a href=&quot;https://doi.org/10.5281/zenodo.15281967&quot;&gt;the materials available under an open access license&lt;/a&gt;! I hope this initiative will help to further foster the teaching of the future generation of omics miners, support the development of educational resources for genome mining, metabolomics, and metabolome mining, and promote discussions and integration between the fields of genome mining and metabolome mining.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-a548f678.DscDT-pC_Z1pHYGC.webp&quot; srcset=&quot;&quot;&gt;
With huge thanks to all the NPLinker eScience Workshop instructors who came from across the globe to Wageningen to teach the participants many facets of integrative omics mining.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personal reflection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Altogether, I am happy that all participants and instructors enjoyed the workshop and gained something valuable from it. I am very pleased that everyone had a good time and that the location and catering was appreciated. Furthermore, it was great to organize the symposium with Marnix Medema that celebrated the work lustra of our teams in computational genomics (1o years) and metabolomics (5 years). Not only did we invite keynote speakers–Pieter Dorrestein, Tilmann Weber, and Margherita Sosio–but we also invited three workshop participants to showcase their work in a flash talk. In case you are curious, you can watch it back &lt;a href=&quot;https://wur.yuja.com/V/Video?v=885970&amp;#x26;node=4776818&amp;#x26;a=66183860&quot;&gt;here&lt;/a&gt;. I found it nice to read in the evaluations how the participants liked to see each others’ posters during the breaks, and how they liked the flash talks during the symposium.&lt;/p&gt;
&lt;p&gt;If there is one thing I would have changed looking back at the event, it would be to organize more structured parallel sessions to dive deeper into the application and development of NPLinker, for example by using two separate rooms and dividing participants and instructors accordingly. This would have allowed both groups (users and developers) to discuss their ideas and challenges in greater detail, without the feeling of disturbing each other.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-22f93410.DbJUW8l-_ZDPVU9.webp&quot; srcset=&quot;&quot;&gt;
Community building during the workshop dinner!&lt;/p&gt;
&lt;p&gt;What I really liked were the workshop keynotes–thanks again to Kate Duncan for setting the scene on Monday, to Margherita Sosio for showcasing how omics mining is applied in an industrial setting and how the Molecules Gateway operates, and to Kumar Saurabh Singh for sharing his perspective on multi-omics analyses. Further, thanks again to the eScience Center for supporting this workshop series, and to the Omnia and Orion teams for their support and efforts before and during the week. A big thank-you as well to Maria Augustijn and Marie-José van Iersel for their support in organizing various aspects of the workshop and symposium. Thanks to Marnix for your support and being co-organizer of this event. And finally, many thanks to all the participants for their open and constructive attitude during the workshop — much appreciated!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Scientific Community Building through Workshops: the NPLinker eScience experience&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-a3b95cc3.C5BiktrF_ZyC2x6.webp&quot; srcset=&quot;&quot;&gt;
Marnix Medema (right) and myself (left) during the symposium we organized.&lt;/p&gt;
&lt;p&gt;Whilst this was the last workshop in a series of two, I hope to see the integrative omics community together on future occasions!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/scientific-community-building-through-wo-0741307b.Cd4Yi41s.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Benchmarking LLM fine-tuning on different HPC systems</title><link>https://blog.esciencecenter.nl/posts/2025-05-06---benchmarking-llm-fine-tuning-on-different-hpc-systems</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-05-06---benchmarking-llm-fine-tuning-on-different-hpc-systems</guid><description>&lt;p&gt;43&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Authors: Flavio Hafner (Netherlands eScience center), Mattie Niznik (Princeton Research Computing), Malte Lüken (Netherlands eScience center), Alessandra Maranca (Princeton University), Matthew Salganik (Princeton University).&lt;/p&gt;
&lt;p&gt;We have developed a benchmark that compares the compute performance of fine-tuning LLMs on multiple high-performance computing (HPC) systems, including systems designed for working with sensitive data. In this blog post, we introduce the benchmark, describe the lessons learned developing it and make it &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;open-source&lt;/a&gt; so that it can be used and improved by others.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-61f6f9dd.BB_OnOxS_P3heT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nanadua11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Nana Dua&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;our-use-case&quot;&gt;Our use case&lt;/h3&gt;
&lt;p&gt;Our team researches how Large Language Models (LLMs) can be leveraged to predict social outcomes with large-scale social and survey data. We use the ODISSEI Secure Supercomputer (&lt;a href=&quot;https://servicedesk.surf.nl/wiki/spaces/WIKI/pages/17826074/ODISSEI+Secure+Supercomputer&quot;&gt;OSSC&lt;/a&gt;), which &lt;a href=&quot;https://www.surf.nl/&quot;&gt;SURF&lt;/a&gt; operates in the Netherlands. The OSSC is a virtual private cluster running on the hardware of Snellius, the Dutch national supercomputer. The OSSC makes it possible to use GPU and CPU nodes to analyze sensitive data from Statistics Netherlands. This makes the OSSC one among very few systems globally that bring the power of national computing clusters to large-scale social data.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/pdf/2103.14679&quot;&gt;Previous performance benchmarks for OSSC&lt;/a&gt; were entirely focused on CPUs, and the performance of OSSC for GPU-intensive tasks, such as fine-tuning LLMs, was unknown.&lt;/p&gt;
&lt;p&gt;Our benchmarking compares the performance of the OSSC to two different systems: 1) its parent system, &lt;a href=&quot;https://www.surf.nl/en/services/snellius-the-national-supercomputer&quot;&gt;Snellius&lt;/a&gt;, which is not connected to sensitive data and 2) &lt;a href=&quot;https://researchcomputing.princeton.edu/systems/della&quot;&gt;Della&lt;/a&gt;, an HPC system similar to Snellius, which is operated by Princeton University.&lt;/p&gt;
&lt;h3 id=&quot;beyond-our-use-case&quot;&gt;Beyond our use case&lt;/h3&gt;
&lt;p&gt;Our benchmark, &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;openly available on GitHub&lt;/a&gt;, is also a starting point for the exploration of fine-tuning performance in other cases. For instance, one can compare the training performance within and across HPC systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Within a system, one may have to choose between different GPU models, and the cost and benefits of using one versus the other may vary depending on the task.&lt;/li&gt;
&lt;li&gt;Across systems, training performance does not only depend on the raw performance of GPUs–the number of floating point operations per second–, but also on factors such as the file system, how the computing hardware (processing cores and nodes) is connected through wires, and the exact version of GPU models used — as we will show.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-performance-benchmark&quot;&gt;The performance benchmark&lt;/h2&gt;
&lt;h3 id=&quot;the-specification&quot;&gt;The specification&lt;/h3&gt;
&lt;p&gt;We decided that our benchmark should satisfy the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is easy to run in many different computing environments.&lt;/li&gt;
&lt;li&gt;It tracks multiple measures of speed, such as tokens per second and wall time.&lt;/li&gt;
&lt;li&gt;It tracks anything useful to understand possible differences between the environments (GPU usage, CPU usage).&lt;/li&gt;
&lt;li&gt;It is fast to run.&lt;/li&gt;
&lt;li&gt;It is easy to improve over time: as our research evolves, we may need to re-assess the performance for new use cases.&lt;/li&gt;
&lt;li&gt;It is easy to understand and replicate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our compute conditions are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Environment: Della, Snellius, OSSC.&lt;/li&gt;
&lt;li&gt;GPUs: A100 (40/80GB VRAM), H100 (80/96GB VRAM).&lt;/li&gt;
&lt;li&gt;Single-node training, with GPUs per node: 1, 2, 4.&lt;/li&gt;
&lt;li&gt;As many CPUs as are necessary to keep the GPUs busy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-implementation&quot;&gt;The implementation&lt;/h3&gt;
&lt;p&gt;We found that &lt;a href=&quot;https://pytorch.org/torchtune/stable/index.html&quot;&gt;torchtune&lt;/a&gt; fits our requirements best. We fine-tune the &lt;a href=&quot;https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct&quot;&gt;Llama-3.2–1B-Instruct&lt;/a&gt; model on the &lt;a href=&quot;https://huggingface.co/datasets/yahma/alpaca-cleaned&quot;&gt;alpaca-cleaned&lt;/a&gt; dataset. Our main hyperparameters are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A context length of 2048 on a packed dataset&lt;/li&gt;
&lt;li&gt;Low-Rank Adaptation (LoRA) for the attention layers as well as the output layers. We use a rank of 64, alpha of 128 and 0 dropout.&lt;/li&gt;
&lt;li&gt;A batch size of 6, which was the maximum we could fit into our least capable GPUs (A100)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-we-found&quot;&gt;What we found&lt;/h2&gt;
&lt;h3 id=&quot;performance-differences&quot;&gt;Performance differences&lt;/h3&gt;
&lt;p&gt;The figure below shows the results from our benchmarking runs:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;329&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-08fc9eed.N9GnHhKC_15W5Hg.webp&quot; srcset=&quot;&quot;&gt;
Tokens per second per GPU on a single node (higher is better). The colors refer to different systems (Della, Snellius, OSSC); the panels refer to different numbers of GPUs.In our experience, there was little variation in throughput across different runs on the same system, so we did not average over multiple runs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Della was about 15% faster than the Dutch systems, independent of the number and models of GPUs.&lt;/li&gt;
&lt;li&gt;The OSSC performed on par with Snellius.&lt;/li&gt;
&lt;li&gt;For our use case, H100s were between 1.7x and 2x faster than A100s.&lt;/li&gt;
&lt;li&gt;Throughput scales nearly linearly with the number of GPUs: The communication overhead from multiple GPUs was about 6–8% for going from 1 to 2 GPUs and 2% or less for going from 2 to 4 GPUs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these results made sense to us. Because Della and Snellius are broadly similar systems, we were surprised by the performance gap between the two. Thus, we decided to &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark/issues/10&quot;&gt;investigate&lt;/a&gt; further.&lt;/p&gt;
&lt;p&gt;First, we ruled out that the gap stems from differences in software. The precise way to install dependencies differs between Della and Snellius: Our environments use anaconda on Della and a Python virtual environment with pip on Snellius. We confirmed that the two environments use the same package versions.&lt;/p&gt;
&lt;p&gt;Second, we ruled out that the gap stems from differences in the file system. In particular, for high-performance machine learning, data I/O is often a bottleneck, and it can be reduced by using a fast file system. However, our experiments on Snellius showed no difference in speed between the &lt;a href=&quot;https://servicedesk.surf.nl/wiki/display/WIKI/Snellius+filesystems&quot;&gt;various file systems&lt;/a&gt; available.&lt;/p&gt;
&lt;p&gt;We then found that subtle hardware differences probably explain the gap — differences in memory clock speed of the GPUs:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;408&quot; height=&quot;163&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-0b239ae2.Dq9YkhP4_Z1gsdLp.webp&quot; srcset=&quot;&quot;&gt;
Memory clock speed for GPUs on the two systems (higher is better).For the A100s, the Snellius/OSSC GPUs have 40GB VRAM, while the Della GPUs have 80GB VRAM. The 80GB variant also comes with a higher memory clock speed than the 40GB variant, leading to the difference in fine-tuning speed on A100s between Della and Snellius.&lt;/p&gt;
&lt;p&gt;For the H100s, the difference is in the version of the cards, and specifically their memory: Della has cards with the faster HBM3 memory, while Snellius/OSSC has cards with HBM2e memory. This means that the calculations during model training have a memory speed bottleneck on Snellius/OSSC compared to Della.&lt;/p&gt;
&lt;h3 id=&quot;lessons-learned-from-bringing-llms-into-secure-computing-environments&quot;&gt;Lessons learned from bringing LLMs into secure computing environments&lt;/h3&gt;
&lt;p&gt;Running this test and bringing the Llama model into a secure environment created additional challenges.&lt;/p&gt;
&lt;p&gt;First, by default, torchtune downloads the specified dataset from the internet without the user noticing. But because the OSSC is cut off from the internet, we had to use the Alpaca dataset locally and adjust the code accordingly before deployment.&lt;/p&gt;
&lt;p&gt;Second, to import the model weights to the secure computing environment, we had to ensure that the contents of the files were not a security risk. Thus, we followed current best practices: First, we manually scanned the files with the virus scanner &lt;a href=&quot;https://docs.clamav.net/manual/Usage/Scanning.html&quot;&gt;ClamScan&lt;/a&gt;, similar to what Hugging Face does automatically for models hosted there. Second, we imported the model weights in &lt;a href=&quot;https://huggingface.co/docs/safetensors/en/index&quot;&gt;safetensors&lt;/a&gt; format, which is safer than the pickle format and prevents arbitrary code execution.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We introduce a benchmark for comparing throughput for LLM fine-tuning on different HPC systems. We found hardware-driven performance differences between two standard HPC systems. We also provide the first performance comparison of the OSSC compared to its parent system, Snellius. Lastly, our benchmark suggests little cost of scaling fine-tuning to multiple GPUs on a single node.&lt;/p&gt;
&lt;p&gt;The code for our benchmark is publicly available: &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Patrick Bos for feedback on a draft.&lt;/p&gt;</description><pubDate>Tue, 06 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;43&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Authors: Flavio Hafner (Netherlands eScience center), Mattie Niznik (Princeton Research Computing), Malte Lüken (Netherlands eScience center), Alessandra Maranca (Princeton University), Matthew Salganik (Princeton University).&lt;/p&gt;
&lt;p&gt;We have developed a benchmark that compares the compute performance of fine-tuning LLMs on multiple high-performance computing (HPC) systems, including systems designed for working with sensitive data. In this blog post, we introduce the benchmark, describe the lessons learned developing it and make it &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;open-source&lt;/a&gt; so that it can be used and improved by others.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-61f6f9dd.BB_OnOxS_P3heT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nanadua11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Nana Dua&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;our-use-case&quot;&gt;Our use case&lt;/h3&gt;
&lt;p&gt;Our team researches how Large Language Models (LLMs) can be leveraged to predict social outcomes with large-scale social and survey data. We use the ODISSEI Secure Supercomputer (&lt;a href=&quot;https://servicedesk.surf.nl/wiki/spaces/WIKI/pages/17826074/ODISSEI+Secure+Supercomputer&quot;&gt;OSSC&lt;/a&gt;), which &lt;a href=&quot;https://www.surf.nl/&quot;&gt;SURF&lt;/a&gt; operates in the Netherlands. The OSSC is a virtual private cluster running on the hardware of Snellius, the Dutch national supercomputer. The OSSC makes it possible to use GPU and CPU nodes to analyze sensitive data from Statistics Netherlands. This makes the OSSC one among very few systems globally that bring the power of national computing clusters to large-scale social data.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/pdf/2103.14679&quot;&gt;Previous performance benchmarks for OSSC&lt;/a&gt; were entirely focused on CPUs, and the performance of OSSC for GPU-intensive tasks, such as fine-tuning LLMs, was unknown.&lt;/p&gt;
&lt;p&gt;Our benchmarking compares the performance of the OSSC to two different systems: 1) its parent system, &lt;a href=&quot;https://www.surf.nl/en/services/snellius-the-national-supercomputer&quot;&gt;Snellius&lt;/a&gt;, which is not connected to sensitive data and 2) &lt;a href=&quot;https://researchcomputing.princeton.edu/systems/della&quot;&gt;Della&lt;/a&gt;, an HPC system similar to Snellius, which is operated by Princeton University.&lt;/p&gt;
&lt;h3 id=&quot;beyond-our-use-case&quot;&gt;Beyond our use case&lt;/h3&gt;
&lt;p&gt;Our benchmark, &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;openly available on GitHub&lt;/a&gt;, is also a starting point for the exploration of fine-tuning performance in other cases. For instance, one can compare the training performance within and across HPC systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Within a system, one may have to choose between different GPU models, and the cost and benefits of using one versus the other may vary depending on the task.&lt;/li&gt;
&lt;li&gt;Across systems, training performance does not only depend on the raw performance of GPUs–the number of floating point operations per second–, but also on factors such as the file system, how the computing hardware (processing cores and nodes) is connected through wires, and the exact version of GPU models used — as we will show.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-performance-benchmark&quot;&gt;The performance benchmark&lt;/h2&gt;
&lt;h3 id=&quot;the-specification&quot;&gt;The specification&lt;/h3&gt;
&lt;p&gt;We decided that our benchmark should satisfy the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is easy to run in many different computing environments.&lt;/li&gt;
&lt;li&gt;It tracks multiple measures of speed, such as tokens per second and wall time.&lt;/li&gt;
&lt;li&gt;It tracks anything useful to understand possible differences between the environments (GPU usage, CPU usage).&lt;/li&gt;
&lt;li&gt;It is fast to run.&lt;/li&gt;
&lt;li&gt;It is easy to improve over time: as our research evolves, we may need to re-assess the performance for new use cases.&lt;/li&gt;
&lt;li&gt;It is easy to understand and replicate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our compute conditions are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Environment: Della, Snellius, OSSC.&lt;/li&gt;
&lt;li&gt;GPUs: A100 (40/80GB VRAM), H100 (80/96GB VRAM).&lt;/li&gt;
&lt;li&gt;Single-node training, with GPUs per node: 1, 2, 4.&lt;/li&gt;
&lt;li&gt;As many CPUs as are necessary to keep the GPUs busy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-implementation&quot;&gt;The implementation&lt;/h3&gt;
&lt;p&gt;We found that &lt;a href=&quot;https://pytorch.org/torchtune/stable/index.html&quot;&gt;torchtune&lt;/a&gt; fits our requirements best. We fine-tune the &lt;a href=&quot;https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct&quot;&gt;Llama-3.2–1B-Instruct&lt;/a&gt; model on the &lt;a href=&quot;https://huggingface.co/datasets/yahma/alpaca-cleaned&quot;&gt;alpaca-cleaned&lt;/a&gt; dataset. Our main hyperparameters are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A context length of 2048 on a packed dataset&lt;/li&gt;
&lt;li&gt;Low-Rank Adaptation (LoRA) for the attention layers as well as the output layers. We use a rank of 64, alpha of 128 and 0 dropout.&lt;/li&gt;
&lt;li&gt;A batch size of 6, which was the maximum we could fit into our least capable GPUs (A100)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-we-found&quot;&gt;What we found&lt;/h2&gt;
&lt;h3 id=&quot;performance-differences&quot;&gt;Performance differences&lt;/h3&gt;
&lt;p&gt;The figure below shows the results from our benchmarking runs:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;329&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-08fc9eed.N9GnHhKC_15W5Hg.webp&quot; srcset=&quot;&quot;&gt;
Tokens per second per GPU on a single node (higher is better). The colors refer to different systems (Della, Snellius, OSSC); the panels refer to different numbers of GPUs.In our experience, there was little variation in throughput across different runs on the same system, so we did not average over multiple runs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Della was about 15% faster than the Dutch systems, independent of the number and models of GPUs.&lt;/li&gt;
&lt;li&gt;The OSSC performed on par with Snellius.&lt;/li&gt;
&lt;li&gt;For our use case, H100s were between 1.7x and 2x faster than A100s.&lt;/li&gt;
&lt;li&gt;Throughput scales nearly linearly with the number of GPUs: The communication overhead from multiple GPUs was about 6–8% for going from 1 to 2 GPUs and 2% or less for going from 2 to 4 GPUs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these results made sense to us. Because Della and Snellius are broadly similar systems, we were surprised by the performance gap between the two. Thus, we decided to &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark/issues/10&quot;&gt;investigate&lt;/a&gt; further.&lt;/p&gt;
&lt;p&gt;First, we ruled out that the gap stems from differences in software. The precise way to install dependencies differs between Della and Snellius: Our environments use anaconda on Della and a Python virtual environment with pip on Snellius. We confirmed that the two environments use the same package versions.&lt;/p&gt;
&lt;p&gt;Second, we ruled out that the gap stems from differences in the file system. In particular, for high-performance machine learning, data I/O is often a bottleneck, and it can be reduced by using a fast file system. However, our experiments on Snellius showed no difference in speed between the &lt;a href=&quot;https://servicedesk.surf.nl/wiki/display/WIKI/Snellius+filesystems&quot;&gt;various file systems&lt;/a&gt; available.&lt;/p&gt;
&lt;p&gt;We then found that subtle hardware differences probably explain the gap — differences in memory clock speed of the GPUs:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Benchmarking LLM fine-tuning on different HPC systems&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;408&quot; height=&quot;163&quot; src=&quot;https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-0b239ae2.Dq9YkhP4_Z1gsdLp.webp&quot; srcset=&quot;&quot;&gt;
Memory clock speed for GPUs on the two systems (higher is better).For the A100s, the Snellius/OSSC GPUs have 40GB VRAM, while the Della GPUs have 80GB VRAM. The 80GB variant also comes with a higher memory clock speed than the 40GB variant, leading to the difference in fine-tuning speed on A100s between Della and Snellius.&lt;/p&gt;
&lt;p&gt;For the H100s, the difference is in the version of the cards, and specifically their memory: Della has cards with the faster HBM3 memory, while Snellius/OSSC has cards with HBM2e memory. This means that the calculations during model training have a memory speed bottleneck on Snellius/OSSC compared to Della.&lt;/p&gt;
&lt;h3 id=&quot;lessons-learned-from-bringing-llms-into-secure-computing-environments&quot;&gt;Lessons learned from bringing LLMs into secure computing environments&lt;/h3&gt;
&lt;p&gt;Running this test and bringing the Llama model into a secure environment created additional challenges.&lt;/p&gt;
&lt;p&gt;First, by default, torchtune downloads the specified dataset from the internet without the user noticing. But because the OSSC is cut off from the internet, we had to use the Alpaca dataset locally and adjust the code accordingly before deployment.&lt;/p&gt;
&lt;p&gt;Second, to import the model weights to the secure computing environment, we had to ensure that the contents of the files were not a security risk. Thus, we followed current best practices: First, we manually scanned the files with the virus scanner &lt;a href=&quot;https://docs.clamav.net/manual/Usage/Scanning.html&quot;&gt;ClamScan&lt;/a&gt;, similar to what Hugging Face does automatically for models hosted there. Second, we imported the model weights in &lt;a href=&quot;https://huggingface.co/docs/safetensors/en/index&quot;&gt;safetensors&lt;/a&gt; format, which is safer than the pickle format and prevents arbitrary code execution.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We introduce a benchmark for comparing throughput for LLM fine-tuning on different HPC systems. We found hardware-driven performance differences between two standard HPC systems. We also provide the first performance comparison of the OSSC compared to its parent system, Snellius. Lastly, our benchmark suggests little cost of scaling fine-tuning to multiple GPUs on a single node.&lt;/p&gt;
&lt;p&gt;The code for our benchmark is publicly available: &lt;a href=&quot;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&quot;&gt;https://github.com/odissei-benchmarks/torchtune-gpu-benchmark&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks to Patrick Bos for feedback on a draft.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/benchmarking-llm-fine-tuning-on-differen-61f6f9dd.BB_OnOxS.jpg" medium="image"/><author>Flavio Hafner</author></item><item><title>Keeping your scientific data files small</title><link>https://blog.esciencecenter.nl/posts/2025-04-22---keeping-your-scientific-data-files-small</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-04-22---keeping-your-scientific-data-files-small</guid><description>&lt;h1 id=&quot;keeping-your-scientific-data-files-small&quot;&gt;&lt;strong&gt;Keeping your scientific data files small&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;an-rses-guide-to-netcdf-compression&quot;&gt;An RSE’s guide to NetCDF compression&lt;/h2&gt;
&lt;p&gt;If you’ve ever watched a crawling progress bar while transferring research data, or received a dreaded ‘storage quota exceeded’ message, you’re not alone. Researchers across disciplines face a common challenge: the size of collected data can outpace storage and processing capabilities. This blog explores how compression techniques for NetCDF (Network Common Data Form) files — a format commonly used for multidimensional scientific data — can reduce storage requirements while maintaining data integrity. Whether you’re handling climate models, GIS data, or sensor networks, these approaches can change how you manage and access multidimensional data, such as data with both time and spatial coordinates.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;247&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-98bdacab.BAgZz0KS_Z1jIqyL.webp&quot; srcset=&quot;&quot;&gt;
Simplified structure of a netCDF file (from the &lt;a href=&quot;https://docs.xarray.dev/en/latest/user-guide/data-structures.html#dataset&quot;&gt;xarray documentation&lt;/a&gt;); created by Stephan Hoyer, Apache 2.0 license).If you have multidimensional data, the file sizes can get big quite fast. Take output from the &lt;a href=&quot;https://www.ecmwf.int/en/forecasts/dataset/ecmwf-reanalysis-v5&quot;&gt;ERA5 global weather reanalysis&lt;/a&gt; product:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It has a resolution of 0.25 degrees, at an hourly frequency.&lt;/li&gt;
&lt;li&gt;This means that there are 720x1440x365x24 = 9 billion data points per variable per year.&lt;/li&gt;
&lt;li&gt;This type of data is usually represented as &lt;a href=&quot;https://en.wikipedia.org/wiki/Single-precision_floating-point_format&quot;&gt;32-bit floating points numbers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;32 bits equals 4 bytes, times 9 billion; approximately 36 GB/year. Per variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As soon as you want to analyze multiple years, for multiple variables, your required storage can quickly reach dozens of terabytes. Storing all this data can not only be prohibitively difficult or expensive, it also significantly increases your carbon footprint. Luckily, there are multiple ways to reduce the file size of netCDF files, with various up- and downsides.&lt;/p&gt;
&lt;h3 id=&quot;lossless-compression&quot;&gt;Lossless compression**&lt;/h3&gt;
&lt;p&gt;You are probably familiar with putting files on your computer in a zip folder. This can significantly reduce their size (if the data is not already compressed yet):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;627&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-b8c718e0.DGm5X3sc_lkybk.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Lossless compression of a simple 19 kB python code file&lt;/em&gt;You can then retrieve the exact files from the zip folder, without any loss of information. This is called “lossless” compression. Many files on your computer are compressed in this way already (for example, Microsoft Office files, or PDF documents).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lossy compression&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A different compression method you probably have encountered before is lossy compression. Lossy compression is often applied to audio, images and video to dramatically reduce their size (~10x for audio or still images, 100x for video), with little &lt;em&gt;perceived&lt;/em&gt; quality loss.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;200&quot; height=&quot;200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-74813b92.BawBpZT5_ZYuTqU.webp&quot; srcset=&quot;&quot;&gt;
*Very lossy JPEG compression versus lossless PNG. Source: *&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Comparison_of_JPEG_and_PNG.png&quot;&gt;&lt;em&gt;Wikimedia&lt;/em&gt;&lt;/a&gt;A downside of lossy compression is that each time you open the data and would write it away lossily again, additional compression artifacts are introduced. This will cause a gradual degradation in data quality.&lt;/p&gt;
&lt;h2 id=&quot;compressing-netcdf-files&quot;&gt;Compressing netCDF files&lt;/h2&gt;
&lt;p&gt;As a quick refresher, we need to discuss how netCDF files are structured.&lt;/p&gt;
&lt;p&gt;NetCDF files organize the data per variable. Each variable in turn is split up in different “chunks”. These chunks correspond to subsets of the full array. For example, data can be chunked only in time, where each chunk represents the entire physical domain (latitude &amp;#x26; longitude) for a single time coordinate.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;211&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-16368190.DhbsZa2l_ZXGA1a.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Graphical representation of chunks in the xarray python package, using Dask&lt;/em&gt;These chunks are read into memory one at a time, so for any operations it is important that the chunks fit your analysis for efficiency.&lt;/p&gt;
&lt;p&gt;The actual underlying data can be stored as 32-bit floating point numbers on disk, but there are a few options for compression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lossless netCDF compression&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just like with text files or other documents, lossless compression is possible for netCDF files. The more repetitious your data is, the easier it is for lossless compression algorithms to compress your data.&lt;/p&gt;
&lt;p&gt;cdo -z zip 4 … # where 4 is the compression level (1 - 9)In Python, with the popular ‘xarray’ package, you can instead do:&lt;/p&gt;
&lt;p&gt;import xarray as xr&lt;/p&gt;
&lt;p&gt;ds = xr.open_dataset(“my_dataset.nc”)
encoding = {“my_variable”: {“zlib”: True, “complevel”: 4}}
ds.to_netcdf(“compressed_dataset.nc”, encoding=encoding)In many cases applying lossless compression to your data can reduce the size on disk by 20–50%. This comes at a cost of slightly more CPU use, while disk I/O usage is lower.&lt;/p&gt;
&lt;p&gt;The exact impact on your analysis speed will depend on your system, but unless you have a slow CPU and a blazingly fast disk your further analyses will likely be faster when you compress your data. Therefore it’s best to default to using some form of lossless compression on your netCDF files, unless you have a specific reason not to.&lt;/p&gt;
&lt;p&gt;Lossy netCDF compression**&lt;/p&gt;
&lt;p&gt;As stated earlier, unlike lossless compression, lossy compression does not preserve the full original data. Some of the original resolution can be lost, while offering a much smaller file size as well as a faster read speed.&lt;/p&gt;
&lt;p&gt;Often some loss of resolution is not a problem, as 32-bit floating point numbers offer more precision than many measurements or model data realistically have.&lt;/p&gt;
&lt;p&gt;One way of lossy compression which is well supported by netCDF is encoding floating point numbers to integers. This is usually done with 16-bit unsigned integers: whole numbers ranging from 0 to 65,535. The floating point numbers can then be mapped to this range.&lt;/p&gt;
&lt;p&gt;For example; as the lowest ambient air temperature ever recorded on earth is 184 K, and the highest 330 K, giving a range of 146 K. To convert the temperature, you take the integer value, multiply it with a ‘scale factor’, and add the offset. The temperature range can thus be divided over 65,535 discrete values, translating into a maximum resolution of ~2.23 mK, which is a much higher resolution than most scientific air temperature sensors. Your offset here would be 184 K.&lt;/p&gt;
&lt;p&gt;Integer encoding works very well for climate data as the range of values that you can expect should be very well constrained. This allows you to make informed estimates of what sufficient precision is for these variables, while still significantly reducing the size of the data on disk.&lt;/p&gt;
&lt;p&gt;When using integer encoding in xarray you can specify the encoding as such:&lt;/p&gt;
&lt;p&gt;import xarray as xr**
ds = xr.open_dataset(“my_dataset.nc”)&lt;/p&gt;
&lt;p&gt;fvalue = 65535  # fill value for missing values
scale = 0.005  # store temperature in 5 mK increments
offset = 0  # Kelvin is abolute: no offset required&lt;/p&gt;
&lt;p&gt;encoding = {
“my_temperature_variable”:
{
‘_FillValue’: fvalue, ‘scale_factor’: scale, ‘add_offset’: offset, ‘dtype’: ‘int16’,
“zlib”: True, “complevel”: 4,  # you can still use lossless compression!
},
}&lt;/p&gt;
&lt;p&gt;ds.to_netcdf(“compressed_dataset.nc”, encoding=encoding)For Climate Data Operators users, the &lt;a href=&quot;https://code.mpimet.mpg.de/projects/cdo/embedded/index.html#x1-1130002.2.4&quot;&gt;“pack” operator&lt;/a&gt; is available for this purpose.&lt;/p&gt;
&lt;p&gt;Compression ‘filters’**&lt;/p&gt;
&lt;p&gt;Lastly, HDF5; the underlying data format of netCDF4 files, has “filter plugins” available. These plugins allow you to use other lossy compression algorithms for your netCDF data. These filters are a more advanced use case and not as easy to set up as the other compression methods.&lt;/p&gt;
&lt;p&gt;Some publications (e.g., &lt;a href=&quot;https://gmd.copernicus.org/articles/17/8909/2024/&quot;&gt;Prims, 2024&lt;/a&gt;, and &lt;a href=&quot;https://gmd.copernicus.org/articles/12/4099/2019/#section14&quot;&gt;Delauney, 2019&lt;/a&gt;)) have studied the effect of these on netCDF and numerical weather prediction data specifically.&lt;/p&gt;
&lt;p&gt;Depending on the variables, these compression algorithms can reduce the data size on disk by a factor of 5–150. However, unlike integer compression, the effects of these compression algorithms on your data is not as easily predictable, and you might need to do a sensitivity study for your own application.&lt;/p&gt;
&lt;p&gt;However, there are use cases such as many climate model ensembles where compressing the data lossily could be a way to store data that would otherwise be too large to store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compression and chunks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As the underlying data of each variable in a netCDF file is organized in “chunks”, the compression algorithm is applied per chunk. *This allows you to still load individual chunks of data without requiring to load and decompress the entire file.&lt;/p&gt;
&lt;p&gt;Therefore it is important to organize these chunks in a way that aligns well with your intended usage; for example, either looking at the full time series for a single location, or the entire world at a single point in time. This will enable you to read parts of your full netCDF file very quickly and store them efficiently.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Compressing your netCDF data can reduce your disk usage significantly, which allows you to store or share data more easily. For most users lossless compression is the most straightforward and should be applied by default.&lt;/p&gt;
&lt;p&gt;For many others, where storage space is a constraint, storing your floating point numbers as 16-bit integers is a predictable way of compressing your data further. Other lossy algorithms are available, but are generally too complex to use for most users.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-e8dca7c8.DvWanidn_1mq1og.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jasonpofahlphotography?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Jason Pofahl&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 22 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;keeping-your-scientific-data-files-small&quot;&gt;&lt;strong&gt;Keeping your scientific data files small&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;an-rses-guide-to-netcdf-compression&quot;&gt;An RSE’s guide to NetCDF compression&lt;/h2&gt;
&lt;p&gt;If you’ve ever watched a crawling progress bar while transferring research data, or received a dreaded ‘storage quota exceeded’ message, you’re not alone. Researchers across disciplines face a common challenge: the size of collected data can outpace storage and processing capabilities. This blog explores how compression techniques for NetCDF (Network Common Data Form) files — a format commonly used for multidimensional scientific data — can reduce storage requirements while maintaining data integrity. Whether you’re handling climate models, GIS data, or sensor networks, these approaches can change how you manage and access multidimensional data, such as data with both time and spatial coordinates.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;247&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-98bdacab.BAgZz0KS_Z1jIqyL.webp&quot; srcset=&quot;&quot;&gt;
Simplified structure of a netCDF file (from the &lt;a href=&quot;https://docs.xarray.dev/en/latest/user-guide/data-structures.html#dataset&quot;&gt;xarray documentation&lt;/a&gt;); created by Stephan Hoyer, Apache 2.0 license).If you have multidimensional data, the file sizes can get big quite fast. Take output from the &lt;a href=&quot;https://www.ecmwf.int/en/forecasts/dataset/ecmwf-reanalysis-v5&quot;&gt;ERA5 global weather reanalysis&lt;/a&gt; product:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It has a resolution of 0.25 degrees, at an hourly frequency.&lt;/li&gt;
&lt;li&gt;This means that there are 720x1440x365x24 = 9 billion data points per variable per year.&lt;/li&gt;
&lt;li&gt;This type of data is usually represented as &lt;a href=&quot;https://en.wikipedia.org/wiki/Single-precision_floating-point_format&quot;&gt;32-bit floating points numbers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;32 bits equals 4 bytes, times 9 billion; approximately 36 GB/year. Per variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As soon as you want to analyze multiple years, for multiple variables, your required storage can quickly reach dozens of terabytes. Storing all this data can not only be prohibitively difficult or expensive, it also significantly increases your carbon footprint. Luckily, there are multiple ways to reduce the file size of netCDF files, with various up- and downsides.&lt;/p&gt;
&lt;h3 id=&quot;lossless-compression&quot;&gt;Lossless compression**&lt;/h3&gt;
&lt;p&gt;You are probably familiar with putting files on your computer in a zip folder. This can significantly reduce their size (if the data is not already compressed yet):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;627&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-b8c718e0.DGm5X3sc_lkybk.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Lossless compression of a simple 19 kB python code file&lt;/em&gt;You can then retrieve the exact files from the zip folder, without any loss of information. This is called “lossless” compression. Many files on your computer are compressed in this way already (for example, Microsoft Office files, or PDF documents).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lossy compression&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A different compression method you probably have encountered before is lossy compression. Lossy compression is often applied to audio, images and video to dramatically reduce their size (~10x for audio or still images, 100x for video), with little &lt;em&gt;perceived&lt;/em&gt; quality loss.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;200&quot; height=&quot;200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-74813b92.BawBpZT5_ZYuTqU.webp&quot; srcset=&quot;&quot;&gt;
*Very lossy JPEG compression versus lossless PNG. Source: *&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Comparison_of_JPEG_and_PNG.png&quot;&gt;&lt;em&gt;Wikimedia&lt;/em&gt;&lt;/a&gt;A downside of lossy compression is that each time you open the data and would write it away lossily again, additional compression artifacts are introduced. This will cause a gradual degradation in data quality.&lt;/p&gt;
&lt;h2 id=&quot;compressing-netcdf-files&quot;&gt;Compressing netCDF files&lt;/h2&gt;
&lt;p&gt;As a quick refresher, we need to discuss how netCDF files are structured.&lt;/p&gt;
&lt;p&gt;NetCDF files organize the data per variable. Each variable in turn is split up in different “chunks”. These chunks correspond to subsets of the full array. For example, data can be chunked only in time, where each chunk represents the entire physical domain (latitude &amp;#x26; longitude) for a single time coordinate.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;211&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-16368190.DhbsZa2l_ZXGA1a.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Graphical representation of chunks in the xarray python package, using Dask&lt;/em&gt;These chunks are read into memory one at a time, so for any operations it is important that the chunks fit your analysis for efficiency.&lt;/p&gt;
&lt;p&gt;The actual underlying data can be stored as 32-bit floating point numbers on disk, but there are a few options for compression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lossless netCDF compression&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just like with text files or other documents, lossless compression is possible for netCDF files. The more repetitious your data is, the easier it is for lossless compression algorithms to compress your data.&lt;/p&gt;
&lt;p&gt;cdo -z zip 4 … # where 4 is the compression level (1 - 9)In Python, with the popular ‘xarray’ package, you can instead do:&lt;/p&gt;
&lt;p&gt;import xarray as xr&lt;/p&gt;
&lt;p&gt;ds = xr.open_dataset(“my_dataset.nc”)
encoding = {“my_variable”: {“zlib”: True, “complevel”: 4}}
ds.to_netcdf(“compressed_dataset.nc”, encoding=encoding)In many cases applying lossless compression to your data can reduce the size on disk by 20–50%. This comes at a cost of slightly more CPU use, while disk I/O usage is lower.&lt;/p&gt;
&lt;p&gt;The exact impact on your analysis speed will depend on your system, but unless you have a slow CPU and a blazingly fast disk your further analyses will likely be faster when you compress your data. Therefore it’s best to default to using some form of lossless compression on your netCDF files, unless you have a specific reason not to.&lt;/p&gt;
&lt;p&gt;Lossy netCDF compression**&lt;/p&gt;
&lt;p&gt;As stated earlier, unlike lossless compression, lossy compression does not preserve the full original data. Some of the original resolution can be lost, while offering a much smaller file size as well as a faster read speed.&lt;/p&gt;
&lt;p&gt;Often some loss of resolution is not a problem, as 32-bit floating point numbers offer more precision than many measurements or model data realistically have.&lt;/p&gt;
&lt;p&gt;One way of lossy compression which is well supported by netCDF is encoding floating point numbers to integers. This is usually done with 16-bit unsigned integers: whole numbers ranging from 0 to 65,535. The floating point numbers can then be mapped to this range.&lt;/p&gt;
&lt;p&gt;For example; as the lowest ambient air temperature ever recorded on earth is 184 K, and the highest 330 K, giving a range of 146 K. To convert the temperature, you take the integer value, multiply it with a ‘scale factor’, and add the offset. The temperature range can thus be divided over 65,535 discrete values, translating into a maximum resolution of ~2.23 mK, which is a much higher resolution than most scientific air temperature sensors. Your offset here would be 184 K.&lt;/p&gt;
&lt;p&gt;Integer encoding works very well for climate data as the range of values that you can expect should be very well constrained. This allows you to make informed estimates of what sufficient precision is for these variables, while still significantly reducing the size of the data on disk.&lt;/p&gt;
&lt;p&gt;When using integer encoding in xarray you can specify the encoding as such:&lt;/p&gt;
&lt;p&gt;import xarray as xr**
ds = xr.open_dataset(“my_dataset.nc”)&lt;/p&gt;
&lt;p&gt;fvalue = 65535  # fill value for missing values
scale = 0.005  # store temperature in 5 mK increments
offset = 0  # Kelvin is abolute: no offset required&lt;/p&gt;
&lt;p&gt;encoding = {
“my_temperature_variable”:
{
‘_FillValue’: fvalue, ‘scale_factor’: scale, ‘add_offset’: offset, ‘dtype’: ‘int16’,
“zlib”: True, “complevel”: 4,  # you can still use lossless compression!
},
}&lt;/p&gt;
&lt;p&gt;ds.to_netcdf(“compressed_dataset.nc”, encoding=encoding)For Climate Data Operators users, the &lt;a href=&quot;https://code.mpimet.mpg.de/projects/cdo/embedded/index.html#x1-1130002.2.4&quot;&gt;“pack” operator&lt;/a&gt; is available for this purpose.&lt;/p&gt;
&lt;p&gt;Compression ‘filters’**&lt;/p&gt;
&lt;p&gt;Lastly, HDF5; the underlying data format of netCDF4 files, has “filter plugins” available. These plugins allow you to use other lossy compression algorithms for your netCDF data. These filters are a more advanced use case and not as easy to set up as the other compression methods.&lt;/p&gt;
&lt;p&gt;Some publications (e.g., &lt;a href=&quot;https://gmd.copernicus.org/articles/17/8909/2024/&quot;&gt;Prims, 2024&lt;/a&gt;, and &lt;a href=&quot;https://gmd.copernicus.org/articles/12/4099/2019/#section14&quot;&gt;Delauney, 2019&lt;/a&gt;)) have studied the effect of these on netCDF and numerical weather prediction data specifically.&lt;/p&gt;
&lt;p&gt;Depending on the variables, these compression algorithms can reduce the data size on disk by a factor of 5–150. However, unlike integer compression, the effects of these compression algorithms on your data is not as easily predictable, and you might need to do a sensitivity study for your own application.&lt;/p&gt;
&lt;p&gt;However, there are use cases such as many climate model ensembles where compressing the data lossily could be a way to store data that would otherwise be too large to store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compression and chunks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As the underlying data of each variable in a netCDF file is organized in “chunks”, the compression algorithm is applied per chunk. *This allows you to still load individual chunks of data without requiring to load and decompress the entire file.&lt;/p&gt;
&lt;p&gt;Therefore it is important to organize these chunks in a way that aligns well with your intended usage; for example, either looking at the full time series for a single location, or the entire world at a single point in time. This will enable you to read parts of your full netCDF file very quickly and store them efficiently.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Compressing your netCDF data can reduce your disk usage significantly, which allows you to store or share data more easily. For most users lossless compression is the most straightforward and should be applied by default.&lt;/p&gt;
&lt;p&gt;For many others, where storage space is a constraint, storing your floating point numbers as 16-bit integers is a predictable way of compressing your data further. Other lossy algorithms are available, but are generally too complex to use for most users.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keeping your scientific data files small&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-e8dca7c8.DvWanidn_1mq1og.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jasonpofahlphotography?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Jason Pofahl&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/keeping-your-scientific-data-files-small-98bdacab.BAgZz0KS.jpeg" medium="image"/><author>Bart Schilperoort</author></item><item><title>Solving the mystery of the missing symbols! (part II)</title><link>https://blog.esciencecenter.nl/posts/2025-04-22---solving-the-mystery-of-the-missing-symbols-part-ii</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-04-22---solving-the-mystery-of-the-missing-symbols-part-ii</guid><description>&lt;h2 id=&quot;this-is-the-conclusion-to-the-story-i-wrote-about-earlier&quot;&gt;&lt;em&gt;This is the conclusion to the story I &lt;em&gt;&lt;a href=&quot;https://medium.com/escience-center/a-debugging-journey-into-the-unknown-a2fa291bfb35&quot;&gt;&lt;em&gt;wrote about&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; earlier.&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;In that earlier post, we were investigating why the MingW-w64 build of DuckDB fails to export the C-API symbols in the final DLL. We identified that the issue was introduced by the commit &lt;a href=&quot;https://github.com/duckdb/duckdb/commit/d1ea1538c9217fb536485f1500f04a0b55b1e584&quot;&gt;d1ea1538&lt;/a&gt;. However, we could not ascertain the underlying reason for the problem. To take this further, let us try to isolate which part of the change was the cause.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Solving the mystery of the missing symbols! (part II)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/solving-the-mystery-of-the-missing-symbo-41382a82.CPSPwa2V_Z2ldSdg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@tomasmartinez?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tomas Martinez&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-dead-end&quot;&gt;A dead-end&lt;/h2&gt;
&lt;p&gt;To identify the source file responsible for the bug, we can start by inspecting the different build artifacts and checking for the C-API symbols. But first, we need to log all the build commands. It is much easier to do this with Make than Ninja (default generator for DuckDB). We can choose our generator by calling CMake as:&lt;/p&gt;
&lt;p&gt;$ cmake -G “Unix Makefiles” …We can then log all the build commands by starting a verbose build with Make:&lt;/p&gt;
&lt;p&gt;$ VERBOSE=1 make -j6 |&amp;#x26; tee build.logWith all the build commands recorded to a log file, I searched for commands that create the shared library &lt;code&gt;libduckdb.dll&lt;/code&gt; and narrowed it down to the following set of build commands:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;/usr/bin/cmake -E rm -f CMakeFiles/duckdb.dir/objects.a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;sr&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; /usr/bin/x86_64-w64-mingw32-ar qc CMakeFiles/duckdb.dir/objects.a @CMakeFiles/duckdb.dir/objects1.rsp
$ /usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -shared -o libduckdb.dll &lt;br&gt;
-Wl,—out-implib,libduckdb.dll.a -Wl,—major-image-version,0,—minor-image-version,0 -Wl,—whole-archive &lt;br&gt;
CMakeFiles/duckdb.dir/objects.a -Wl,—no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rspGoing through the steps individually, we will see that even though the symbols are present in the earlier steps, the final library creation step drops them.&lt;/p&gt;
&lt;h2 id=&quot;tracing-through-the-build-steps&quot;&gt;Tracing through the build steps&lt;/h2&gt;
&lt;p&gt;Let us first look for the object file that has the C-API symbols.&lt;/p&gt;
&lt;p&gt;$ tr ’ ’ ‘\n’ &amp;#x3C;CMakeFiles/duckdb.dir/objects1.rsp | grep capi.cpp
main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.objWe can then check for the C-API symbols in the object, and confirm that the object file is included in the objects archive.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0000000000004&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.obj | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ai&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ai&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;pp&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0000000000004&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; /usr/bin/x86_64-w64-mingw32-ar t CMakeFiles/duckdb.dir/objects.a | grep capi.cpp
ub_duckdb_main_capi.cpp.objIf we check for the C-API symbols again in the archive file, we see they are present and publicly visible (exported).&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0000000000004&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0000000000004&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; winedump -j export CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
31a0ae4 duckdb_vector_sizeFinally, we can create the shared library by calling the linker.&lt;/p&gt;
&lt;p&gt;$ /usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -shared -o libduckdb.dll &lt;br&gt;
-Wl,—out-implib,libduckdb.dll.a -Wl,—major-image-version,0,—minor-image-version,0 -Wl,—whole-archive &lt;br&gt;
CMakeFiles/duckdb.dir/objects.a -Wl,—no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rspWe see that while the C-API symbols are present, they are not exported!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;00000001&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mn&gt;116&lt;/mn&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C libduckdb.dll | grep duckdb_vector_size
00000001f3d116e0 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ib&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;00000001&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;116&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; winedump -j export libduckdb.dll | grep duckdb_vector_size # no match&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While not helpful on its own, the observation that symbols are not exported in the final linking step that creates the DLL will make sense later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;a-clue&quot;&gt;A clue&lt;/h2&gt;
&lt;p&gt;Since we could not already isolate the issue to a source file, next, I decided to “bisect” the contents of the problem commit. As the issue is with C-API symbols, I started with the files that have these symbols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb.h&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/main/capi/aggregate_function-c.cpp&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test/api/capi/capi_aggregate_functions.cpp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I commented out parts of the above files, while ensuring the build still succeeds, and checking for the C-API symbols in the final DLL in the usual way with &lt;code&gt;nm&lt;/code&gt; and &lt;code&gt;winedump&lt;/code&gt;. This led me to discover that the &lt;em&gt;problem disappears if we reorder the include headers&lt;/em&gt; in &lt;code&gt;src/main/capi/aggregate_function-c.cpp&lt;/code&gt;. You can see the change in this PR: &lt;a href=&quot;https://github.com/duckdb/duckdb/pull/16396/files&quot;&gt;duckdb/duckdb#16396&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;diff —git a/src/main/capi/aggregate_function-c.cpp b/src/main/capi/aggregate_function-c.cpp
index 43ddfdbc074a..1379f652d669 100644
--- a/src/main/capi/aggregate_function-c.cpp
+++ b/src/main/capi/aggregate_function-c.cpp
@@ -1,9 +1,11 @@
+// clang-format off
+#include “duckdb/main/capi/capi_internal.hpp”
+// clang-format on
#include “duckdb/catalog/catalog.hpp”
#include “duckdb/common/type_visitor.hpp”
#include “duckdb/common/types.hpp”
#include “duckdb/function/function.hpp”
#include “duckdb/function/scalar_function.hpp”
-#include “duckdb/main/capi/capi_internal.hpp”
#include “duckdb/main/client_context.hpp”
#include “duckdb/parser/parsed_data/create_aggregate_function_info.hpp”
#include “duckdb/planner/expression/bound_function_expression.hpp”This is, of course, not the correct solution since there should not be any dependence on the order in which we include headers. It is indicative of an underlying bug. This means some definition in the headers is being overridden silently. This can only happen for preprocessor macros; anything else would trigger a compilation error.&lt;/p&gt;
&lt;h2 id=&quot;solution-to-the-mystery&quot;&gt;Solution to the mystery!&lt;/h2&gt;
&lt;p&gt;After further investigation from DuckDB core developer Mark Raasveldt, the issue was resolved in this PR: &lt;a href=&quot;https://github.com/duckdb/duckdb/pull/16397&quot;&gt;duckdb/duckdb#13697&lt;/a&gt;. So, what was the issue?&lt;/p&gt;
&lt;p&gt;When building shared libraries for Windows, the public API has to be marked for export. This is done by adding the &lt;code&gt;__declspec(dllexport)&lt;/code&gt; &lt;a href=&quot;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md#symbol-visibility-in-windows-dlls&quot;&gt;attribute&lt;/a&gt; to the relevant symbols. In the DuckDB codebase this is done by defining a macro &lt;code&gt;DUCKDB_API&lt;/code&gt; that expands to that attribute. However, there were two such definitions, they were in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb.h&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb/common/winapi.hpp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Superficially, they seem equivalent, however, they are actually used in slightly different contexts. The macro defined in &lt;code&gt;duckdb.h&lt;/code&gt; is used to annotate symbols that are part of the C-API*. Whereas the macro defined in &lt;code&gt;winapi.hpp&lt;/code&gt; is used to mark symbols that comprise the &lt;em&gt;C++ API&lt;/em&gt;. In an earlier commit (&lt;a href=&quot;https://github.com/duckdb/duckdb/commit/367595af51b459d07121647bc2de1beabc836e0c&quot;&gt;367595af&lt;/a&gt;), the macro defined in &lt;code&gt;winapi.hpp&lt;/code&gt; was changed to exclude MingW builds.&lt;/p&gt;
&lt;p&gt;diff —git a/src/include/duckdb/common/winapi.hpp b/src/include/duckdb/common/winapi.hpp
index 2cff5d12d4..65dd89975e 100644
--- a/src/include/duckdb/common/winapi.hpp
+++ b/src/include/duckdb/common/winapi.hpp
@@ -9,7 +9,7 @@
#pragma once&lt;/p&gt;
&lt;p&gt;#ifndef DUCKDB_API
-#ifdef _WIN32
+#if defined(_WIN32) &amp;#x26;&amp;#x26; !defined(&lt;strong&gt;MINGW32&lt;/strong&gt;)
#if defined(DUCKDB_BUILD_LIBRARY) &amp;#x26;&amp;#x26; !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else&lt;/p&gt;
&lt;h2 id=&quot;the-reason--the-fix&quot;&gt;The reason &amp;#x26; the fix&lt;/h2&gt;
&lt;p&gt;When exporting symbols, MingW normally excludes inline functions (see &lt;code&gt;man x86_64-w64-mingw32-g++&lt;/code&gt; and search for &lt;code&gt;-fkeep-inline-functions&lt;/code&gt;). The macro redefinition handles this case by excluding symbol export for MingW.&lt;/p&gt;
&lt;p&gt;Now, in the DuckDB source, depending on which definition is seen first, symbols may or may not be exported. This, of course, depends on the order of the include headers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;duckdb.h&lt;/code&gt; is seen first, symbols are exported correctly, on the other hand&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;winapi.hpp&lt;/code&gt; is seen first, symbols are not exported.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The final fix was to rename one of the macros to make the two definitions distinct so that they do not interfere with each other; i.e.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;duckdb.h&lt;/code&gt; was renamed to &lt;code&gt;DUCKDB_C_API&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;winapi.hpp&lt;/code&gt; remains unchanged.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-did-we-learn&quot;&gt;What did we learn?&lt;/h2&gt;
&lt;p&gt;After this resolution, any project reliant on this build can update to the latest version of DuckDB starting from version 1.2.1. In our case that is the Julia binding for DuckDB, &lt;code&gt;DuckDB.jl&lt;/code&gt;. If we look at the original issue: &lt;a href=&quot;https://github.com/duckdb/duckdb/issues/13911&quot;&gt;duckdb/duckdb#13911&lt;/a&gt;, there are many different projects reliant on it, so the impact of this fix is quite broad!&lt;/p&gt;
&lt;p&gt;During this investigation, we also learnt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bisection is an incredibly effective idea that can be used in many different contexts, and&lt;/li&gt;
&lt;li&gt;macro hygiene is important in C/C++ code bases.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Tue, 22 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;this-is-the-conclusion-to-the-story-i-wrote-about-earlier&quot;&gt;&lt;em&gt;This is the conclusion to the story I &lt;em&gt;&lt;a href=&quot;https://medium.com/escience-center/a-debugging-journey-into-the-unknown-a2fa291bfb35&quot;&gt;&lt;em&gt;wrote about&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; earlier.&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;In that earlier post, we were investigating why the MingW-w64 build of DuckDB fails to export the C-API symbols in the final DLL. We identified that the issue was introduced by the commit &lt;a href=&quot;https://github.com/duckdb/duckdb/commit/d1ea1538c9217fb536485f1500f04a0b55b1e584&quot;&gt;d1ea1538&lt;/a&gt;. However, we could not ascertain the underlying reason for the problem. To take this further, let us try to isolate which part of the change was the cause.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Solving the mystery of the missing symbols! (part II)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/solving-the-mystery-of-the-missing-symbo-41382a82.CPSPwa2V_Z2ldSdg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@tomasmartinez?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tomas Martinez&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-dead-end&quot;&gt;A dead-end&lt;/h2&gt;
&lt;p&gt;To identify the source file responsible for the bug, we can start by inspecting the different build artifacts and checking for the C-API symbols. But first, we need to log all the build commands. It is much easier to do this with Make than Ninja (default generator for DuckDB). We can choose our generator by calling CMake as:&lt;/p&gt;
&lt;p&gt;$ cmake -G “Unix Makefiles” …We can then log all the build commands by starting a verbose build with Make:&lt;/p&gt;
&lt;p&gt;$ VERBOSE=1 make -j6 |&amp;#x26; tee build.logWith all the build commands recorded to a log file, I searched for commands that create the shared library &lt;code&gt;libduckdb.dll&lt;/code&gt; and narrowed it down to the following set of build commands:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;/usr/bin/cmake -E rm -f CMakeFiles/duckdb.dir/objects.a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;sr&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; /usr/bin/x86_64-w64-mingw32-ar qc CMakeFiles/duckdb.dir/objects.a @CMakeFiles/duckdb.dir/objects1.rsp
$ /usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -shared -o libduckdb.dll &lt;br&gt;
-Wl,—out-implib,libduckdb.dll.a -Wl,—major-image-version,0,—minor-image-version,0 -Wl,—whole-archive &lt;br&gt;
CMakeFiles/duckdb.dir/objects.a -Wl,—no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rspGoing through the steps individually, we will see that even though the symbols are present in the earlier steps, the final library creation step drops them.&lt;/p&gt;
&lt;h2 id=&quot;tracing-through-the-build-steps&quot;&gt;Tracing through the build steps&lt;/h2&gt;
&lt;p&gt;Let us first look for the object file that has the C-API symbols.&lt;/p&gt;
&lt;p&gt;$ tr ’ ’ ‘\n’ &amp;#x3C;CMakeFiles/duckdb.dir/objects1.rsp | grep capi.cpp
main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.objWe can then check for the C-API symbols in the object, and confirm that the object file is included in the objects archive.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0000000000004&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.obj | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ai&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ai&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;pp&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0000000000004&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; /usr/bin/x86_64-w64-mingw32-ar t CMakeFiles/duckdb.dir/objects.a | grep capi.cpp
ub_duckdb_main_capi.cpp.objIf we check for the C-API symbols again in the archive file, we see they are present and publicly visible (exported).&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0000000000004&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;ak&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;bj&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0000000000004&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; winedump -j export CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
31a0ae4 duckdb_vector_sizeFinally, we can create the shared library by calling the linker.&lt;/p&gt;
&lt;p&gt;$ /usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -shared -o libduckdb.dll &lt;br&gt;
-Wl,—out-implib,libduckdb.dll.a -Wl,—major-image-version,0,—minor-image-version,0 -Wl,—whole-archive &lt;br&gt;
CMakeFiles/duckdb.dir/objects.a -Wl,—no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rspWe see that while the C-API symbols are present, they are not exported!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;00000001&lt;/mn&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mn&gt;116&lt;/mn&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;nm -C libduckdb.dll | grep duckdb_vector_size
00000001f3d116e0 T duckdb_vector_size&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ib&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;00000001&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;116&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; winedump -j export libduckdb.dll | grep duckdb_vector_size # no match&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While not helpful on its own, the observation that symbols are not exported in the final linking step that creates the DLL will make sense later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;a-clue&quot;&gt;A clue&lt;/h2&gt;
&lt;p&gt;Since we could not already isolate the issue to a source file, next, I decided to “bisect” the contents of the problem commit. As the issue is with C-API symbols, I started with the files that have these symbols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb.h&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/main/capi/aggregate_function-c.cpp&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test/api/capi/capi_aggregate_functions.cpp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I commented out parts of the above files, while ensuring the build still succeeds, and checking for the C-API symbols in the final DLL in the usual way with &lt;code&gt;nm&lt;/code&gt; and &lt;code&gt;winedump&lt;/code&gt;. This led me to discover that the &lt;em&gt;problem disappears if we reorder the include headers&lt;/em&gt; in &lt;code&gt;src/main/capi/aggregate_function-c.cpp&lt;/code&gt;. You can see the change in this PR: &lt;a href=&quot;https://github.com/duckdb/duckdb/pull/16396/files&quot;&gt;duckdb/duckdb#16396&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;diff —git a/src/main/capi/aggregate_function-c.cpp b/src/main/capi/aggregate_function-c.cpp
index 43ddfdbc074a..1379f652d669 100644
--- a/src/main/capi/aggregate_function-c.cpp
+++ b/src/main/capi/aggregate_function-c.cpp
@@ -1,9 +1,11 @@
+// clang-format off
+#include “duckdb/main/capi/capi_internal.hpp”
+// clang-format on
#include “duckdb/catalog/catalog.hpp”
#include “duckdb/common/type_visitor.hpp”
#include “duckdb/common/types.hpp”
#include “duckdb/function/function.hpp”
#include “duckdb/function/scalar_function.hpp”
-#include “duckdb/main/capi/capi_internal.hpp”
#include “duckdb/main/client_context.hpp”
#include “duckdb/parser/parsed_data/create_aggregate_function_info.hpp”
#include “duckdb/planner/expression/bound_function_expression.hpp”This is, of course, not the correct solution since there should not be any dependence on the order in which we include headers. It is indicative of an underlying bug. This means some definition in the headers is being overridden silently. This can only happen for preprocessor macros; anything else would trigger a compilation error.&lt;/p&gt;
&lt;h2 id=&quot;solution-to-the-mystery&quot;&gt;Solution to the mystery!&lt;/h2&gt;
&lt;p&gt;After further investigation from DuckDB core developer Mark Raasveldt, the issue was resolved in this PR: &lt;a href=&quot;https://github.com/duckdb/duckdb/pull/16397&quot;&gt;duckdb/duckdb#13697&lt;/a&gt;. So, what was the issue?&lt;/p&gt;
&lt;p&gt;When building shared libraries for Windows, the public API has to be marked for export. This is done by adding the &lt;code&gt;__declspec(dllexport)&lt;/code&gt; &lt;a href=&quot;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md#symbol-visibility-in-windows-dlls&quot;&gt;attribute&lt;/a&gt; to the relevant symbols. In the DuckDB codebase this is done by defining a macro &lt;code&gt;DUCKDB_API&lt;/code&gt; that expands to that attribute. However, there were two such definitions, they were in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb.h&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/include/duckdb/common/winapi.hpp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Superficially, they seem equivalent, however, they are actually used in slightly different contexts. The macro defined in &lt;code&gt;duckdb.h&lt;/code&gt; is used to annotate symbols that are part of the C-API*. Whereas the macro defined in &lt;code&gt;winapi.hpp&lt;/code&gt; is used to mark symbols that comprise the &lt;em&gt;C++ API&lt;/em&gt;. In an earlier commit (&lt;a href=&quot;https://github.com/duckdb/duckdb/commit/367595af51b459d07121647bc2de1beabc836e0c&quot;&gt;367595af&lt;/a&gt;), the macro defined in &lt;code&gt;winapi.hpp&lt;/code&gt; was changed to exclude MingW builds.&lt;/p&gt;
&lt;p&gt;diff —git a/src/include/duckdb/common/winapi.hpp b/src/include/duckdb/common/winapi.hpp
index 2cff5d12d4..65dd89975e 100644
--- a/src/include/duckdb/common/winapi.hpp
+++ b/src/include/duckdb/common/winapi.hpp
@@ -9,7 +9,7 @@
#pragma once&lt;/p&gt;
&lt;p&gt;#ifndef DUCKDB_API
-#ifdef _WIN32
+#if defined(_WIN32) &amp;#x26;&amp;#x26; !defined(&lt;strong&gt;MINGW32&lt;/strong&gt;)
#if defined(DUCKDB_BUILD_LIBRARY) &amp;#x26;&amp;#x26; !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else&lt;/p&gt;
&lt;h2 id=&quot;the-reason--the-fix&quot;&gt;The reason &amp;#x26; the fix&lt;/h2&gt;
&lt;p&gt;When exporting symbols, MingW normally excludes inline functions (see &lt;code&gt;man x86_64-w64-mingw32-g++&lt;/code&gt; and search for &lt;code&gt;-fkeep-inline-functions&lt;/code&gt;). The macro redefinition handles this case by excluding symbol export for MingW.&lt;/p&gt;
&lt;p&gt;Now, in the DuckDB source, depending on which definition is seen first, symbols may or may not be exported. This, of course, depends on the order of the include headers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;duckdb.h&lt;/code&gt; is seen first, symbols are exported correctly, on the other hand&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;winapi.hpp&lt;/code&gt; is seen first, symbols are not exported.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The final fix was to rename one of the macros to make the two definitions distinct so that they do not interfere with each other; i.e.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;duckdb.h&lt;/code&gt; was renamed to &lt;code&gt;DUCKDB_C_API&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DUCKDB_API&lt;/code&gt; in &lt;code&gt;winapi.hpp&lt;/code&gt; remains unchanged.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-did-we-learn&quot;&gt;What did we learn?&lt;/h2&gt;
&lt;p&gt;After this resolution, any project reliant on this build can update to the latest version of DuckDB starting from version 1.2.1. In our case that is the Julia binding for DuckDB, &lt;code&gt;DuckDB.jl&lt;/code&gt;. If we look at the original issue: &lt;a href=&quot;https://github.com/duckdb/duckdb/issues/13911&quot;&gt;duckdb/duckdb#13911&lt;/a&gt;, there are many different projects reliant on it, so the impact of this fix is quite broad!&lt;/p&gt;
&lt;p&gt;During this investigation, we also learnt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bisection is an incredibly effective idea that can be used in many different contexts, and&lt;/li&gt;
&lt;li&gt;macro hygiene is important in C/C++ code bases.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/solving-the-mystery-of-the-missing-symbo-41382a82.CPSPwa2V.jpg" medium="image"/><author>Suvayu</author></item><item><title>Introduction to Deep Learning with Python</title><link>https://blog.esciencecenter.nl/posts/2025-03-25---introduction-to-deep-learning-with-python</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-03-25---introduction-to-deep-learning-with-python</guid><description>&lt;h2 id=&quot;written-by-sven-van-der-burg-carsten-schnober-sarah-m-brown-and-toby-hodges&quot;&gt;Written by &lt;a href=&quot;https://www.esciencecenter.nl/team/sven-van-der-burg/&quot;&gt;Sven van der Burg&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/carsten-schnober/&quot;&gt;Carsten Schnober&lt;/a&gt;, &lt;a href=&quot;https://carpentries.org/blog/author/sarah-m-brown/&quot;&gt;Sarah M. Brown&lt;/a&gt; and &lt;a href=&quot;https://carpentries.org/blog/author/toby-hodges/&quot;&gt;Toby Hodges&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Engineers and instructors at the eScience Center have developed lots of open source lesson materials for the workshops we teach. One example is the lesson material for &lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/&quot;&gt;&lt;em&gt;Introduction to Deep Learning&lt;/em&gt;&lt;/a&gt;*, *which was recently accepted into the peer-reviewed lesson material collection in the &lt;a href=&quot;https://carpentries-lab.org/&quot;&gt;Carpentries Lab&lt;/a&gt;. In this post you can read more about the lesson and its development.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Introduction to Deep Learning with Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/introduction-to-deep-learning-with-pytho-6c0721f9.BkgMA3vv_239jHH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@scottwebb?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Scott Webb&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Carpentries Lab was set up as a space for peer-reviewed lessons developed by &lt;a href=&quot;https://carpentries.org/about-us/&quot;&gt;the Carpentries community&lt;/a&gt;. Designed to complement &lt;a href=&quot;https://carpentries-incubator.org/&quot;&gt;The Carpentries Incubator&lt;/a&gt;, where the community collaborates on the development of new lessons on a wide range of topics, the Lab is a platform for open peer-review of community-developed lessons and for hosting the lessons that have passed through that review process.&lt;/p&gt;
&lt;p&gt;The text below was originally published on &lt;a href=&quot;https://carpentries.org/blog/2025/03/carpentries-lab-introduction-to-deep-learning-with-python/&quot;&gt;the Carpentries blog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;about-the-curriculum&quot;&gt;About the curriculum&lt;/h2&gt;
&lt;p&gt;The use of deep learning has seen a sharp increase in popularity and applicability over the last decade. While deep learning can be a useful tool for researchers from a wide range of domains, taking the first steps in the world of deep learning can be somewhat intimidating.&lt;/p&gt;
&lt;p&gt;Introduction to Deep Learning covers the fundamentals of deep learning in a practical and hands-on manner, for researchers who want to apply deep learning in their research. By the end of the course, students will be able to train their first neural network and understand the subsequent steps needed to improve the model.&lt;/p&gt;
&lt;p&gt;The lesson can be taught in a 2-day or 4 half-day workshop.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Introduction to Deep Learning with Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;425&quot; src=&quot;https://blog.esciencecenter.nl/_astro/introduction-to-deep-learning-with-pytho-01ca30a5.BRpGGPlp_Z4xKIB.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Part of the &lt;em&gt;&lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/3-monitor-the-model.html&quot;&gt;&lt;em&gt;Monitor the training Process&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; episode of the lesson.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-brief-history-of-the-development-of-this-lesson&quot;&gt;A brief history of the development of this lesson&lt;/h2&gt;
&lt;p&gt;What follows is a year-by-year history of the main contributors to the lesson. Of course, GitHub keeps the score, and all contributions to the commit history, big and, especially, small, can be better tracked &lt;a href=&quot;https://github.com/carpentries-lab/deep-learning-intro/graphs/contributors&quot;&gt;in this interactive contributor graph&lt;/a&gt;. Over the years 30 people contributed to this lesson!&lt;/p&gt;
&lt;p&gt;The development of the lesson started in 2020 in a collaboration between &lt;a href=&quot;https://github.com/bpmweel&quot;&gt;Berend Weel&lt;/a&gt; and &lt;a href=&quot;https://github.com/florian-huber&quot;&gt;Florian Huber&lt;/a&gt; (both at the Netherlands eScience Center at the time), &lt;a href=&quot;https://github.com/psteinb&quot;&gt;Peter Steinbach&lt;/a&gt;, &lt;a href=&quot;https://github.com/colinsauze&quot;&gt;Colin Sauze&lt;/a&gt;, &lt;a href=&quot;https://github.com/samumantha&quot;&gt;Samantha Wittke&lt;/a&gt;, and &lt;a href=&quot;https://github.com/tobyhodges&quot;&gt;Toby Hodges&lt;/a&gt;. During this period the main design of the lesson was drafted and the first pilot workshops were given.&lt;/p&gt;
&lt;p&gt;During the year of 2021, Dafne van Kuppevelt, Djura Smits, and Sven van der Burg from the Netherlands eScience Center became involved and by the year 2022 Sven and Djura were the main contributors. In this period the lesson was taught a lot by various organisations and all feedback went into an ever-improving lesson.&lt;/p&gt;
&lt;p&gt;In the period from 2023 till now the lesson was really polished towards its final shape, thanks to contributions from fresh team members Carsten Schnober and Pranav Chandramouli from the Netherlands eScience Center. This is the period that the lesson was transitioned to The Carpentries Workbench and went through The Carpentries Lab review process.&lt;/p&gt;
&lt;h2 id=&quot;about-the-review-process&quot;&gt;About the review process&lt;/h2&gt;
&lt;p&gt;The curriculum was reviewed in &lt;a href=&quot;https://github.com/carpentries-lab/reviews/issues/25&quot;&gt;a public issue thread on The Carpentries Lab reviews repository&lt;/a&gt;. This was a slightly unusual case because one of the authors is a member of The Carpentries Curriculum Team and was the sole Editor of the Lab at the time of submission. (Three other community members have joined as Editors since.) &lt;a href=&quot;https://github.com/brownsarahm&quot;&gt;Sarah M Brown&lt;/a&gt;, formerly a long-standing member of the Trainers Leadership Committee, accepted an invitation to act as Guest Editor for this review. The authors and Carpentries team are enormously grateful to Sarah for the effort she put in and the diligence she displayed throughout the process. She made several essential contributions as Editor, in particular by encouraging the authors to more deeply explore the choice of example datasets used in the lesson (read more about this below).&lt;/p&gt;
&lt;p&gt;After the authors had responded to Sarah’s initial editorial checks, the curriculum was reviewed in detail by two volunteers from The Carpentries community: &lt;a href=&quot;https://github.com/PaulaNietoG&quot;&gt;Johanna Bayer&lt;/a&gt; and &lt;a href=&quot;https://github.com/mike-ivs&quot;&gt;Mike Laverick&lt;/a&gt; (thanks to Erin Becker for helping to connect Sarah with these reviewers). These reviewers were invited based on their expertise as Carpentries Instructors and their domain knowledge in machine learning and related fields.&lt;/p&gt;
&lt;p&gt;The peer-review process led to a number of improvements to the accessibility of the lesson, with better alternative text descriptions for images and various adjustments to make language clearer and more beginner-friendly. The lesson was made easier to teach by other instructors through the addition and improvement of Instructor Notes, and the explanations of a number of important deep learning concepts were expanded.&lt;/p&gt;
&lt;p&gt;Perhaps most importantly, the Editor highlighted that one of the datasets used as an example in the lesson, the CIFAR-10 dataset, is not available under a clearly-defined license. On closer inspection, the authors were surprised to find that CIFAR-10, a dataset very commonly used for benchmarking in machine learning research, was created with image files scraped from the internet without permission from their original owners.&lt;/p&gt;
&lt;p&gt;Sven van der Burg, one of the leading authors of the lesson, created &lt;a href=&quot;https://zenodo.org/records/10970014&quot;&gt;the “Dollar Street 10” dataset&lt;/a&gt; as an alternative to replace CIFAR-10 in the lesson. Dollar Street 10 is derived from the CC-BY-4.0 licensed Dollar Street Dataset from the Gapminder Project: a collection of images that has been more ethically assembled with an emphasis on ensuring that the data is representative of global diversity and accompanied by accurate metadata. The authors added a callout to the lesson to comment on this change, as they felt it represented a great entry point for a discussion of ethics in data and deep learning during a workshop.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;The development team will of course keep on teaching this lesson at their institutes and keep on improving the lesson. We will have to, since deep learning is such a rapidly moving field. But our main goal is to help as many others as possible to adopt this lesson so that it can be taught around the world!&lt;/p&gt;
&lt;p&gt;The lesson has been submitted to &lt;a href=&quot;https://jose.theoj.org/&quot;&gt;The Journal of Open Source Education&lt;/a&gt; for publication.&lt;/p&gt;
&lt;p&gt;The wider Carpentries community can now &lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/&quot;&gt;find the lesson in The Carpentries Lab&lt;/a&gt;, use and adapt it to teach their own workshops, contribute feedback, and suggest improvements. We hope you find it a helpful resource!&lt;/p&gt;
&lt;h2 id=&quot;become-a-reviewer&quot;&gt;Become a Reviewer&lt;/h2&gt;
&lt;p&gt;The Carpentries Lab is looking for reviewers!** To volunteer to review a lesson in the Lab, please read &lt;a href=&quot;https://github.com/carpentries-lab/reviews/blob/main/docs/reviewer_guide.md&quot;&gt;our Guide for Reviewers&lt;/a&gt;, and &lt;a href=&quot;https://forms.gle/cFD4nVjstTtVYoxg8&quot;&gt;register as a reviewer&lt;/a&gt; so we can contact you when relevant lessons are ready for review.&lt;/p&gt;
&lt;p&gt;Lessons in the Incubator can be submitted for review in the Lab by &lt;a href=&quot;https://github.com/carpentries-lab/reviews/issues/new?assignees=tobyhodges&amp;#x26;labels=review&amp;#x26;template=review_submission.yml&amp;#x26;title=%5BReview%5D%3A+&quot;&gt;opening an issue on the reviews repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;We would like to thank all instructors and helpers that taught the course, and the community of people that left contributions to the project, no matter how big or small.&lt;/p&gt;
&lt;p&gt;We thank The Carpentries for providing such a great framework for developing this lesson material.&lt;/p&gt;
&lt;p&gt;We thank all students enrolled in the workshops that were taught using this lesson material for providing us with feedback.&lt;/p&gt;
&lt;p&gt;Congratulations to the authors for creating an excellent lesson that will prove a useful resource to so many people:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/svenvanderburg&quot;&gt;Sven van der Burg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/florian-huber/&quot;&gt;Florian Huber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/psteinb/&quot;&gt;Peter Steinbach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/colinsauze/&quot;&gt;Colin Sauze&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/carschno/&quot;&gt;Carsten Schnober&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dsmits/&quot;&gt;Djura Smits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tobyhodges/&quot;&gt;Toby Hodges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bpmweel&quot;&gt;Berend Weel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cpranav93/&quot;&gt;Pranav Chandramouli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wikfeldt/&quot;&gt;Thor Wikfeldt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CunliangGeng/&quot;&gt;Cunliang Geng&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/qualiaMachine/&quot;&gt;Chris Endemann&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wmotion/&quot;&gt;Giordano Lipari&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/samumantha&quot;&gt;Samantha Wittke&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ashwinvis&quot;&gt;Ashwin V. Mohanan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sstevens2&quot;&gt;Sarah Stevens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/axdy-a&quot;&gt;axdy-a&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/code4yonglei&quot;&gt;YL Wang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Morrizzzzz&quot;&gt;Maurice de Kleijn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/laurasootes&quot;&gt;Laura Ootes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/k-dominik&quot;&gt;Dominik Kutra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sunyi000&quot;&gt;Yi Sun&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/esclapez&quot;&gt;Lucas Esclapez&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/unode&quot;&gt;Renato Alves&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miguel-mx&quot;&gt;Miguel A Magaña&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FenneRiemslagh&quot;&gt;Fenne Riemslagh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dafnevk&quot;&gt;Dafne van Kuppevelt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/annefou&quot;&gt;Anne Fouilloux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And huge thanks again to &lt;a href=&quot;https://github.com/brownsarahm&quot;&gt;Sarah M Brown&lt;/a&gt; for acting as Guest Editor, and to the reviewers, &lt;a href=&quot;https://github.com/likeajumprope&quot;&gt;Johanna Bayer&lt;/a&gt; and &lt;a href=&quot;https://github.com/mike-ivs&quot;&gt;Mike Laverick&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 25 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;written-by-sven-van-der-burg-carsten-schnober-sarah-m-brown-and-toby-hodges&quot;&gt;Written by &lt;a href=&quot;https://www.esciencecenter.nl/team/sven-van-der-burg/&quot;&gt;Sven van der Burg&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/carsten-schnober/&quot;&gt;Carsten Schnober&lt;/a&gt;, &lt;a href=&quot;https://carpentries.org/blog/author/sarah-m-brown/&quot;&gt;Sarah M. Brown&lt;/a&gt; and &lt;a href=&quot;https://carpentries.org/blog/author/toby-hodges/&quot;&gt;Toby Hodges&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Engineers and instructors at the eScience Center have developed lots of open source lesson materials for the workshops we teach. One example is the lesson material for &lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/&quot;&gt;&lt;em&gt;Introduction to Deep Learning&lt;/em&gt;&lt;/a&gt;*, *which was recently accepted into the peer-reviewed lesson material collection in the &lt;a href=&quot;https://carpentries-lab.org/&quot;&gt;Carpentries Lab&lt;/a&gt;. In this post you can read more about the lesson and its development.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Introduction to Deep Learning with Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/introduction-to-deep-learning-with-pytho-6c0721f9.BkgMA3vv_239jHH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@scottwebb?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Scott Webb&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Carpentries Lab was set up as a space for peer-reviewed lessons developed by &lt;a href=&quot;https://carpentries.org/about-us/&quot;&gt;the Carpentries community&lt;/a&gt;. Designed to complement &lt;a href=&quot;https://carpentries-incubator.org/&quot;&gt;The Carpentries Incubator&lt;/a&gt;, where the community collaborates on the development of new lessons on a wide range of topics, the Lab is a platform for open peer-review of community-developed lessons and for hosting the lessons that have passed through that review process.&lt;/p&gt;
&lt;p&gt;The text below was originally published on &lt;a href=&quot;https://carpentries.org/blog/2025/03/carpentries-lab-introduction-to-deep-learning-with-python/&quot;&gt;the Carpentries blog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;about-the-curriculum&quot;&gt;About the curriculum&lt;/h2&gt;
&lt;p&gt;The use of deep learning has seen a sharp increase in popularity and applicability over the last decade. While deep learning can be a useful tool for researchers from a wide range of domains, taking the first steps in the world of deep learning can be somewhat intimidating.&lt;/p&gt;
&lt;p&gt;Introduction to Deep Learning covers the fundamentals of deep learning in a practical and hands-on manner, for researchers who want to apply deep learning in their research. By the end of the course, students will be able to train their first neural network and understand the subsequent steps needed to improve the model.&lt;/p&gt;
&lt;p&gt;The lesson can be taught in a 2-day or 4 half-day workshop.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Introduction to Deep Learning with Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;425&quot; src=&quot;https://blog.esciencecenter.nl/_astro/introduction-to-deep-learning-with-pytho-01ca30a5.BRpGGPlp_Z4xKIB.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Part of the &lt;em&gt;&lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/3-monitor-the-model.html&quot;&gt;&lt;em&gt;Monitor the training Process&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; episode of the lesson.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-brief-history-of-the-development-of-this-lesson&quot;&gt;A brief history of the development of this lesson&lt;/h2&gt;
&lt;p&gt;What follows is a year-by-year history of the main contributors to the lesson. Of course, GitHub keeps the score, and all contributions to the commit history, big and, especially, small, can be better tracked &lt;a href=&quot;https://github.com/carpentries-lab/deep-learning-intro/graphs/contributors&quot;&gt;in this interactive contributor graph&lt;/a&gt;. Over the years 30 people contributed to this lesson!&lt;/p&gt;
&lt;p&gt;The development of the lesson started in 2020 in a collaboration between &lt;a href=&quot;https://github.com/bpmweel&quot;&gt;Berend Weel&lt;/a&gt; and &lt;a href=&quot;https://github.com/florian-huber&quot;&gt;Florian Huber&lt;/a&gt; (both at the Netherlands eScience Center at the time), &lt;a href=&quot;https://github.com/psteinb&quot;&gt;Peter Steinbach&lt;/a&gt;, &lt;a href=&quot;https://github.com/colinsauze&quot;&gt;Colin Sauze&lt;/a&gt;, &lt;a href=&quot;https://github.com/samumantha&quot;&gt;Samantha Wittke&lt;/a&gt;, and &lt;a href=&quot;https://github.com/tobyhodges&quot;&gt;Toby Hodges&lt;/a&gt;. During this period the main design of the lesson was drafted and the first pilot workshops were given.&lt;/p&gt;
&lt;p&gt;During the year of 2021, Dafne van Kuppevelt, Djura Smits, and Sven van der Burg from the Netherlands eScience Center became involved and by the year 2022 Sven and Djura were the main contributors. In this period the lesson was taught a lot by various organisations and all feedback went into an ever-improving lesson.&lt;/p&gt;
&lt;p&gt;In the period from 2023 till now the lesson was really polished towards its final shape, thanks to contributions from fresh team members Carsten Schnober and Pranav Chandramouli from the Netherlands eScience Center. This is the period that the lesson was transitioned to The Carpentries Workbench and went through The Carpentries Lab review process.&lt;/p&gt;
&lt;h2 id=&quot;about-the-review-process&quot;&gt;About the review process&lt;/h2&gt;
&lt;p&gt;The curriculum was reviewed in &lt;a href=&quot;https://github.com/carpentries-lab/reviews/issues/25&quot;&gt;a public issue thread on The Carpentries Lab reviews repository&lt;/a&gt;. This was a slightly unusual case because one of the authors is a member of The Carpentries Curriculum Team and was the sole Editor of the Lab at the time of submission. (Three other community members have joined as Editors since.) &lt;a href=&quot;https://github.com/brownsarahm&quot;&gt;Sarah M Brown&lt;/a&gt;, formerly a long-standing member of the Trainers Leadership Committee, accepted an invitation to act as Guest Editor for this review. The authors and Carpentries team are enormously grateful to Sarah for the effort she put in and the diligence she displayed throughout the process. She made several essential contributions as Editor, in particular by encouraging the authors to more deeply explore the choice of example datasets used in the lesson (read more about this below).&lt;/p&gt;
&lt;p&gt;After the authors had responded to Sarah’s initial editorial checks, the curriculum was reviewed in detail by two volunteers from The Carpentries community: &lt;a href=&quot;https://github.com/PaulaNietoG&quot;&gt;Johanna Bayer&lt;/a&gt; and &lt;a href=&quot;https://github.com/mike-ivs&quot;&gt;Mike Laverick&lt;/a&gt; (thanks to Erin Becker for helping to connect Sarah with these reviewers). These reviewers were invited based on their expertise as Carpentries Instructors and their domain knowledge in machine learning and related fields.&lt;/p&gt;
&lt;p&gt;The peer-review process led to a number of improvements to the accessibility of the lesson, with better alternative text descriptions for images and various adjustments to make language clearer and more beginner-friendly. The lesson was made easier to teach by other instructors through the addition and improvement of Instructor Notes, and the explanations of a number of important deep learning concepts were expanded.&lt;/p&gt;
&lt;p&gt;Perhaps most importantly, the Editor highlighted that one of the datasets used as an example in the lesson, the CIFAR-10 dataset, is not available under a clearly-defined license. On closer inspection, the authors were surprised to find that CIFAR-10, a dataset very commonly used for benchmarking in machine learning research, was created with image files scraped from the internet without permission from their original owners.&lt;/p&gt;
&lt;p&gt;Sven van der Burg, one of the leading authors of the lesson, created &lt;a href=&quot;https://zenodo.org/records/10970014&quot;&gt;the “Dollar Street 10” dataset&lt;/a&gt; as an alternative to replace CIFAR-10 in the lesson. Dollar Street 10 is derived from the CC-BY-4.0 licensed Dollar Street Dataset from the Gapminder Project: a collection of images that has been more ethically assembled with an emphasis on ensuring that the data is representative of global diversity and accompanied by accurate metadata. The authors added a callout to the lesson to comment on this change, as they felt it represented a great entry point for a discussion of ethics in data and deep learning during a workshop.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;The development team will of course keep on teaching this lesson at their institutes and keep on improving the lesson. We will have to, since deep learning is such a rapidly moving field. But our main goal is to help as many others as possible to adopt this lesson so that it can be taught around the world!&lt;/p&gt;
&lt;p&gt;The lesson has been submitted to &lt;a href=&quot;https://jose.theoj.org/&quot;&gt;The Journal of Open Source Education&lt;/a&gt; for publication.&lt;/p&gt;
&lt;p&gt;The wider Carpentries community can now &lt;a href=&quot;https://carpentries-lab.github.io/deep-learning-intro/&quot;&gt;find the lesson in The Carpentries Lab&lt;/a&gt;, use and adapt it to teach their own workshops, contribute feedback, and suggest improvements. We hope you find it a helpful resource!&lt;/p&gt;
&lt;h2 id=&quot;become-a-reviewer&quot;&gt;Become a Reviewer&lt;/h2&gt;
&lt;p&gt;The Carpentries Lab is looking for reviewers!** To volunteer to review a lesson in the Lab, please read &lt;a href=&quot;https://github.com/carpentries-lab/reviews/blob/main/docs/reviewer_guide.md&quot;&gt;our Guide for Reviewers&lt;/a&gt;, and &lt;a href=&quot;https://forms.gle/cFD4nVjstTtVYoxg8&quot;&gt;register as a reviewer&lt;/a&gt; so we can contact you when relevant lessons are ready for review.&lt;/p&gt;
&lt;p&gt;Lessons in the Incubator can be submitted for review in the Lab by &lt;a href=&quot;https://github.com/carpentries-lab/reviews/issues/new?assignees=tobyhodges&amp;#x26;labels=review&amp;#x26;template=review_submission.yml&amp;#x26;title=%5BReview%5D%3A+&quot;&gt;opening an issue on the reviews repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;We would like to thank all instructors and helpers that taught the course, and the community of people that left contributions to the project, no matter how big or small.&lt;/p&gt;
&lt;p&gt;We thank The Carpentries for providing such a great framework for developing this lesson material.&lt;/p&gt;
&lt;p&gt;We thank all students enrolled in the workshops that were taught using this lesson material for providing us with feedback.&lt;/p&gt;
&lt;p&gt;Congratulations to the authors for creating an excellent lesson that will prove a useful resource to so many people:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/svenvanderburg&quot;&gt;Sven van der Burg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/florian-huber/&quot;&gt;Florian Huber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/psteinb/&quot;&gt;Peter Steinbach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/colinsauze/&quot;&gt;Colin Sauze&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/carschno/&quot;&gt;Carsten Schnober&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dsmits/&quot;&gt;Djura Smits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tobyhodges/&quot;&gt;Toby Hodges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bpmweel&quot;&gt;Berend Weel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cpranav93/&quot;&gt;Pranav Chandramouli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wikfeldt/&quot;&gt;Thor Wikfeldt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CunliangGeng/&quot;&gt;Cunliang Geng&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/qualiaMachine/&quot;&gt;Chris Endemann&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wmotion/&quot;&gt;Giordano Lipari&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/samumantha&quot;&gt;Samantha Wittke&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ashwinvis&quot;&gt;Ashwin V. Mohanan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sstevens2&quot;&gt;Sarah Stevens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/axdy-a&quot;&gt;axdy-a&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/code4yonglei&quot;&gt;YL Wang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Morrizzzzz&quot;&gt;Maurice de Kleijn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/laurasootes&quot;&gt;Laura Ootes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/k-dominik&quot;&gt;Dominik Kutra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sunyi000&quot;&gt;Yi Sun&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/esclapez&quot;&gt;Lucas Esclapez&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/unode&quot;&gt;Renato Alves&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miguel-mx&quot;&gt;Miguel A Magaña&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FenneRiemslagh&quot;&gt;Fenne Riemslagh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dafnevk&quot;&gt;Dafne van Kuppevelt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/annefou&quot;&gt;Anne Fouilloux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And huge thanks again to &lt;a href=&quot;https://github.com/brownsarahm&quot;&gt;Sarah M Brown&lt;/a&gt; for acting as Guest Editor, and to the reviewers, &lt;a href=&quot;https://github.com/likeajumprope&quot;&gt;Johanna Bayer&lt;/a&gt; and &lt;a href=&quot;https://github.com/mike-ivs&quot;&gt;Mike Laverick&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/introduction-to-deep-learning-with-pytho-6c0721f9.BkgMA3vv.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>A debugging journey into the unknown (part I)</title><link>https://blog.esciencecenter.nl/posts/2025-03-13---a-debugging-journey-into-the-unknown-part-i</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-03-13---a-debugging-journey-into-the-unknown-part-i</guid><description>&lt;p&gt;&lt;em&gt;Faced with a buggy library, most people will just give up and wait for a patch to be released. Certainly not our engineers.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A debugging journey into the unknown (part I)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-debugging-journey-into-the-unknown-par-feee515a.cLSBS6f2_Z1TJWjC.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://science.nasa.gov/image-detail/pia17049-hires/&quot;&gt;&lt;em&gt;NASA/JPL-Caltech&lt;/em&gt;&lt;/a&gt;It all started with a colleague trying to update their Julia environment for one of &lt;a href=&quot;https://github.com/TulipaEnergy&quot;&gt;our projects&lt;/a&gt;. They could not update because a dependency, the Julia bindings for DuckDB, was failing to compile. For the moment we decided to deal with it later, and pinned &lt;code&gt;DuckDB.jl&lt;/code&gt; to the working version. We also filed an issue upstream: &lt;a href=&quot;https://github.com/duckdb/duckdb/issues/13911&quot;&gt;duckdb/duckdb#13911&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since there was no significant progress on the issue for a few months, I decided to dive in once and for all — this is that story.&lt;/p&gt;
&lt;h2 id=&quot;the-issue&quot;&gt;The issue&lt;/h2&gt;
&lt;p&gt;On Windows, trying to install any version of &lt;code&gt;DuckDB.jl&lt;/code&gt; later than &lt;code&gt;1.0.0&lt;/code&gt; was failing with the error:&lt;/p&gt;
&lt;p&gt;ERROR: LoadError: could not load symbol “duckdb_vector_size”:
The specified procedure could not be found.Some Julia packages, like &lt;code&gt;DuckDB.jl&lt;/code&gt; depend on a native library. The native library is an internal dependency, and typically named &lt;code&gt;MyPackage_jll.jl&lt;/code&gt;; in the case of DuckDB, it is &lt;code&gt;DuckDB_jll.jl&lt;/code&gt;. The error above tells us that during the compilation step, Julia tries to load a symbol from the native library, but cannot find it. A “symbol” here refers to a DuckDB C-API function provided by the native DuckDB library.&lt;/p&gt;
&lt;p&gt;So as a first step, I wanted to check: can we actually install this library, and load that symbol? To get the call syntax correct, I looked at the source code of &lt;code&gt;[DuckDB.jl](https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/tools/juliapkg/src/api.jl#L1285-L1297)&lt;/code&gt;&lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/tools/juliapkg/src/api.jl#L1285-L1297&quot;&gt; &lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;function duckdb_vector_size()
return ccall((:duckdb_vector_size, libduckdb), idx_t, ())
endThe variable &lt;code&gt;idx_t&lt;/code&gt; above is defined in &lt;code&gt;ctypes.jl&lt;/code&gt; as:&lt;/p&gt;
&lt;p&gt;const idx_t = UInt64 # DuckDB index typeSo we can test loading the native library like this:&lt;/p&gt;
&lt;p&gt;pkg&gt; add DuckDB_jll
julia&gt; using DuckDB_jll
julia&gt; ccall((:duckdb_vector_size, libduckdb), UInt64, ())The above recipe replicates the error for any version newer than &lt;code&gt;1.0.0&lt;/code&gt;! Hurray! Now that we have confirmation that the problem is in the native library, we have to understand: &lt;em&gt;Why is the symbol not visible to Julia?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;symbol-visibility-in-windows-dlls&quot;&gt;Symbol visibility in Windows DLLs&lt;/h2&gt;
&lt;p&gt;My first hurdle was to find a way to get both versions of the library and compare. I decided to install different versions of the native library &lt;code&gt;DuckDB_jll&lt;/code&gt;in different directories; after loading the library, the &lt;code&gt;libduckdb&lt;/code&gt; variable points to the correct path of the shared library. We can then use other tools to inspect the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic-link_library&quot;&gt;dynamic-link libraries&lt;/a&gt; (DLLs) and check if the symbols actually exist. If we can compare the working version of the native library with a version that does not maybe we can find out what is wrong.&lt;/p&gt;
&lt;p&gt;On Linux, we can use &lt;code&gt;nm&lt;/code&gt; from &lt;code&gt;binutils&lt;/code&gt; to look at the symbols present in the library. Thanks to the &lt;code&gt;-C&lt;/code&gt; flag, &lt;code&gt;nm&lt;/code&gt; can even &lt;a href=&quot;https://en.wikipedia.org/wiki/Name_mangling&quot;&gt;“demangle”&lt;/a&gt; symbol names if necessary. So for the moment we can copy over DLLs from Windows to Linux, and inspect.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;#&amp;#x27; at position 48: …b_vector_size  #̲ working versio…&quot; style=&quot;color:#cc0000&quot;&gt;nm -C libduckdb.dll | grep duckdb_vector_size  # working version: v1.0.0
000000036a271d00 T duckdb_vector_size&lt;/span&gt; nm -C libduckdb.dll | grep duckdb_vector_size  # not working version: e.g. v1.1.2
000000036a36e0e0 T duckdb_vector_size
000000036be998d0 r .rdata$.refptr.duckdb_vector_size
000000036be998d0 R .refptr.duckdb_vector_sizeNo luck 😦, seems that the symbols exist for both versions of the native library. I was puzzled. Searching around I found while building Windows DLLs, you have to explicitly &lt;a href=&quot;https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport&quot;&gt;export symbol names&lt;/a&gt; using the &lt;code&gt;__declspec(dllexport)&lt;/code&gt; attribute. Besides signalling which names are available, it also serves as a mechanism to optimise DLL load times. So I went looking for these attributes in the DuckDB &lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/src/include/duckdb.h#L17-L31&quot;&gt;source code&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;#ifndef DUCKDB_API
#ifdef _WIN32
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_API
#else
#if defined(DUCKDB_BUILD_LIBRARY) &amp;#x26;&amp;#x26; !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else
#define DUCKDB_API __declspec(dllimport)
#endif
#endif
#else
#define DUCKDB_API
#endif
#endifYou can see, the &lt;code&gt;#ifdef&lt;/code&gt; directives conditionally defines the macro &lt;code&gt;DUCKDB_API&lt;/code&gt; which expands to &lt;code&gt;__declspec(dllexport)&lt;/code&gt; when building a Windows DLL. Later in the header file, this macro is used to &lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/src/include/duckdb.h#L1289-L1295&quot;&gt;mark every C-API function for export&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DUCKDB_API idx_t duckdb_vector_size();Now that we know the C-API function name symbols are marked for export correctly, we should check if they are indeed exported. After some searching, I learnt Windows development tools includes the program &lt;code&gt;dumpbin.exe&lt;/code&gt; that can show the exported symbol names. So I can search for exported symbols in the output.&lt;/p&gt;
&lt;p&gt;Working version of &lt;code&gt;libduckdb.dll&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;&gt; dumpbin.exe /EXPORTS .\bin\libduckdb.dll | findstr duckdb_vector_size
335  14E 0078D1B0 duckdb_vector_sizeFaulty version of &lt;code&gt;libduckdb.dll&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;&gt; dumpbin.exe /EXPORTS .\bin\libduckdb.dll | findstr duckdb_vector_size&lt;/p&gt;
&lt;h1 id=&quot;empty-output-since-nothing-was-foundso-it-is-confirmed-that-the-symbol-export-is-not-working-for-the-faulty-version-however-we-still-do-not-know-which-commit-introduced-the-issue-let-us-try-to-find-that-&quot;&gt;empty output, since nothing was foundSo it is confirmed that the symbol export is not working for the faulty version. However we still do not know which commit introduced the issue. Let us try to find that 🙂.&lt;/h1&gt;
&lt;h2 id=&quot;hunt-for-the-first-bad-commit&quot;&gt;Hunt for the first “bad” commit&lt;/h2&gt;
&lt;p&gt;To be able to find the first bad commit, we need to be able to compile the library. Julia has a whole other infrastructure called &lt;code&gt;[BinaryBuilder](https://binarybuilder.org/)&lt;/code&gt;. It cross-compiles native binaries for all platforms on Linux. This is a whole another rabbit hole, and let us shelve this for another time. The only relevant bit is, the builds are done only* on Linux. This presents a different problem, &lt;code&gt;dumpbin.exe&lt;/code&gt;, the tool to check if the symbol export is correct is available only on Windows. If we are to find the bad commit, we need to automate the build &amp;#x26; check steps and run it with &lt;code&gt;git-bisect&lt;/code&gt;. How can we do that if parts of our toolchain runs on different platforms‽&lt;/p&gt;
&lt;p&gt;So I went searching again for an alternative. Unsurprisingly, Wine (the Windows compatibility layer for Linux) ships with the tool &lt;code&gt;[winedump](https://gitlab.winehq.org/wine/wine/-/wikis/Man-Pages/winedump)&lt;/code&gt;, which is an equivalent to the Windows tool &lt;code&gt;dumpbin.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To build with Windows DLL, we need to cross-compile DuckDB on Linux using the MingW-w64 toolchain. Combined with the &lt;code&gt;winedump&lt;/code&gt; tool, I wrote the following script that we can use to test a successful build.&lt;/p&gt;
&lt;p&gt;#!/bin/bash&lt;/p&gt;
&lt;p&gt;rm -rf build
cmake -B build &lt;br&gt;
-DCMAKE_BUILD_TYPE=Release &lt;br&gt;
-DCMAKE_TOOLCHAIN_FILE=mingw-w64-x86_64.cmake &lt;br&gt;
-DBUILD_EXTENSIONS=‘autocomplete;icu;parquet;json;fts;tpcds;tpch’ &lt;br&gt;
-DENABLE_EXTENSION_AUTOLOADING=1 &lt;br&gt;
-DENABLE_EXTENSION_AUTOINSTALL=1 &lt;br&gt;
-DBUILD_UNITTESTS=FALSE &lt;br&gt;
-DBUILD_SHELL=TRUE &lt;br&gt;
-DDUCKDB_EXPLICIT_PLATFORM=x86_64-w64-mingw32-cxx11 .
cmake —build build&lt;/p&gt;
&lt;p&gt;[[ $? -ne 0 ]] &amp;#x26;&amp;#x26; &lt;br&gt;
{
echo “build failed, cannot test”
exit 125
}&lt;/p&gt;
&lt;p&gt;if [[ -f build/src/libduckdb.dll ]]; then
winedump -j export build/src/libduckdb.dll | grep -q duckdb_vector_size
if [[ $? -eq 0 ]]; then
exit 0
else
exit 1
fi
else
echo “cannot find DLL, cannot test”
exit 125
fiThe script builds DuckDB, and checks whether the generated DLL file export the C-API symbols correctly. It also handles a few corner cases of build failures. Note that the build command uses the following toolchain file (thanks to this &lt;a href=&quot;https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8/&quot;&gt;gist&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)&lt;/p&gt;
&lt;h1 id=&quot;cross-compilers-to-use-for-c-c-and-fortran&quot;&gt;cross compilers to use for C, C++ and Fortran&lt;/h1&gt;
&lt;p&gt;set(CMAKE_C_COMPILER &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;/mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;cc&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;{TOOLCHAIN_PREFIX}-g++)
set(CMAKE_Fortran_COMPILER &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;/mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;{TOOLCHAIN_PREFIX}-windres)&lt;/p&gt;
&lt;h1 id=&quot;target-environment-on-the-build-host-system&quot;&gt;target environment on the build host system&lt;/h1&gt;
&lt;p&gt;set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})&lt;/p&gt;
&lt;h1 id=&quot;modify-default-behavior-of-find_xxx-commands&quot;&gt;modify default behavior of FIND_XXX() commands&lt;/h1&gt;
&lt;p&gt;set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)Now we can use this script with &lt;code&gt;git-bisect&lt;/code&gt; to find the first bad commit, like this:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;git bisect start&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; git bisect bad v1.1.2
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mn&gt;1.0.0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;git bisect good v1.0.0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1.0.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; git bisect run ./bisect-script.bash
&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;#&amp;#x27; at position 22: …sect visualize #̲ shows a nice s…&quot; style=&quot;color:#cc0000&quot;&gt;git bisect visualize # shows a nice summary&lt;/span&gt; git bisect resetThe bisection led me to this commit: &lt;a href=&quot;https://github.com/duckdb/duckdb/commit/d1ea1538c9217fb536485f1500f04a0b55b1e584&quot;&gt;d1ea1538&lt;/a&gt;. Unfortunately it is not clear how that commit would lead to symbol export failure, it only adds 11 new functions to the C-API (so 11 new symbols). So for now, this debugging journey has to stop here, without a clear resolution. But we did learn a lot of new concepts, and used a wide variety of tools to investigate.&lt;/p&gt;
&lt;h2 id=&quot;what-did-we-learn&quot;&gt;What did we learn?&lt;/h2&gt;
&lt;p&gt;To summarise, the issue is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All releases of &lt;code&gt;DuckDB.jl&lt;/code&gt; after &lt;code&gt;v1.0.0&lt;/code&gt; on Windows are broken.&lt;/li&gt;
&lt;li&gt;We recreate the issue without Julia, which shows the the DuckDB build using the MingW-w64 toolchain is broken for all releases after &lt;code&gt;v1.0.0&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And in the process of debugging this, we learnt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows has a separate mechanism to export symbol names in its shared libraries (DLL).&lt;/li&gt;
&lt;li&gt;We learnt about tools to inspect symbols in native libraries; namely &lt;code&gt;nm&lt;/code&gt;, &lt;code&gt;dumpbin.exe&lt;/code&gt;, and &lt;code&gt;winedump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We learnt about the Julia build system for native libraries (a topic for a future post).&lt;/li&gt;
&lt;li&gt;We learnt to write a script that we can use with &lt;code&gt;git-bisect&lt;/code&gt; to run automatic bisections (a potential topic for a future post).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The story isn’t complete. There will be a concluding part when I actually fix the problem.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;*Cross post from: *&lt;a href=&quot;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md&quot;&gt;&lt;em&gt;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 13 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Faced with a buggy library, most people will just give up and wait for a patch to be released. Certainly not our engineers.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A debugging journey into the unknown (part I)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-debugging-journey-into-the-unknown-par-feee515a.cLSBS6f2_Z1TJWjC.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://science.nasa.gov/image-detail/pia17049-hires/&quot;&gt;&lt;em&gt;NASA/JPL-Caltech&lt;/em&gt;&lt;/a&gt;It all started with a colleague trying to update their Julia environment for one of &lt;a href=&quot;https://github.com/TulipaEnergy&quot;&gt;our projects&lt;/a&gt;. They could not update because a dependency, the Julia bindings for DuckDB, was failing to compile. For the moment we decided to deal with it later, and pinned &lt;code&gt;DuckDB.jl&lt;/code&gt; to the working version. We also filed an issue upstream: &lt;a href=&quot;https://github.com/duckdb/duckdb/issues/13911&quot;&gt;duckdb/duckdb#13911&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since there was no significant progress on the issue for a few months, I decided to dive in once and for all — this is that story.&lt;/p&gt;
&lt;h2 id=&quot;the-issue&quot;&gt;The issue&lt;/h2&gt;
&lt;p&gt;On Windows, trying to install any version of &lt;code&gt;DuckDB.jl&lt;/code&gt; later than &lt;code&gt;1.0.0&lt;/code&gt; was failing with the error:&lt;/p&gt;
&lt;p&gt;ERROR: LoadError: could not load symbol “duckdb_vector_size”:
The specified procedure could not be found.Some Julia packages, like &lt;code&gt;DuckDB.jl&lt;/code&gt; depend on a native library. The native library is an internal dependency, and typically named &lt;code&gt;MyPackage_jll.jl&lt;/code&gt;; in the case of DuckDB, it is &lt;code&gt;DuckDB_jll.jl&lt;/code&gt;. The error above tells us that during the compilation step, Julia tries to load a symbol from the native library, but cannot find it. A “symbol” here refers to a DuckDB C-API function provided by the native DuckDB library.&lt;/p&gt;
&lt;p&gt;So as a first step, I wanted to check: can we actually install this library, and load that symbol? To get the call syntax correct, I looked at the source code of &lt;code&gt;[DuckDB.jl](https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/tools/juliapkg/src/api.jl#L1285-L1297)&lt;/code&gt;&lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/tools/juliapkg/src/api.jl#L1285-L1297&quot;&gt; &lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;function duckdb_vector_size()
return ccall((:duckdb_vector_size, libduckdb), idx_t, ())
endThe variable &lt;code&gt;idx_t&lt;/code&gt; above is defined in &lt;code&gt;ctypes.jl&lt;/code&gt; as:&lt;/p&gt;
&lt;p&gt;const idx_t = UInt64 # DuckDB index typeSo we can test loading the native library like this:&lt;/p&gt;
&lt;p&gt;pkg&gt; add DuckDB_jll
julia&gt; using DuckDB_jll
julia&gt; ccall((:duckdb_vector_size, libduckdb), UInt64, ())The above recipe replicates the error for any version newer than &lt;code&gt;1.0.0&lt;/code&gt;! Hurray! Now that we have confirmation that the problem is in the native library, we have to understand: &lt;em&gt;Why is the symbol not visible to Julia?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;symbol-visibility-in-windows-dlls&quot;&gt;Symbol visibility in Windows DLLs&lt;/h2&gt;
&lt;p&gt;My first hurdle was to find a way to get both versions of the library and compare. I decided to install different versions of the native library &lt;code&gt;DuckDB_jll&lt;/code&gt;in different directories; after loading the library, the &lt;code&gt;libduckdb&lt;/code&gt; variable points to the correct path of the shared library. We can then use other tools to inspect the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic-link_library&quot;&gt;dynamic-link libraries&lt;/a&gt; (DLLs) and check if the symbols actually exist. If we can compare the working version of the native library with a version that does not maybe we can find out what is wrong.&lt;/p&gt;
&lt;p&gt;On Linux, we can use &lt;code&gt;nm&lt;/code&gt; from &lt;code&gt;binutils&lt;/code&gt; to look at the symbols present in the library. Thanks to the &lt;code&gt;-C&lt;/code&gt; flag, &lt;code&gt;nm&lt;/code&gt; can even &lt;a href=&quot;https://en.wikipedia.org/wiki/Name_mangling&quot;&gt;“demangle”&lt;/a&gt; symbol names if necessary. So for the moment we can copy over DLLs from Windows to Linux, and inspect.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;#&amp;#x27; at position 48: …b_vector_size  #̲ working versio…&quot; style=&quot;color:#cc0000&quot;&gt;nm -C libduckdb.dll | grep duckdb_vector_size  # working version: v1.0.0
000000036a271d00 T duckdb_vector_size&lt;/span&gt; nm -C libduckdb.dll | grep duckdb_vector_size  # not working version: e.g. v1.1.2
000000036a36e0e0 T duckdb_vector_size
000000036be998d0 r .rdata$.refptr.duckdb_vector_size
000000036be998d0 R .refptr.duckdb_vector_sizeNo luck 😦, seems that the symbols exist for both versions of the native library. I was puzzled. Searching around I found while building Windows DLLs, you have to explicitly &lt;a href=&quot;https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport&quot;&gt;export symbol names&lt;/a&gt; using the &lt;code&gt;__declspec(dllexport)&lt;/code&gt; attribute. Besides signalling which names are available, it also serves as a mechanism to optimise DLL load times. So I went looking for these attributes in the DuckDB &lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/src/include/duckdb.h#L17-L31&quot;&gt;source code&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;#ifndef DUCKDB_API
#ifdef _WIN32
#ifdef DUCKDB_STATIC_BUILD
#define DUCKDB_API
#else
#if defined(DUCKDB_BUILD_LIBRARY) &amp;#x26;&amp;#x26; !defined(DUCKDB_BUILD_LOADABLE_EXTENSION)
#define DUCKDB_API __declspec(dllexport)
#else
#define DUCKDB_API __declspec(dllimport)
#endif
#endif
#else
#define DUCKDB_API
#endif
#endifYou can see, the &lt;code&gt;#ifdef&lt;/code&gt; directives conditionally defines the macro &lt;code&gt;DUCKDB_API&lt;/code&gt; which expands to &lt;code&gt;__declspec(dllexport)&lt;/code&gt; when building a Windows DLL. Later in the header file, this macro is used to &lt;a href=&quot;https://github.com/duckdb/duckdb/blob/5f5512b827df6397afd31daedb4bbdee76520019/src/include/duckdb.h#L1289-L1295&quot;&gt;mark every C-API function for export&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DUCKDB_API idx_t duckdb_vector_size();Now that we know the C-API function name symbols are marked for export correctly, we should check if they are indeed exported. After some searching, I learnt Windows development tools includes the program &lt;code&gt;dumpbin.exe&lt;/code&gt; that can show the exported symbol names. So I can search for exported symbols in the output.&lt;/p&gt;
&lt;p&gt;Working version of &lt;code&gt;libduckdb.dll&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;&gt; dumpbin.exe /EXPORTS .\bin\libduckdb.dll | findstr duckdb_vector_size
335  14E 0078D1B0 duckdb_vector_sizeFaulty version of &lt;code&gt;libduckdb.dll&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;&gt; dumpbin.exe /EXPORTS .\bin\libduckdb.dll | findstr duckdb_vector_size&lt;/p&gt;
&lt;h1 id=&quot;empty-output-since-nothing-was-foundso-it-is-confirmed-that-the-symbol-export-is-not-working-for-the-faulty-version-however-we-still-do-not-know-which-commit-introduced-the-issue-let-us-try-to-find-that-&quot;&gt;empty output, since nothing was foundSo it is confirmed that the symbol export is not working for the faulty version. However we still do not know which commit introduced the issue. Let us try to find that 🙂.&lt;/h1&gt;
&lt;h2 id=&quot;hunt-for-the-first-bad-commit&quot;&gt;Hunt for the first “bad” commit&lt;/h2&gt;
&lt;p&gt;To be able to find the first bad commit, we need to be able to compile the library. Julia has a whole other infrastructure called &lt;code&gt;[BinaryBuilder](https://binarybuilder.org/)&lt;/code&gt;. It cross-compiles native binaries for all platforms on Linux. This is a whole another rabbit hole, and let us shelve this for another time. The only relevant bit is, the builds are done only* on Linux. This presents a different problem, &lt;code&gt;dumpbin.exe&lt;/code&gt;, the tool to check if the symbol export is correct is available only on Windows. If we are to find the bad commit, we need to automate the build &amp;#x26; check steps and run it with &lt;code&gt;git-bisect&lt;/code&gt;. How can we do that if parts of our toolchain runs on different platforms‽&lt;/p&gt;
&lt;p&gt;So I went searching again for an alternative. Unsurprisingly, Wine (the Windows compatibility layer for Linux) ships with the tool &lt;code&gt;[winedump](https://gitlab.winehq.org/wine/wine/-/wikis/Man-Pages/winedump)&lt;/code&gt;, which is an equivalent to the Windows tool &lt;code&gt;dumpbin.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To build with Windows DLL, we need to cross-compile DuckDB on Linux using the MingW-w64 toolchain. Combined with the &lt;code&gt;winedump&lt;/code&gt; tool, I wrote the following script that we can use to test a successful build.&lt;/p&gt;
&lt;p&gt;#!/bin/bash&lt;/p&gt;
&lt;p&gt;rm -rf build
cmake -B build &lt;br&gt;
-DCMAKE_BUILD_TYPE=Release &lt;br&gt;
-DCMAKE_TOOLCHAIN_FILE=mingw-w64-x86_64.cmake &lt;br&gt;
-DBUILD_EXTENSIONS=‘autocomplete;icu;parquet;json;fts;tpcds;tpch’ &lt;br&gt;
-DENABLE_EXTENSION_AUTOLOADING=1 &lt;br&gt;
-DENABLE_EXTENSION_AUTOINSTALL=1 &lt;br&gt;
-DBUILD_UNITTESTS=FALSE &lt;br&gt;
-DBUILD_SHELL=TRUE &lt;br&gt;
-DDUCKDB_EXPLICIT_PLATFORM=x86_64-w64-mingw32-cxx11 .
cmake —build build&lt;/p&gt;
&lt;p&gt;[[ $? -ne 0 ]] &amp;#x26;&amp;#x26; &lt;br&gt;
{
echo “build failed, cannot test”
exit 125
}&lt;/p&gt;
&lt;p&gt;if [[ -f build/src/libduckdb.dll ]]; then
winedump -j export build/src/libduckdb.dll | grep -q duckdb_vector_size
if [[ $? -eq 0 ]]; then
exit 0
else
exit 1
fi
else
echo “cannot find DLL, cannot test”
exit 125
fiThe script builds DuckDB, and checks whether the generated DLL file export the C-API symbols correctly. It also handles a few corner cases of build failures. Note that the build command uses the following toolchain file (thanks to this &lt;a href=&quot;https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8/&quot;&gt;gist&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)&lt;/p&gt;
&lt;h1 id=&quot;cross-compilers-to-use-for-c-c-and-fortran&quot;&gt;cross compilers to use for C, C++ and Fortran&lt;/h1&gt;
&lt;p&gt;set(CMAKE_C_COMPILER &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;/mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;cc&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;{TOOLCHAIN_PREFIX}-g++)
set(CMAKE_Fortran_COMPILER &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;/mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;{TOOLCHAIN_PREFIX}-windres)&lt;/p&gt;
&lt;h1 id=&quot;target-environment-on-the-build-host-system&quot;&gt;target environment on the build host system&lt;/h1&gt;
&lt;p&gt;set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})&lt;/p&gt;
&lt;h1 id=&quot;modify-default-behavior-of-find_xxx-commands&quot;&gt;modify default behavior of FIND_XXX() commands&lt;/h1&gt;
&lt;p&gt;set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)Now we can use this script with &lt;code&gt;git-bisect&lt;/code&gt; to find the first bad commit, like this:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;git bisect start&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; git bisect bad v1.1.2
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mn&gt;1.0.0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;git bisect good v1.0.0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;bi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1.0.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; git bisect run ./bisect-script.bash
&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;#&amp;#x27; at position 22: …sect visualize #̲ shows a nice s…&quot; style=&quot;color:#cc0000&quot;&gt;git bisect visualize # shows a nice summary&lt;/span&gt; git bisect resetThe bisection led me to this commit: &lt;a href=&quot;https://github.com/duckdb/duckdb/commit/d1ea1538c9217fb536485f1500f04a0b55b1e584&quot;&gt;d1ea1538&lt;/a&gt;. Unfortunately it is not clear how that commit would lead to symbol export failure, it only adds 11 new functions to the C-API (so 11 new symbols). So for now, this debugging journey has to stop here, without a clear resolution. But we did learn a lot of new concepts, and used a wide variety of tools to investigate.&lt;/p&gt;
&lt;h2 id=&quot;what-did-we-learn&quot;&gt;What did we learn?&lt;/h2&gt;
&lt;p&gt;To summarise, the issue is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All releases of &lt;code&gt;DuckDB.jl&lt;/code&gt; after &lt;code&gt;v1.0.0&lt;/code&gt; on Windows are broken.&lt;/li&gt;
&lt;li&gt;We recreate the issue without Julia, which shows the the DuckDB build using the MingW-w64 toolchain is broken for all releases after &lt;code&gt;v1.0.0&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And in the process of debugging this, we learnt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows has a separate mechanism to export symbol names in its shared libraries (DLL).&lt;/li&gt;
&lt;li&gt;We learnt about tools to inspect symbols in native libraries; namely &lt;code&gt;nm&lt;/code&gt;, &lt;code&gt;dumpbin.exe&lt;/code&gt;, and &lt;code&gt;winedump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We learnt about the Julia build system for native libraries (a topic for a future post).&lt;/li&gt;
&lt;li&gt;We learnt to write a script that we can use with &lt;code&gt;git-bisect&lt;/code&gt; to run automatic bisections (a potential topic for a future post).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The story isn’t complete. There will be a concluding part when I actually fix the problem.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;*Cross post from: *&lt;a href=&quot;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md&quot;&gt;&lt;em&gt;https://github.com/suvayu/suvayu/blob/master/blog/2025-02-15-duckdb-julia-windows.md&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-debugging-journey-into-the-unknown-par-feee515a.cLSBS6f2.jpeg" medium="image"/><author>Suvayu</author></item><item><title>Sharing MATLAB models with everyone</title><link>https://blog.esciencecenter.nl/posts/2025-03-12---sharing-matlab-models-with-everyone</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-03-12---sharing-matlab-models-with-everyone</guid><description>&lt;p&gt;MATLAB is still commonly used in many scientific fields, despite its closed-source nature. While many (technical) universities used to teach coding using MATLAB, more and more are moving away from it, preferring open-source and free alternatives such as Python or Julia. O&lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;ne of the main reasons Julia was developed&lt;/a&gt; was because of MATLAB’s proprietary and closed software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-e5b6ed0c.DWmPeRbD_1MP8vq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ivvndiaz?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Iván Díaz&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;However, for those with a vested interest in the language, such as a large legacy code base, &lt;a href=&quot;https://medium.com/escience-center/how-to-ensure-that-others-can-run-your-code-4c7672524a69&quot;&gt;it is still important to be able to share your models&lt;/a&gt;. Just sharing MATLAB code is not that useful as it requires the users to have a MATLAB license. For &lt;a href=&quot;https://research-software-directory.org/projects/ecoextreml&quot;&gt;a project&lt;/a&gt; with the University of Twente, we work on [a MATLAB land-surface model](&lt;a href=&quot;https://github.com/Eco&quot;&gt;https://github.com/Eco&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ExtreML/STEMMUS_SCOPE/). We wanted to make the model open-source and available for anyone to run, as well as allow interaction with the model through a &lt;a href=&quot;https://bmi.readthedocs.io&quot;&gt;Basic Model Interface&lt;/a&gt;, a standardized interface for numerical models.&lt;/p&gt;
&lt;p&gt;One option would be to try GNU Octave, a language that is mostly compatible with MATLAB. The key word being &lt;em&gt;mostly&lt;/em&gt;*. For us, the difference in execution time was too large. The second option is to make use of MATLAB Runtime.&lt;/p&gt;
&lt;h2 id=&quot;matlab-runtime&quot;&gt;MATLAB Runtime&lt;/h2&gt;
&lt;p&gt;With &lt;a href=&quot;https://nl.mathworks.com/products/compiler/matlab-runtime.html&quot;&gt;MATLAB Runtime&lt;/a&gt; anyone can run MATLAB applications or components without installing MATLAB. You generate an executable file on a system &lt;em&gt;with&lt;/em&gt; a MATLAB license, which you can then run on a system &lt;em&gt;without&lt;/em&gt; a license. This does require that the target system has the same operating system and architecture as the system that generated the executable file.&lt;/p&gt;
&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;/h2&gt;
&lt;p&gt;This is where Docker comes into play. Docker allows you to package your application together with a minimal operating system and any dependencies, such that it can run as a standalone application. Note that you can also use Apptainer, an open-source alternative.&lt;/p&gt;
&lt;p&gt;Lucky for us, &lt;a href=&quot;https://github.com/demartis/MATLAB_runtime_docker&quot;&gt;someone already did the work of containerizing MATLAB Runtime&lt;/a&gt;. Thanks Riccardo De Martis! A quick example is in the following Dockerfile:&lt;/p&gt;
&lt;h1 id=&quot;we-start-from-the-already-existing-matlab-runtime-container&quot;&gt;We start from the already-existing MATLAB Runtime container:&lt;/h1&gt;
&lt;p&gt;FROM demartis/matlab-runtime:R2023a&lt;/p&gt;
&lt;h1 id=&quot;put-the-executable-in-the-container-for-example-from-github&quot;&gt;Put the executable in the container, for example from GitHub:&lt;/h1&gt;
&lt;p&gt;RUN wget &lt;a href=&quot;https://github.com/MyOrganization/MyRepo/raw/main/exe/MATLAB_MODEL&quot;&gt;https://github.com/MyOrganization/MyRepo/raw/main/exe/MATLAB_MODEL&lt;/a&gt; - no-check-certificate&lt;/p&gt;
&lt;h1 id=&quot;make-sure-the-file-is-executable&quot;&gt;Make sure the file is executable&lt;/h1&gt;
&lt;p&gt;RUN chmod +x ./MATLAB_MODEL&lt;/p&gt;
&lt;h1 id=&quot;allow-mcr-to-have-a-cache-directory-which-all-users-can-access&quot;&gt;Allow MCR to have a cache directory which all users can access&lt;/h1&gt;
&lt;h1 id=&quot;this-allows-for-executing-the-model-as-a-different-user&quot;&gt;this allows for executing the model as a different user.&lt;/h1&gt;
&lt;p&gt;RUN mkdir /temp/
RUN chmod 777 /temp/
ENV MCR_CACHE_ROOT /temp/&lt;/p&gt;
&lt;h1 id=&quot;run-the-model&quot;&gt;Run the model:&lt;/h1&gt;
&lt;p&gt;CMD ./MATLAB_MODELNotice that the MATLAB Runtime container is based on Debian, so you need to generate your executable file on a Linux system as well. On the flip side, once the container is built, it will be easy to run it on different systems, as well as in parallel (such as scaling up your analysis on HPC, where more computational power and data is available).&lt;/p&gt;
&lt;h2 id=&quot;interacting-with-the-containerized-model&quot;&gt;Interacting with the containerized model&lt;/h2&gt;
&lt;p&gt;For many users, this will be good enough: you simply run the model once, passing a config file as an argument, and you’re done. If the model needs access to data, you can attach those directories to the container. The model’s output will be written to a file.&lt;/p&gt;
&lt;p&gt;A more advanced use case is when you want to interact with the model while* it is running, such as with the Basic Model Interface mentioned earlier. For this, you will need to communicate with the running MATLAB code.&lt;/p&gt;
&lt;p&gt;Communicating with the model inside the directory &lt;em&gt;can&lt;/em&gt; be done using the terminal, but more ideal would be a proper interface. If you set up &lt;a href=&quot;https://www.mathworks.com/matlabcentral/fileexchange/29027-web-server&quot;&gt;a MATLAB HTTP server&lt;/a&gt;, you can expose the server’s port inside the container. This then allows you to start the HTTP server and execute the MATLAB code from outside the container.&lt;/p&gt;
&lt;h3 id=&quot;data-exchange&quot;&gt;Data exchange&lt;/h3&gt;
&lt;p&gt;While telling the model to run certain routines is straightforward using an HTTP server, data exchange is a bit more complex. A simpler way is to write the model’s state or parameters of interest to file.&lt;/p&gt;
&lt;p&gt;MATLAB’s default file format is HDF5 nowadays, which is supported by most other languages (for example, Julia with HDF5.jl, or Python with h5py). Scripts or programs written in these other languages can then interact with this file, which can be loaded again in MATLAB if two-way communication is required.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-3dd8c2ff.Cb2yxATD_PpHsa.webp&quot; srcset=&quot;&quot;&gt;
Communicating with a containerized MATLAB model through Python&lt;/p&gt;
&lt;h2 id=&quot;example-stemmus_scope-basic-model-interface&quot;&gt;Example: STEMMUS_SCOPE Basic Model Interface&lt;/h2&gt;
&lt;p&gt;A working example of a containerized MATLAB model is &lt;a href=&quot;https://github.com/EcoExtreML/STEMMUS_SCOPE&quot;&gt;STEMMUS_SCOPE&lt;/a&gt;, a land surface model. We wanted to write a &lt;a href=&quot;https://csdms.colorado.edu/wiki/BMI&quot;&gt;Basic Model Interface&lt;/a&gt; (BMI), to allow for coupling the model to other models such as the groundwater model MODFLOW.&lt;/p&gt;
&lt;p&gt;However, coupling a MATLAB model to models written in a different language is challenging, so we &lt;a href=&quot;https://github.com/EcoExtreML/STEMMUS_SCOPE_Processing/tree/v0.4.0/PyStemmusScope/bmi&quot;&gt;connected a Python BMI to the containerized model&lt;/a&gt;, as Python excels at being a “glue” language. This allows us to couple the STEMMUS_SCOPE model with other models implementing a BMI.&lt;/p&gt;
&lt;p&gt;One detail here is that we did not have access to a full MATLAB IDE, so it was too challenging to actually go the proper route and implement an HTTP server for STEMMUS_SCOPE. Instead, we communicate to the MATLAB processing using stdin/stdout.&lt;/p&gt;
&lt;h2 id=&quot;sharing-is-caring&quot;&gt;Sharing is caring&lt;/h2&gt;
&lt;p&gt;While it’s certainly more difficult than with many other programming languages, sharing easily (re-)usable MATLAB code with others is still possible. Not only that, but it can also make your own life easier by being able to run your code on other platforms and allowing you to run it in a single command.&lt;/p&gt;
&lt;p&gt;If you enjoyed this story, have a look at the blogpost “&lt;a href=&quot;https://medium.com/escience-center/how-to-ensure-that-others-can-run-your-code-4c7672524a69&quot;&gt;How to ensure that others can run your code&lt;/a&gt;” by Julian Gonggrijp, which touches on many reasons why* *you would want to make sure others can run your code (and how).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-c9e37c82.CatIam-l_ZFm20b.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@j0shuadcampbell?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Josh Campbell&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;*** Octave does not support all MATLAB functions, so the code will have to be modified to support both MATLAB and Octave. Octave can also be an order of magnitude slower than MATLAB, which can be problematic.&lt;/p&gt;</description><pubDate>Wed, 12 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;MATLAB is still commonly used in many scientific fields, despite its closed-source nature. While many (technical) universities used to teach coding using MATLAB, more and more are moving away from it, preferring open-source and free alternatives such as Python or Julia. O&lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;ne of the main reasons Julia was developed&lt;/a&gt; was because of MATLAB’s proprietary and closed software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-e5b6ed0c.DWmPeRbD_1MP8vq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ivvndiaz?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Iván Díaz&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;However, for those with a vested interest in the language, such as a large legacy code base, &lt;a href=&quot;https://medium.com/escience-center/how-to-ensure-that-others-can-run-your-code-4c7672524a69&quot;&gt;it is still important to be able to share your models&lt;/a&gt;. Just sharing MATLAB code is not that useful as it requires the users to have a MATLAB license. For &lt;a href=&quot;https://research-software-directory.org/projects/ecoextreml&quot;&gt;a project&lt;/a&gt; with the University of Twente, we work on [a MATLAB land-surface model](&lt;a href=&quot;https://github.com/Eco&quot;&gt;https://github.com/Eco&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ExtreML/STEMMUS_SCOPE/). We wanted to make the model open-source and available for anyone to run, as well as allow interaction with the model through a &lt;a href=&quot;https://bmi.readthedocs.io&quot;&gt;Basic Model Interface&lt;/a&gt;, a standardized interface for numerical models.&lt;/p&gt;
&lt;p&gt;One option would be to try GNU Octave, a language that is mostly compatible with MATLAB. The key word being &lt;em&gt;mostly&lt;/em&gt;*. For us, the difference in execution time was too large. The second option is to make use of MATLAB Runtime.&lt;/p&gt;
&lt;h2 id=&quot;matlab-runtime&quot;&gt;MATLAB Runtime&lt;/h2&gt;
&lt;p&gt;With &lt;a href=&quot;https://nl.mathworks.com/products/compiler/matlab-runtime.html&quot;&gt;MATLAB Runtime&lt;/a&gt; anyone can run MATLAB applications or components without installing MATLAB. You generate an executable file on a system &lt;em&gt;with&lt;/em&gt; a MATLAB license, which you can then run on a system &lt;em&gt;without&lt;/em&gt; a license. This does require that the target system has the same operating system and architecture as the system that generated the executable file.&lt;/p&gt;
&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;/h2&gt;
&lt;p&gt;This is where Docker comes into play. Docker allows you to package your application together with a minimal operating system and any dependencies, such that it can run as a standalone application. Note that you can also use Apptainer, an open-source alternative.&lt;/p&gt;
&lt;p&gt;Lucky for us, &lt;a href=&quot;https://github.com/demartis/MATLAB_runtime_docker&quot;&gt;someone already did the work of containerizing MATLAB Runtime&lt;/a&gt;. Thanks Riccardo De Martis! A quick example is in the following Dockerfile:&lt;/p&gt;
&lt;h1 id=&quot;we-start-from-the-already-existing-matlab-runtime-container&quot;&gt;We start from the already-existing MATLAB Runtime container:&lt;/h1&gt;
&lt;p&gt;FROM demartis/matlab-runtime:R2023a&lt;/p&gt;
&lt;h1 id=&quot;put-the-executable-in-the-container-for-example-from-github&quot;&gt;Put the executable in the container, for example from GitHub:&lt;/h1&gt;
&lt;p&gt;RUN wget &lt;a href=&quot;https://github.com/MyOrganization/MyRepo/raw/main/exe/MATLAB_MODEL&quot;&gt;https://github.com/MyOrganization/MyRepo/raw/main/exe/MATLAB_MODEL&lt;/a&gt; - no-check-certificate&lt;/p&gt;
&lt;h1 id=&quot;make-sure-the-file-is-executable&quot;&gt;Make sure the file is executable&lt;/h1&gt;
&lt;p&gt;RUN chmod +x ./MATLAB_MODEL&lt;/p&gt;
&lt;h1 id=&quot;allow-mcr-to-have-a-cache-directory-which-all-users-can-access&quot;&gt;Allow MCR to have a cache directory which all users can access&lt;/h1&gt;
&lt;h1 id=&quot;this-allows-for-executing-the-model-as-a-different-user&quot;&gt;this allows for executing the model as a different user.&lt;/h1&gt;
&lt;p&gt;RUN mkdir /temp/
RUN chmod 777 /temp/
ENV MCR_CACHE_ROOT /temp/&lt;/p&gt;
&lt;h1 id=&quot;run-the-model&quot;&gt;Run the model:&lt;/h1&gt;
&lt;p&gt;CMD ./MATLAB_MODELNotice that the MATLAB Runtime container is based on Debian, so you need to generate your executable file on a Linux system as well. On the flip side, once the container is built, it will be easy to run it on different systems, as well as in parallel (such as scaling up your analysis on HPC, where more computational power and data is available).&lt;/p&gt;
&lt;h2 id=&quot;interacting-with-the-containerized-model&quot;&gt;Interacting with the containerized model&lt;/h2&gt;
&lt;p&gt;For many users, this will be good enough: you simply run the model once, passing a config file as an argument, and you’re done. If the model needs access to data, you can attach those directories to the container. The model’s output will be written to a file.&lt;/p&gt;
&lt;p&gt;A more advanced use case is when you want to interact with the model while* it is running, such as with the Basic Model Interface mentioned earlier. For this, you will need to communicate with the running MATLAB code.&lt;/p&gt;
&lt;p&gt;Communicating with the model inside the directory &lt;em&gt;can&lt;/em&gt; be done using the terminal, but more ideal would be a proper interface. If you set up &lt;a href=&quot;https://www.mathworks.com/matlabcentral/fileexchange/29027-web-server&quot;&gt;a MATLAB HTTP server&lt;/a&gt;, you can expose the server’s port inside the container. This then allows you to start the HTTP server and execute the MATLAB code from outside the container.&lt;/p&gt;
&lt;h3 id=&quot;data-exchange&quot;&gt;Data exchange&lt;/h3&gt;
&lt;p&gt;While telling the model to run certain routines is straightforward using an HTTP server, data exchange is a bit more complex. A simpler way is to write the model’s state or parameters of interest to file.&lt;/p&gt;
&lt;p&gt;MATLAB’s default file format is HDF5 nowadays, which is supported by most other languages (for example, Julia with HDF5.jl, or Python with h5py). Scripts or programs written in these other languages can then interact with this file, which can be loaded again in MATLAB if two-way communication is required.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-3dd8c2ff.Cb2yxATD_PpHsa.webp&quot; srcset=&quot;&quot;&gt;
Communicating with a containerized MATLAB model through Python&lt;/p&gt;
&lt;h2 id=&quot;example-stemmus_scope-basic-model-interface&quot;&gt;Example: STEMMUS_SCOPE Basic Model Interface&lt;/h2&gt;
&lt;p&gt;A working example of a containerized MATLAB model is &lt;a href=&quot;https://github.com/EcoExtreML/STEMMUS_SCOPE&quot;&gt;STEMMUS_SCOPE&lt;/a&gt;, a land surface model. We wanted to write a &lt;a href=&quot;https://csdms.colorado.edu/wiki/BMI&quot;&gt;Basic Model Interface&lt;/a&gt; (BMI), to allow for coupling the model to other models such as the groundwater model MODFLOW.&lt;/p&gt;
&lt;p&gt;However, coupling a MATLAB model to models written in a different language is challenging, so we &lt;a href=&quot;https://github.com/EcoExtreML/STEMMUS_SCOPE_Processing/tree/v0.4.0/PyStemmusScope/bmi&quot;&gt;connected a Python BMI to the containerized model&lt;/a&gt;, as Python excels at being a “glue” language. This allows us to couple the STEMMUS_SCOPE model with other models implementing a BMI.&lt;/p&gt;
&lt;p&gt;One detail here is that we did not have access to a full MATLAB IDE, so it was too challenging to actually go the proper route and implement an HTTP server for STEMMUS_SCOPE. Instead, we communicate to the MATLAB processing using stdin/stdout.&lt;/p&gt;
&lt;h2 id=&quot;sharing-is-caring&quot;&gt;Sharing is caring&lt;/h2&gt;
&lt;p&gt;While it’s certainly more difficult than with many other programming languages, sharing easily (re-)usable MATLAB code with others is still possible. Not only that, but it can also make your own life easier by being able to run your code on other platforms and allowing you to run it in a single command.&lt;/p&gt;
&lt;p&gt;If you enjoyed this story, have a look at the blogpost “&lt;a href=&quot;https://medium.com/escience-center/how-to-ensure-that-others-can-run-your-code-4c7672524a69&quot;&gt;How to ensure that others can run your code&lt;/a&gt;” by Julian Gonggrijp, which touches on many reasons why* *you would want to make sure others can run your code (and how).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sharing MATLAB models with everyone&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-c9e37c82.CatIam-l_ZFm20b.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@j0shuadcampbell?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Josh Campbell&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;*** Octave does not support all MATLAB functions, so the code will have to be modified to support both MATLAB and Octave. Octave can also be an order of magnitude slower than MATLAB, which can be problematic.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/sharing-matlab-models-with-everyone-e5b6ed0c.DWmPeRbD.jpg" medium="image"/><author>Bart Schilperoort</author></item><item><title>A Helpful Noob</title><link>https://blog.esciencecenter.nl/posts/2025-02-21---a-helpful-noob</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-02-21---a-helpful-noob</guid><description>&lt;p&gt;&lt;img alt=&quot;A Helpful Noob&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-helpful-noob-a2f448b4.lQj8rzQD_Z2cSNID.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@keiteu_ko?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Keiteu Ko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Yesterday, my colleague &lt;a href=&quot;https://github.com/fdiblen&quot;&gt;Faruk&lt;/a&gt; asked me to conduct a Hallway Test for the &lt;code&gt;[NLeSC/python-template](https://github.com/NLeSC/python-template)&lt;/code&gt; he is working on: he just grabbed me off the hallway and asked me to give it a spin. This is, however, not a story about the test, but of open-source intelligence (OSINT) and the contributions of yet another “helpful noob”.&lt;/p&gt;
&lt;p&gt;Right after I posted my feedback in an &lt;a href=&quot;https://github.com/NLeSC/python-template/issues/554&quot;&gt;issue&lt;/a&gt; of the project, someone else posted a helpful contribution right underneath:&lt;/p&gt;
&lt;p&gt;GitHub comment from xiaobai-marker, with edited link so y’all don’t get any funny ideasHuh? It took this person only a few seconds to post a fix for quite a list of small changes that I posted. That’s so nice! So let’s do a review of &lt;em&gt;their&lt;/em&gt; contributions.&lt;/p&gt;
&lt;h2 id=&quot;trail-github&quot;&gt;Trail: GitHub&lt;/h2&gt;
&lt;p&gt;Their GitHub handle is &lt;code&gt;xiaobai-marker&lt;/code&gt;. XiaoBai is (Pinyin writing of) Chinese and translates to “little white”, not referring to the actual color, but more in the direction of “unsullied”. It means Little Noob.&lt;/p&gt;
&lt;p&gt;A brief dive into &lt;code&gt;xiaobai-marker&lt;/code&gt; ‘s GitHub profile (by now mysteriously removed) confirms this initial impression.&lt;/p&gt;
&lt;p&gt;GitHub profile of &lt;code&gt;xiaobai-marker&lt;/code&gt;They forked only three publicly available repositories. They apparently deal with self-driving toy cars and machine learning to detect road lanes. Fun! However, that’s not a lot of content for someone who seems to contribute to other projects, especially considering that they did not open any repositories themselves.&lt;/p&gt;
&lt;p&gt;But we’re not judging. Any contributions are welcome, and that includes those from people with little experience. So let’s have a look at their actual contribution.&lt;/p&gt;
&lt;h2 id=&quot;trail-download-link&quot;&gt;Trail: Download Link&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mediafire.com&quot;&gt;MediaFire&lt;/a&gt; is a known file storage and sharing website. Clicking &lt;em&gt;this&lt;/em&gt; link is not &lt;em&gt;per se&lt;/em&gt; dangerous. Still, we proceed with caution.&lt;/p&gt;
&lt;p&gt;MediaFire download pageMediaFire uses VirusTotal to scan for malicious files. This inspires confidence, right? An encrypted &lt;code&gt;*.zip&lt;/code&gt; file, however, is opaque to any scans since we can’t look inside without the password, which was supplied on GitHub and is not known to MediaFire or VirusTotal. Another interesting detail is where the file comes from. Apparently it was uploaded the same day from somewhere in Russia. Is our Little Noob from Russia?&lt;/p&gt;
&lt;p&gt;Let’s check out the files now.&lt;/p&gt;
&lt;h2 id=&quot;trail-files&quot;&gt;Trail: Files&lt;/h2&gt;
&lt;p&gt;What did we actually download? A rather small zip file.&lt;/p&gt;
&lt;p&gt;$ ls -lah fix.zip
-rw-r—r— 1 ole users 367K Aug 27 08:15 fix.zipProviding the password, we can unpack it and have a look at the content.&lt;/p&gt;
&lt;p&gt;$ 7z e -pchangeme fix.zip&lt;/p&gt;
&lt;p&gt;7-Zip [64] 17.05 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28
p7zip Version 17.05 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs x64)&lt;/p&gt;
&lt;p&gt;Scanning the drive for archives:
1 file, 375771 bytes (367 KiB)&lt;/p&gt;
&lt;h2 id=&quot;extracting-archive-fixzip&quot;&gt;Extracting archive: fix.zip&lt;/h2&gt;
&lt;p&gt;Path = fix.zip
Type = zip
Physical Size = 375771&lt;/p&gt;
&lt;p&gt;Everything is Ok&lt;/p&gt;
&lt;p&gt;Folders: 1
Files: 2
Size:       747008
Compressed: 375771What did we just unpack?&lt;/p&gt;
&lt;p&gt;$ ls -lah fix/
total 456K
-rw-r—r— 1 ole users 490K Aug 27 08:15 msvcp140.dll
-rw-r—r— 1 ole users 240K Aug 27 08:15 x86_64-w64-ranlib.exeHuh. &lt;code&gt;ranlib&lt;/code&gt; is a standard programming tool, although here it is supposed to be an installer (!). This “fix” seems to have been written for a Windows system. I can’t run it on my Linux machine. Bummer. I’m also not very good at decompiling &lt;code&gt;*.exe&lt;/code&gt; files to check what’s really inside. But we can ask some websites for assistance.&lt;/p&gt;
&lt;h3 id=&quot;virustotal&quot;&gt;VirusTotal&lt;/h3&gt;
&lt;p&gt;First we upload the file to &lt;a href=&quot;https://virustotal.com&quot;&gt;virustotal.com&lt;/a&gt;, a Google-owned file and link analyzer and one of the authorities in the space of malware indexing. On the day of the initial analysis, 28 of 75 security vendors &lt;a href=&quot;https://www.virustotal.com/gui/file/546c34c2782216278a8273d3c9d3a954a980c7c2c7be220914aefe446fe94fd8/detection&quot;&gt;flagged the files as malicious&lt;/a&gt;. You don’t say! One day later this number is up to 35. It seems to be a fresh strain that is quickly being picked up by the security community.&lt;/p&gt;
&lt;p&gt;VirusTotal analysisSo what do we have here? “Trojan”? “MalwareX”? This is still quite vague.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Fun fact: One of the analyses — fourth row, right side — comes from CrowdStrike. Those are guys that &lt;em&gt;&lt;a href=&quot;https://arstechnica.com/information-technology/2024/07/major-outages-at-crowdstrike-microsoft-leave-the-world-with-bsods-and-confusion/&quot;&gt;&lt;em&gt;crashed&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; some &lt;em&gt;&lt;a href=&quot;https://blogs.microsoft.com/blog/2024/07/20/helping-our-customers-through-the-crowdstrike-outage/&quot;&gt;&lt;em&gt;8.5 million rather important Windows computers&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, resulting in &lt;em&gt;&lt;a href=&quot;https://www.oxfordeconomics.com/resource/crowdstrike-update-grounds-thousands-of-flights/&quot;&gt;&lt;em&gt;over 10.000 cancelled flights&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and causing &lt;em&gt;&lt;a href=&quot;https://www.neowin.net/news/systems-paralyzed-by-crowdstrike-within-78-minutes-to-cause-15-billion-in-losses-worldwide/&quot;&gt;&lt;em&gt;some $15 billion damages worldwide&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in July 2024. Oops.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;triage&quot;&gt;Tria.ge&lt;/h3&gt;
&lt;p&gt;Triage provides a malware analysis sandbox and provides reports for submitted samples. Some kind soul already &lt;a href=&quot;https://tria.ge/240826-vhsrtawepj/behavioral4&quot;&gt;uploaded the one we found&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Triage analysis summary“Lumma”? “Stealer”? What’s that? Apparently this malware tries to steal…​ things? Let’s look into this.&lt;/p&gt;
&lt;p&gt;Some more interesting details can be found further down in the network section of the analysis. What’s a malware to do after it did its deeds? It has to send the stuff it found &lt;em&gt;somewhere&lt;/em&gt;, right? So Triage ran the malware in a sandbox and recorded the network traffic. These are some of the connections the malware made:&lt;/p&gt;
&lt;p&gt;Triage analysis network traffic&lt;code&gt;froytnewqowv.shop&lt;/code&gt; seems to be the URL of the Command-and-Control (C2) server of this malware. It tells the malware what to do and collects the bountiful harvest. Also take note of the &lt;code&gt;froytnewqowv.shop/api&lt;/code&gt; path that we will explore in a minute.&lt;/p&gt;
&lt;h2 id=&quot;trail-c2-server&quot;&gt;Trail: C2 server&lt;/h2&gt;
&lt;p&gt;Let’s see if we can find out more about who our malware talks to. WHO IS the one that owns the weird domain name?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“WHOIS is a public database that houses the information collected when someone registers a domain name”
— &lt;a href=&quot;https://www.domain.com/blog/what-is-whois-and-how-is-it-used/&quot;&gt;https://www.domain.com/blog/what-is-whois-and-how-is-it-used/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;whois&quot;&gt;WhoIs&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.whois.com/whois/froytnewqowv.shop&quot;&gt;whois&lt;/a&gt; look-up shows that the domain was registered just a few days ago via &lt;a href=&quot;https://www.namecheap.com/&quot;&gt;namecheap.com&lt;/a&gt;. This register hides the client’s contact information, like physical address or email.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;whois&lt;/code&gt; lookup of &lt;code&gt;the URL froytnewqowv.shop&lt;/code&gt;Furthermore, we see from the “Name Server” entries that they hide behind &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare&lt;/a&gt;. This service can, among other things, act as an intermediary between a user and a website. This means that we cannot directly find out the IP address — the “actual address” that the URL is translated into — of the C2 server, since all the traffic is routed through Cloudflare’s machines first.&lt;/p&gt;
&lt;p&gt;Little Noob is privacy-conscious.&lt;/p&gt;
&lt;p&gt;Let’s give the C2 server a visit then. We open the website in a browser.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note that it’s usually not a good idea to browse possibly malicious sites, since they can* infect your computer.&lt;/p&gt;
&lt;h3 id=&quot;browsing-the-c2-website&quot;&gt;Browsing the C2 website&lt;/h3&gt;
&lt;p&gt;Opening the URL in a browser lets us see:&lt;/p&gt;
&lt;p&gt;Visiting the C2 serverWell, that’s not much. This is the default landing page of their &lt;code&gt;nginx&lt;/code&gt; web server, with no content whatsoever. Let’s have a look at the source code of this website then, by pressing &lt;code&gt;CTRL+U&lt;/code&gt; in the browser.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;html&gt;
&amp;#x3C;head&gt;&amp;#x3C;title&gt;405 Not Allowed&amp;#x3C;/title&gt;&amp;#x3C;/head&gt;
&amp;#x3C;body&gt;
&amp;#x3C;center&gt;&amp;#x3C;h1&gt;405 Not Allowed&amp;#x3C;/h1&gt;&amp;#x3C;/center&gt;
&amp;#x3C;hr&gt;&amp;#x3C;center&gt;nginx/1.18.0 (Ubuntu)&amp;#x3C;/center&gt;
&amp;#x3C;/body&gt;
&amp;#x3C;/html&gt;Ah yes. Privacy conscious. At least we learn that the server runs &lt;code&gt;nginx&lt;/code&gt; version &lt;code&gt;1.18.0&lt;/code&gt; on Ubuntu.&lt;/p&gt;
&lt;p&gt;If we look back at the network section of the Triage analysis, we see that the malware made a request to the &lt;code&gt;/api&lt;/code&gt; path. API stands for Application Programming Interface **and is basically a somewhat standardized interface for talking to computers programmatically. What does that API path look like in the browser?&lt;/p&gt;
&lt;p&gt;API pathI guess I’m not invited to that party. Let’s explore the website a bit more and guess some other paths.&lt;/p&gt;
&lt;p&gt;404 pageNope. Not that easy, apparently. &lt;code&gt;404&lt;/code&gt; is browser-speak for “I can’t find what you asked of me”. Let’s see what Google knows about this URL.&lt;/p&gt;
&lt;p&gt;Google search for the C2 URLAha. Another path: &lt;code&gt;/apib&lt;/code&gt;. Where does this lead to?&lt;/p&gt;
&lt;p&gt;A different 404 page? Hmm…Another dead end? But this one look different. Russian again. How come? After trying some more URLs by hand, it is apparent that everything that starts with &lt;code&gt;/api&lt;/code&gt; is leading to this &lt;em&gt;other&lt;/em&gt; 404-not-found page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/apia&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/apib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api_I_misconfigured_my_nginx_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see what we can learn from this page. Translation:&lt;/p&gt;
&lt;p&gt;404**
Oops… There was a mistake&lt;/p&gt;
&lt;p&gt;Sorry, this page was not found or the administrator has closed access to it&lt;/p&gt;
&lt;p&gt;&amp;#x3C;- To the main pageNo surprises here. Let’s download the whole thing and see what we get.&lt;/p&gt;
&lt;h3 id=&quot;website-source-code&quot;&gt;Website source code&lt;/h3&gt;
&lt;p&gt;The website source contains the following files:&lt;/p&gt;
&lt;p&gt;$ tree
.
├── Ошибка_files
│   ├── dober.html
│   ├── doberman.min.html
│   ├── jquery-3.6.0.min.js
│   ├── tabler-flags.min.css
│   ├── tabler-icons.min.css
│   ├── tabler.min.css
│   ├── tabler.min.js
│   ├── tabler-payments.min.css
│   ├── tabler-vendors.min.css
│   ├── tom-select.complete.min.js
│   └── tom-select.css
└── Ошибка.htmlOur error page seems to have been built with &lt;a href=&quot;https://tabler.io/&quot;&gt;tabler.io&lt;/a&gt;. This seems to be a bit too much effort for a simple 404 page. Tabler is often used to build elaborate dashboards. So there’s probably more to it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;css&lt;/code&gt; files are Cascading Style Sheets (CSS), which are used for styling a web page. Not too interesting. &lt;code&gt;[tom-select](https://tom-select.js.org/)&lt;/code&gt; is a standard JavaScript framework for UI control. &lt;code&gt;[jquery](https://jquery.com/)&lt;/code&gt; is a library to simplify HTML development, assisting with document traversal and other things.&lt;/p&gt;
&lt;p&gt;The interesting ones that remain are &lt;code&gt;dober.html&lt;/code&gt; and &lt;code&gt;doberman.min.html&lt;/code&gt;. What are those? Let’s have a look.&lt;/p&gt;
&lt;p&gt;The content of &lt;code&gt;dober.html&lt;/code&gt; is one single line of text which looks like this:&lt;/p&gt;
&lt;p&gt;&amp;#x3C;!DOCTYPE html&gt;&amp;#x3C;html lang=“en-US”&gt;&amp;#x3C;head&gt;&amp;#x3C;title&gt;Just a moment…&amp;#x3C;/title&gt;&amp;#x3C;meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”&gt;&amp;#x3C;meta http-equiv=“X-UA-Compatible” content=“IE=Edge”&gt;&amp;#x3C;meta name=“robots” content=“noindex,nofollow”&gt;&amp;#x3C;meta name=“viewport” content=“width=device-width,initial-scale=1”&gt;&amp;#x3C;style&gt;*{box-sizing:border-box;margin:0;padding:0}html{line-height:1.15;-webkit-text-size-adjust:100%;color:#313131}button,html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}@media (prefers-color-sch…Urgh. This HTML vomit is “minified”, which means it is condensed as much as possible to save bandwidth when opening a website. This makes it hard to read for us humans, though. Luckily we can get some help with disentangling it.&lt;/p&gt;
&lt;h3 id=&quot;unminifycom&quot;&gt;Unminify.com&lt;/h3&gt;
&lt;p&gt;While there are Integrated Development Environments (IDEs) that can disentangle minified HTML, there are also websites that do this for you with a click of a button.&lt;/p&gt;
&lt;p&gt;Unminifying HTML code, making it readable and prettyThe code in the screenshot above is now much more readable. Below in the unminified code of &lt;code&gt;doberman.min.html&lt;/code&gt; we can find a reference to a file that does not seem to exist. An excerpt of &lt;code&gt;doberman.min.html&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&amp;#x3C;script&gt;
(function () {
window._cf_chl_opt = {
cvId: “3”,
cZone: “froytnewqowv.shop”,
cType: “interactive”,
cNounce: “11691”,
cRay: “8b96971bcef66608”,
cHash: “a7c37071216d981”,
cUPMDTk: “/core/panel/js/doberman.min.js?2&amp;#x26;__cf_chl_tk=POTzyU0ftLF9cvsIaAitlr5np8LsKoghhsVMME6MjWg-1724704337-0.0.1.1-2559”,Where is this file &lt;code&gt;/core/panel/js/doberman.min.js&lt;/code&gt; referenced here? It was not downloaded with the rest. Is it being dynamically created and loaded? I would not know without more time to study it. Again, luckily, other people already did the hard work for us. Searching for this file string on Google leads to &lt;a href=&quot;https://www.intrinsec.com/wp-content/uploads/2023/10/TLP-CLEAR-Lumma-Stealer-EN-Information-report.pdf&quot;&gt;an in-depth report&lt;/a&gt; by the French security firm &lt;a href=&quot;https://www.intrinsec.com/&quot;&gt;Intrisec&lt;/a&gt;. The mysterious file is apparently not present anymore in this “newer” version of the Lumma Stealer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;We also noticed the absence of the file “doberman.min.js” on new Lumma C2 panel […]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The full report is a fascinating read. Here’s the summary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Various actors actively deploying Lumma Stealer in multiple campaigns&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lumma Stealer, also known as LummaC2 Stealer, is a malware-as-a-service sold through Telegram and Russian-speaking cybercrime forums. […​] Lumma is an information stealer written in C/C++ language that has been observed in the wild since at least August 2022. […​] This malware is designed to pilfer sensitive data from infected devices. Among the data targeted are cryptocurrency wallets, browser extensions, two-factor authentication codes, logins and passwords stored on browsers, and various files.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;trail-business-case&quot;&gt;Trail: Business Case&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://outpost24.com/&quot;&gt;Outpost24&lt;/a&gt; &lt;a href=&quot;https://outpost24.com/blog/everything-you-need-to-know-lummac2-stealer/&quot;&gt;explored the malware in detail&lt;/a&gt;, including their store. Joining the dark side starts sets you back $250, or a bit more if you aim for best-value. Granted, the chance of someone falling for this weak threat is low. But if the net is cast wide enough…? Imagine just a few victims falling for the malware, finding just &lt;em&gt;one&lt;/em&gt; &lt;a href=&quot;https://techinformed.com/crypto-hackers-have-already-stolen-almost-1-4-billion-this-year/&quot;&gt;juicy crypto-wallet&lt;/a&gt;. The amount of potential profit per dollar is staggering, as is the damage caused.&lt;/p&gt;
&lt;p&gt;Lumma Stealer store page, translated from Russian — by &lt;a href=&quot;https://outpost24.com/blog/everything-you-need-to-know-lummac2-stealer/&quot;&gt;Outpost24&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;As Research Software Engineers we don’t often think about cybersecurity. Our institute, the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, is an independent foundation and not a company with valuable trade secrets. We don’t usually work in projects that are high-profile targets. Nevertheless, people who write code are increasingly targeted by cyber-criminals. Do you remember the &lt;a href=&quot;https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/&quot;&gt;drama around the program &lt;/a&gt;&lt;code&gt;[xz utils](https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/)&lt;/code&gt; in March 2024? A user infiltrated a widely used open-source project, earned trust by making meaningful contributions, and finally injected a malicious backdoor into the source code. It was caught just in time before it was distributed widely.&lt;/p&gt;
&lt;p&gt;The case discussed here is a much cruder approach, amateurish even. Malware-as-a-service, like the Lumma Stealer, makes malware accessible for the masses, enabling this spray-and-pray approach. We can expect its use to only increase in time. It shows that all of us can be targets, at any time.&lt;/p&gt;
&lt;p&gt;Stay vigilant.&lt;/p&gt;
&lt;p&gt;Cross post: &lt;a href=&quot;https://ole.mn/posts/a-helpful-noob/&quot;&gt;https://ole.mn/posts/a-helpful-noob/&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 21 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;A Helpful Noob&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-helpful-noob-a2f448b4.lQj8rzQD_Z2cSNID.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@keiteu_ko?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Keiteu Ko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Yesterday, my colleague &lt;a href=&quot;https://github.com/fdiblen&quot;&gt;Faruk&lt;/a&gt; asked me to conduct a Hallway Test for the &lt;code&gt;[NLeSC/python-template](https://github.com/NLeSC/python-template)&lt;/code&gt; he is working on: he just grabbed me off the hallway and asked me to give it a spin. This is, however, not a story about the test, but of open-source intelligence (OSINT) and the contributions of yet another “helpful noob”.&lt;/p&gt;
&lt;p&gt;Right after I posted my feedback in an &lt;a href=&quot;https://github.com/NLeSC/python-template/issues/554&quot;&gt;issue&lt;/a&gt; of the project, someone else posted a helpful contribution right underneath:&lt;/p&gt;
&lt;p&gt;GitHub comment from xiaobai-marker, with edited link so y’all don’t get any funny ideasHuh? It took this person only a few seconds to post a fix for quite a list of small changes that I posted. That’s so nice! So let’s do a review of &lt;em&gt;their&lt;/em&gt; contributions.&lt;/p&gt;
&lt;h2 id=&quot;trail-github&quot;&gt;Trail: GitHub&lt;/h2&gt;
&lt;p&gt;Their GitHub handle is &lt;code&gt;xiaobai-marker&lt;/code&gt;. XiaoBai is (Pinyin writing of) Chinese and translates to “little white”, not referring to the actual color, but more in the direction of “unsullied”. It means Little Noob.&lt;/p&gt;
&lt;p&gt;A brief dive into &lt;code&gt;xiaobai-marker&lt;/code&gt; ‘s GitHub profile (by now mysteriously removed) confirms this initial impression.&lt;/p&gt;
&lt;p&gt;GitHub profile of &lt;code&gt;xiaobai-marker&lt;/code&gt;They forked only three publicly available repositories. They apparently deal with self-driving toy cars and machine learning to detect road lanes. Fun! However, that’s not a lot of content for someone who seems to contribute to other projects, especially considering that they did not open any repositories themselves.&lt;/p&gt;
&lt;p&gt;But we’re not judging. Any contributions are welcome, and that includes those from people with little experience. So let’s have a look at their actual contribution.&lt;/p&gt;
&lt;h2 id=&quot;trail-download-link&quot;&gt;Trail: Download Link&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mediafire.com&quot;&gt;MediaFire&lt;/a&gt; is a known file storage and sharing website. Clicking &lt;em&gt;this&lt;/em&gt; link is not &lt;em&gt;per se&lt;/em&gt; dangerous. Still, we proceed with caution.&lt;/p&gt;
&lt;p&gt;MediaFire download pageMediaFire uses VirusTotal to scan for malicious files. This inspires confidence, right? An encrypted &lt;code&gt;*.zip&lt;/code&gt; file, however, is opaque to any scans since we can’t look inside without the password, which was supplied on GitHub and is not known to MediaFire or VirusTotal. Another interesting detail is where the file comes from. Apparently it was uploaded the same day from somewhere in Russia. Is our Little Noob from Russia?&lt;/p&gt;
&lt;p&gt;Let’s check out the files now.&lt;/p&gt;
&lt;h2 id=&quot;trail-files&quot;&gt;Trail: Files&lt;/h2&gt;
&lt;p&gt;What did we actually download? A rather small zip file.&lt;/p&gt;
&lt;p&gt;$ ls -lah fix.zip
-rw-r—r— 1 ole users 367K Aug 27 08:15 fix.zipProviding the password, we can unpack it and have a look at the content.&lt;/p&gt;
&lt;p&gt;$ 7z e -pchangeme fix.zip&lt;/p&gt;
&lt;p&gt;7-Zip [64] 17.05 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28
p7zip Version 17.05 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs x64)&lt;/p&gt;
&lt;p&gt;Scanning the drive for archives:
1 file, 375771 bytes (367 KiB)&lt;/p&gt;
&lt;h2 id=&quot;extracting-archive-fixzip&quot;&gt;Extracting archive: fix.zip&lt;/h2&gt;
&lt;p&gt;Path = fix.zip
Type = zip
Physical Size = 375771&lt;/p&gt;
&lt;p&gt;Everything is Ok&lt;/p&gt;
&lt;p&gt;Folders: 1
Files: 2
Size:       747008
Compressed: 375771What did we just unpack?&lt;/p&gt;
&lt;p&gt;$ ls -lah fix/
total 456K
-rw-r—r— 1 ole users 490K Aug 27 08:15 msvcp140.dll
-rw-r—r— 1 ole users 240K Aug 27 08:15 x86_64-w64-ranlib.exeHuh. &lt;code&gt;ranlib&lt;/code&gt; is a standard programming tool, although here it is supposed to be an installer (!). This “fix” seems to have been written for a Windows system. I can’t run it on my Linux machine. Bummer. I’m also not very good at decompiling &lt;code&gt;*.exe&lt;/code&gt; files to check what’s really inside. But we can ask some websites for assistance.&lt;/p&gt;
&lt;h3 id=&quot;virustotal&quot;&gt;VirusTotal&lt;/h3&gt;
&lt;p&gt;First we upload the file to &lt;a href=&quot;https://virustotal.com&quot;&gt;virustotal.com&lt;/a&gt;, a Google-owned file and link analyzer and one of the authorities in the space of malware indexing. On the day of the initial analysis, 28 of 75 security vendors &lt;a href=&quot;https://www.virustotal.com/gui/file/546c34c2782216278a8273d3c9d3a954a980c7c2c7be220914aefe446fe94fd8/detection&quot;&gt;flagged the files as malicious&lt;/a&gt;. You don’t say! One day later this number is up to 35. It seems to be a fresh strain that is quickly being picked up by the security community.&lt;/p&gt;
&lt;p&gt;VirusTotal analysisSo what do we have here? “Trojan”? “MalwareX”? This is still quite vague.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Fun fact: One of the analyses — fourth row, right side — comes from CrowdStrike. Those are guys that &lt;em&gt;&lt;a href=&quot;https://arstechnica.com/information-technology/2024/07/major-outages-at-crowdstrike-microsoft-leave-the-world-with-bsods-and-confusion/&quot;&gt;&lt;em&gt;crashed&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; some &lt;em&gt;&lt;a href=&quot;https://blogs.microsoft.com/blog/2024/07/20/helping-our-customers-through-the-crowdstrike-outage/&quot;&gt;&lt;em&gt;8.5 million rather important Windows computers&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, resulting in &lt;em&gt;&lt;a href=&quot;https://www.oxfordeconomics.com/resource/crowdstrike-update-grounds-thousands-of-flights/&quot;&gt;&lt;em&gt;over 10.000 cancelled flights&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and causing &lt;em&gt;&lt;a href=&quot;https://www.neowin.net/news/systems-paralyzed-by-crowdstrike-within-78-minutes-to-cause-15-billion-in-losses-worldwide/&quot;&gt;&lt;em&gt;some $15 billion damages worldwide&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in July 2024. Oops.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;triage&quot;&gt;Tria.ge&lt;/h3&gt;
&lt;p&gt;Triage provides a malware analysis sandbox and provides reports for submitted samples. Some kind soul already &lt;a href=&quot;https://tria.ge/240826-vhsrtawepj/behavioral4&quot;&gt;uploaded the one we found&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Triage analysis summary“Lumma”? “Stealer”? What’s that? Apparently this malware tries to steal…​ things? Let’s look into this.&lt;/p&gt;
&lt;p&gt;Some more interesting details can be found further down in the network section of the analysis. What’s a malware to do after it did its deeds? It has to send the stuff it found &lt;em&gt;somewhere&lt;/em&gt;, right? So Triage ran the malware in a sandbox and recorded the network traffic. These are some of the connections the malware made:&lt;/p&gt;
&lt;p&gt;Triage analysis network traffic&lt;code&gt;froytnewqowv.shop&lt;/code&gt; seems to be the URL of the Command-and-Control (C2) server of this malware. It tells the malware what to do and collects the bountiful harvest. Also take note of the &lt;code&gt;froytnewqowv.shop/api&lt;/code&gt; path that we will explore in a minute.&lt;/p&gt;
&lt;h2 id=&quot;trail-c2-server&quot;&gt;Trail: C2 server&lt;/h2&gt;
&lt;p&gt;Let’s see if we can find out more about who our malware talks to. WHO IS the one that owns the weird domain name?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“WHOIS is a public database that houses the information collected when someone registers a domain name”
— &lt;a href=&quot;https://www.domain.com/blog/what-is-whois-and-how-is-it-used/&quot;&gt;https://www.domain.com/blog/what-is-whois-and-how-is-it-used/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;whois&quot;&gt;WhoIs&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.whois.com/whois/froytnewqowv.shop&quot;&gt;whois&lt;/a&gt; look-up shows that the domain was registered just a few days ago via &lt;a href=&quot;https://www.namecheap.com/&quot;&gt;namecheap.com&lt;/a&gt;. This register hides the client’s contact information, like physical address or email.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;whois&lt;/code&gt; lookup of &lt;code&gt;the URL froytnewqowv.shop&lt;/code&gt;Furthermore, we see from the “Name Server” entries that they hide behind &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare&lt;/a&gt;. This service can, among other things, act as an intermediary between a user and a website. This means that we cannot directly find out the IP address — the “actual address” that the URL is translated into — of the C2 server, since all the traffic is routed through Cloudflare’s machines first.&lt;/p&gt;
&lt;p&gt;Little Noob is privacy-conscious.&lt;/p&gt;
&lt;p&gt;Let’s give the C2 server a visit then. We open the website in a browser.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note that it’s usually not a good idea to browse possibly malicious sites, since they can* infect your computer.&lt;/p&gt;
&lt;h3 id=&quot;browsing-the-c2-website&quot;&gt;Browsing the C2 website&lt;/h3&gt;
&lt;p&gt;Opening the URL in a browser lets us see:&lt;/p&gt;
&lt;p&gt;Visiting the C2 serverWell, that’s not much. This is the default landing page of their &lt;code&gt;nginx&lt;/code&gt; web server, with no content whatsoever. Let’s have a look at the source code of this website then, by pressing &lt;code&gt;CTRL+U&lt;/code&gt; in the browser.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;html&gt;
&amp;#x3C;head&gt;&amp;#x3C;title&gt;405 Not Allowed&amp;#x3C;/title&gt;&amp;#x3C;/head&gt;
&amp;#x3C;body&gt;
&amp;#x3C;center&gt;&amp;#x3C;h1&gt;405 Not Allowed&amp;#x3C;/h1&gt;&amp;#x3C;/center&gt;
&amp;#x3C;hr&gt;&amp;#x3C;center&gt;nginx/1.18.0 (Ubuntu)&amp;#x3C;/center&gt;
&amp;#x3C;/body&gt;
&amp;#x3C;/html&gt;Ah yes. Privacy conscious. At least we learn that the server runs &lt;code&gt;nginx&lt;/code&gt; version &lt;code&gt;1.18.0&lt;/code&gt; on Ubuntu.&lt;/p&gt;
&lt;p&gt;If we look back at the network section of the Triage analysis, we see that the malware made a request to the &lt;code&gt;/api&lt;/code&gt; path. API stands for Application Programming Interface **and is basically a somewhat standardized interface for talking to computers programmatically. What does that API path look like in the browser?&lt;/p&gt;
&lt;p&gt;API pathI guess I’m not invited to that party. Let’s explore the website a bit more and guess some other paths.&lt;/p&gt;
&lt;p&gt;404 pageNope. Not that easy, apparently. &lt;code&gt;404&lt;/code&gt; is browser-speak for “I can’t find what you asked of me”. Let’s see what Google knows about this URL.&lt;/p&gt;
&lt;p&gt;Google search for the C2 URLAha. Another path: &lt;code&gt;/apib&lt;/code&gt;. Where does this lead to?&lt;/p&gt;
&lt;p&gt;A different 404 page? Hmm…Another dead end? But this one look different. Russian again. How come? After trying some more URLs by hand, it is apparent that everything that starts with &lt;code&gt;/api&lt;/code&gt; is leading to this &lt;em&gt;other&lt;/em&gt; 404-not-found page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/apia&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/apib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api_I_misconfigured_my_nginx_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see what we can learn from this page. Translation:&lt;/p&gt;
&lt;p&gt;404**
Oops… There was a mistake&lt;/p&gt;
&lt;p&gt;Sorry, this page was not found or the administrator has closed access to it&lt;/p&gt;
&lt;p&gt;&amp;#x3C;- To the main pageNo surprises here. Let’s download the whole thing and see what we get.&lt;/p&gt;
&lt;h3 id=&quot;website-source-code&quot;&gt;Website source code&lt;/h3&gt;
&lt;p&gt;The website source contains the following files:&lt;/p&gt;
&lt;p&gt;$ tree
.
├── Ошибка_files
│   ├── dober.html
│   ├── doberman.min.html
│   ├── jquery-3.6.0.min.js
│   ├── tabler-flags.min.css
│   ├── tabler-icons.min.css
│   ├── tabler.min.css
│   ├── tabler.min.js
│   ├── tabler-payments.min.css
│   ├── tabler-vendors.min.css
│   ├── tom-select.complete.min.js
│   └── tom-select.css
└── Ошибка.htmlOur error page seems to have been built with &lt;a href=&quot;https://tabler.io/&quot;&gt;tabler.io&lt;/a&gt;. This seems to be a bit too much effort for a simple 404 page. Tabler is often used to build elaborate dashboards. So there’s probably more to it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;css&lt;/code&gt; files are Cascading Style Sheets (CSS), which are used for styling a web page. Not too interesting. &lt;code&gt;[tom-select](https://tom-select.js.org/)&lt;/code&gt; is a standard JavaScript framework for UI control. &lt;code&gt;[jquery](https://jquery.com/)&lt;/code&gt; is a library to simplify HTML development, assisting with document traversal and other things.&lt;/p&gt;
&lt;p&gt;The interesting ones that remain are &lt;code&gt;dober.html&lt;/code&gt; and &lt;code&gt;doberman.min.html&lt;/code&gt;. What are those? Let’s have a look.&lt;/p&gt;
&lt;p&gt;The content of &lt;code&gt;dober.html&lt;/code&gt; is one single line of text which looks like this:&lt;/p&gt;
&lt;p&gt;&amp;#x3C;!DOCTYPE html&gt;&amp;#x3C;html lang=“en-US”&gt;&amp;#x3C;head&gt;&amp;#x3C;title&gt;Just a moment…&amp;#x3C;/title&gt;&amp;#x3C;meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”&gt;&amp;#x3C;meta http-equiv=“X-UA-Compatible” content=“IE=Edge”&gt;&amp;#x3C;meta name=“robots” content=“noindex,nofollow”&gt;&amp;#x3C;meta name=“viewport” content=“width=device-width,initial-scale=1”&gt;&amp;#x3C;style&gt;*{box-sizing:border-box;margin:0;padding:0}html{line-height:1.15;-webkit-text-size-adjust:100%;color:#313131}button,html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}@media (prefers-color-sch…Urgh. This HTML vomit is “minified”, which means it is condensed as much as possible to save bandwidth when opening a website. This makes it hard to read for us humans, though. Luckily we can get some help with disentangling it.&lt;/p&gt;
&lt;h3 id=&quot;unminifycom&quot;&gt;Unminify.com&lt;/h3&gt;
&lt;p&gt;While there are Integrated Development Environments (IDEs) that can disentangle minified HTML, there are also websites that do this for you with a click of a button.&lt;/p&gt;
&lt;p&gt;Unminifying HTML code, making it readable and prettyThe code in the screenshot above is now much more readable. Below in the unminified code of &lt;code&gt;doberman.min.html&lt;/code&gt; we can find a reference to a file that does not seem to exist. An excerpt of &lt;code&gt;doberman.min.html&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&amp;#x3C;script&gt;
(function () {
window._cf_chl_opt = {
cvId: “3”,
cZone: “froytnewqowv.shop”,
cType: “interactive”,
cNounce: “11691”,
cRay: “8b96971bcef66608”,
cHash: “a7c37071216d981”,
cUPMDTk: “/core/panel/js/doberman.min.js?2&amp;#x26;__cf_chl_tk=POTzyU0ftLF9cvsIaAitlr5np8LsKoghhsVMME6MjWg-1724704337-0.0.1.1-2559”,Where is this file &lt;code&gt;/core/panel/js/doberman.min.js&lt;/code&gt; referenced here? It was not downloaded with the rest. Is it being dynamically created and loaded? I would not know without more time to study it. Again, luckily, other people already did the hard work for us. Searching for this file string on Google leads to &lt;a href=&quot;https://www.intrinsec.com/wp-content/uploads/2023/10/TLP-CLEAR-Lumma-Stealer-EN-Information-report.pdf&quot;&gt;an in-depth report&lt;/a&gt; by the French security firm &lt;a href=&quot;https://www.intrinsec.com/&quot;&gt;Intrisec&lt;/a&gt;. The mysterious file is apparently not present anymore in this “newer” version of the Lumma Stealer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;We also noticed the absence of the file “doberman.min.js” on new Lumma C2 panel […]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The full report is a fascinating read. Here’s the summary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Various actors actively deploying Lumma Stealer in multiple campaigns&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lumma Stealer, also known as LummaC2 Stealer, is a malware-as-a-service sold through Telegram and Russian-speaking cybercrime forums. […​] Lumma is an information stealer written in C/C++ language that has been observed in the wild since at least August 2022. […​] This malware is designed to pilfer sensitive data from infected devices. Among the data targeted are cryptocurrency wallets, browser extensions, two-factor authentication codes, logins and passwords stored on browsers, and various files.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;trail-business-case&quot;&gt;Trail: Business Case&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://outpost24.com/&quot;&gt;Outpost24&lt;/a&gt; &lt;a href=&quot;https://outpost24.com/blog/everything-you-need-to-know-lummac2-stealer/&quot;&gt;explored the malware in detail&lt;/a&gt;, including their store. Joining the dark side starts sets you back $250, or a bit more if you aim for best-value. Granted, the chance of someone falling for this weak threat is low. But if the net is cast wide enough…? Imagine just a few victims falling for the malware, finding just &lt;em&gt;one&lt;/em&gt; &lt;a href=&quot;https://techinformed.com/crypto-hackers-have-already-stolen-almost-1-4-billion-this-year/&quot;&gt;juicy crypto-wallet&lt;/a&gt;. The amount of potential profit per dollar is staggering, as is the damage caused.&lt;/p&gt;
&lt;p&gt;Lumma Stealer store page, translated from Russian — by &lt;a href=&quot;https://outpost24.com/blog/everything-you-need-to-know-lummac2-stealer/&quot;&gt;Outpost24&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;As Research Software Engineers we don’t often think about cybersecurity. Our institute, the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, is an independent foundation and not a company with valuable trade secrets. We don’t usually work in projects that are high-profile targets. Nevertheless, people who write code are increasingly targeted by cyber-criminals. Do you remember the &lt;a href=&quot;https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/&quot;&gt;drama around the program &lt;/a&gt;&lt;code&gt;[xz utils](https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/)&lt;/code&gt; in March 2024? A user infiltrated a widely used open-source project, earned trust by making meaningful contributions, and finally injected a malicious backdoor into the source code. It was caught just in time before it was distributed widely.&lt;/p&gt;
&lt;p&gt;The case discussed here is a much cruder approach, amateurish even. Malware-as-a-service, like the Lumma Stealer, makes malware accessible for the masses, enabling this spray-and-pray approach. We can expect its use to only increase in time. It shows that all of us can be targets, at any time.&lt;/p&gt;
&lt;p&gt;Stay vigilant.&lt;/p&gt;
&lt;p&gt;Cross post: &lt;a href=&quot;https://ole.mn/posts/a-helpful-noob/&quot;&gt;https://ole.mn/posts/a-helpful-noob/&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-helpful-noob-a2f448b4.lQj8rzQD.jpg" medium="image"/><author>ole</author></item><item><title>Fast-Forward Merges on GitHub</title><link>https://blog.esciencecenter.nl/posts/2025-02-21---fast-forward-merges-on-github</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-02-21---fast-forward-merges-on-github</guid><description>&lt;p&gt;&lt;em&gt;The year is 2025 CE and GitHub.com still can’t do “fast-forward” merges via its web-interface. But &lt;em&gt;you&lt;/em&gt; can; I’ll show you how.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jhonkasalo?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Joakim Honkasalo&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;a href=&quot;https://github.com&quot;&gt;Github.com&lt;/a&gt; offers version-control-as-a-service, with all kinds of useful things bolted on top. The year is 2025 CE and GitHub leverages the vast power of &lt;code&gt;git&lt;/code&gt; and exposes it entirely to their users. Well, not entirely… One small feature of indomitable usefulness still holds out against the invaders. Well OK. Here the stories diverge.&lt;/p&gt;
&lt;p&gt;One &lt;code&gt;git&lt;/code&gt; feature that is not available via the &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt; web interface are “fast-forward (ff) merges”. It is among the highest &lt;code&gt;git&lt;/code&gt;-related feature requests with about 1500 upvotes.¹ To explain what that is and why one would want this, we have to take a detour first.&lt;/p&gt;
&lt;h2 id=&quot;intermezzo-merge-types&quot;&gt;Intermezzo: Merge Types&lt;/h2&gt;
&lt;p&gt;To set the ground for explaining fast-forward merging, I’ll cherry-pick (chuckle) a specific scenario.&lt;/p&gt;
&lt;p&gt;Let’s follow best practices where we have our &lt;code&gt;main&lt;/code&gt; branch protected, meaning that we cannot add changes to it directly. Any changes that should end up in &lt;code&gt;main&lt;/code&gt; will be merged via pull- (GitHub speak) or merge- (same, but GitLab speak) requests. That way there can be some auditing before code ends up in the &lt;code&gt;main&lt;/code&gt; branch. This could prevent minor hiccups like the &lt;a href=&quot;https://en.wikipedia.org/wiki/2024_CrowdStrike-related_IT_outages&quot;&gt;CrowdStrike-related IT outages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;nixCraft having a blast at CrowdstrikeGranted, I don’t think code pushed to &lt;code&gt;main&lt;/code&gt; was the cause for the global-scale IT outage, but it would have been funny if it was – however funny &lt;a href=&quot;https://www.businessinsider.com/businesses-claiming-losses-crowdstrike-outage-insurance-billions-losses-cyber-policies-2024-7&quot;&gt;~$10 billion in damages&lt;/a&gt; can be.&lt;/p&gt;
&lt;p&gt;A bit more opinionated than protecting &lt;code&gt;main&lt;/code&gt; is the choice to keep the &lt;code&gt;git&lt;/code&gt; commit history linear. With “commit” we mean a snapshot in time – a set of related changes to your code with a specific description – so you can find it back later. Reasons for a linear &lt;code&gt;git&lt;/code&gt; history could be that you follow the &lt;a href=&quot;https://finitestate.io/blog/git-v-branching-model&quot;&gt;Git V Branching Model&lt;/a&gt; or if you want to have &lt;a href=&quot;https://abelsiqueira.com/&quot;&gt;Abel&lt;/a&gt;’s &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;Utopic Git History&lt;/a&gt;. In general, &lt;code&gt;git&lt;/code&gt; commit graphs can look a bit complicated.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git&lt;/code&gt; commit graph: Guitar Hero 🎸
&lt;code&gt;git&lt;/code&gt; commit graph: Harp 🎵
&lt;code&gt;git&lt;/code&gt; commit graph: London Underground 🚇 (/s)&lt;/p&gt;
&lt;h2 id=&quot;branches&quot;&gt;Branches&lt;/h2&gt;
&lt;p&gt;To compartmentalize development tasks and to keep the repository tidy, we often use “branches”. These are alternative realities of your code-base, and you can jump back and forth between them like &lt;a href=&quot;https://marvelcinematicuniverse.fandom.com/wiki/Doctor_Strange&quot;&gt;Dr. Strange&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead of the mess above, let’s simplify our &lt;code&gt;git&lt;/code&gt; commit history such that it looks like a straight string of pearls. In the following visualizations, time progresses towards the right. The horizontal lines represent branches, and the nodes on them are commits with a certain commit message. They &lt;em&gt;also&lt;/em&gt; have a specific fingerprint, called “hash”, that uniquely identifies them. We will come back to that later.&lt;/p&gt;
&lt;p&gt;When we work on a feature or a bugfix (or anything, really) we usually do that on a separate branch, nicely separated. After we finished working on this branch, we want to &lt;em&gt;somehow&lt;/em&gt; get the changes we made back onto the &lt;code&gt;main&lt;/code&gt; branch. There are different approaches for that.&lt;/p&gt;
&lt;h3 id=&quot;merge-commit&quot;&gt;Merge Commit&lt;/h3&gt;
&lt;p&gt;“Standard” merge commits leave the history where exactly the code came from intact. An extra “merge commit” contains the changes from our &lt;code&gt;feature&lt;/code&gt; branch.&lt;/p&gt;
&lt;h3 id=&quot;rebase&quot;&gt;Rebase&lt;/h3&gt;
&lt;p&gt;Another way to keep the &lt;code&gt;git&lt;/code&gt; history linear is “rebasing”. This approach basically re-plays the new commits that happened on the &lt;code&gt;feature&lt;/code&gt; branch onto the &lt;code&gt;main&lt;/code&gt; branch. This means that there is no “merge commit” on the &lt;code&gt;main&lt;/code&gt; branch anymore. However, if there have been commits to &lt;code&gt;main&lt;/code&gt; after &lt;code&gt;feature&lt;/code&gt; has been branched off, the &lt;code&gt;feature&lt;/code&gt; commits are re-written. Do you remember the “hash” fingerprint, I mentioned before? Here it becomes important. When rebasing, the commit content and commit messages are the same, but since these are effectively “new” commits, the commit hashes are different! This means that anything that was attached to a certain hash, like signatures or tags, will point to the commits on the &lt;code&gt;feature&lt;/code&gt; branch. To demonstrate this, we attached a tag &lt;code&gt;v1.0.0&lt;/code&gt; to one commit on the &lt;code&gt;feature&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;Do you see how the tag is kept dangling on the now useless feature branch?&lt;/p&gt;
&lt;h3 id=&quot;fast-forward-merging&quot;&gt;Fast-forward Merging&lt;/h3&gt;
&lt;p&gt;“Fast-forward” merging can be achieved if &lt;code&gt;main&lt;/code&gt; did &lt;em&gt;not receive any commits&lt;/em&gt; in the meantime. So clean! Instead of re-writing the commits onto another branch, the &lt;code&gt;main&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;feature&lt;/code&gt; commits are basically pointers to the exact same commit.&lt;/p&gt;
&lt;p&gt;This looks very similar to rebasing, does it not?&lt;/p&gt;
&lt;p&gt;In fact, if the main branch did not receive any new commits since the branching, fast-forward merging is the same as rebasing…&lt;/p&gt;
&lt;h2 id=&quot;github-rebasing&quot;&gt;GitHub Rebasing&lt;/h2&gt;
&lt;p&gt;…unless you are using the GitHub web interface. When you rebase a &lt;code&gt;feature&lt;/code&gt; branch on GitHub onto an untouched &lt;code&gt;main&lt;/code&gt; branch, the commits are still re-written. This is contrary to how &lt;code&gt;git&lt;/code&gt; on the command line works. Why is that such a big deal? The commit messages are the same. The commit content is the same. Why worry about a different commit hash?&lt;/p&gt;
&lt;p&gt;It matters, because lots of things are tied to a commit hash. A commit signature is tied to its hash! The signature gets lost if the hash changes during a rebase. The same holds true for tags. &lt;code&gt;feature&lt;/code&gt; commit tags will point to the commits on the &lt;code&gt;feature&lt;/code&gt; branch, not to the re-written ones on &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;solutions&quot;&gt;Solutions&lt;/h2&gt;
&lt;p&gt;There are two ways to achieve fast-forward merging when using GitHub. One is convoluted and error prone. The other one is cursed. Choose wisely.&lt;/p&gt;
&lt;h3 id=&quot;using-local-git&quot;&gt;Using Local &lt;code&gt;git&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Protecting your &lt;code&gt;main&lt;/code&gt; branch means that you can’t commit to it directly. You can, however, push sanctioned changes from &lt;code&gt;main&lt;/code&gt; to your remote repository on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;. Wait, what? I thought you can’t touch &lt;code&gt;main&lt;/code&gt;? Follow me, I’ll show you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a pull request from &lt;code&gt;feature&lt;/code&gt; to &lt;code&gt;main&lt;/code&gt; on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open a terminal and create some magic:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;cd your/project/folder     # cd into your project directory
git pull    # get the latest changes to your local computer
git switch main    # select the &lt;code&gt;main&lt;/code&gt; branch, if necessary
git merge —ff-only feature    # ff-merge feature onto main
git push      # allowed! because you created a pull request&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pull request is automatically closed 🪄&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While rather low-tech, this relies on the workflow and discipline of the developers to work. This is a danger zone. It is 4:55pm on a Friday afternoon. You opened a pull request to contribute your work on the &lt;code&gt;feature&lt;/code&gt; branch and now watch patiently how the green circle closes that shows that all CI tests passed. Your fingers itch to wrap things up quickly so you can go home and wolf down the lasagna you prepared already the day before.&lt;/p&gt;
&lt;p&gt;The mouse cursor hovers over the fat, green “Merge pull request” button.&lt;/p&gt;
&lt;p&gt;Don’t. Don’t do it.Stop! Resist the temptation!**&lt;/p&gt;
&lt;p&gt;Click that button and you need to spend the next half hour undoing the rebased, re-written commits to &lt;code&gt;main&lt;/code&gt;, while sweating profusely because now you are messing directly with the &lt;code&gt;main&lt;/code&gt; branch, which you tried to prevent by protecting it in the first place. And by now, at home, your partner has finished both their and your piece of the lasagna.&lt;/p&gt;
&lt;p&gt;Instead of following the suggested path, you need to step away from the browser and open the terminal. You pull the changes, fast-forward merge locally and finally push to &lt;code&gt;main&lt;/code&gt;, as shown above.&lt;/p&gt;
&lt;h3 id=&quot;using-actions&quot;&gt;Using Actions&lt;/h3&gt;
&lt;p&gt;This approach needs some set-up, but is safer to use afterwards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disable the Merge Button&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We have learned now that the fat, green “Merge” button is dangerous², so we need to disable it. In your GitHub repository, go to&lt;/p&gt;
&lt;p&gt;Settings &lt;em&gt;→&lt;/em&gt; General &lt;em&gt;→&lt;/em&gt; Pull Requests*&lt;/p&gt;
&lt;p&gt;and allow only Squash Merging. Next, go to&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Settings &lt;em&gt;→&lt;/em&gt; Rules &lt;em&gt;→&lt;/em&gt; Rulesets&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;and add a new rule. Name it &lt;code&gt;disable_merge_button&lt;/code&gt;, set it to “Active”. Set the “Target branches” to the “default branch” a.k.a main . Check “Require a pull request before merging” and, while waving a magic wand, set “Allowed merge methods” to “Rebase”, contradicting the general repository settings. Check whichever other settings you would like and click on “Save changes”.&lt;/p&gt;
&lt;p&gt;Now pull requests cannot be merged anymore. Yay?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automate the Wizardry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Set up the “Fast Forward Merge” Action from the GitHub Marketplace: &lt;a href=&quot;https://github.com/marketplace/actions/fast-forward-merge&quot;&gt;https://github.com/marketplace/actions/fast-forward-merge&lt;/a&gt; . This gives you two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A message posted in the PR chat indicating whether fast-forward merging is possible.&lt;/li&gt;
&lt;li&gt;A GitHub Action that fast-forward merges your Pull Request. You trigger it by commenting &lt;code&gt;/fast-forward&lt;/code&gt; in the Pull Request chat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;N.B.: For the triggered ff-merge to work, the Action yml file has to already exist in the main branch. So you have to get it there &lt;em&gt;once&lt;/em&gt; via impure means.&lt;/p&gt;
&lt;p&gt;It works. Yet it feels dirty. You just made a forbidden deal with C̶t̶h̶u̶l̶h̶u̶ Octocat and you will probably need to sacrifice the lasagna you made so it does not come to haunt you at night.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-Up&lt;/h2&gt;
&lt;p&gt;By now you not only know what fast-forward merging is, you also have ways to use it on your external repository on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;. You might have subscribed to &lt;a href=&quot;https://github.com/orgs/community/discussions/4618&quot;&gt;github.com/orgs/community/discussions/4618&lt;/a&gt; and now patiently wait for the powers-that-be to enable this feature on their website.&lt;/p&gt;
&lt;p&gt;Until that happens, feel free to choose one of the workarounds outlined above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Upvote count combines upvotes and thumbs-up from &lt;a href=&quot;https://github.com/orgs/community/discussions/4618&quot;&gt;https://github.com/orgs/community/discussions/4618&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you want to achieve fast-forward merging, that is.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cross post: &lt;a href=&quot;https://ole.mn/posts/fast-forward-github/&quot;&gt;https://ole.mn/posts/fast-forward-github/&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 21 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;The year is 2025 CE and GitHub.com still can’t do “fast-forward” merges via its web-interface. But &lt;em&gt;you&lt;/em&gt; can; I’ll show you how.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jhonkasalo?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Joakim Honkasalo&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;a href=&quot;https://github.com&quot;&gt;Github.com&lt;/a&gt; offers version-control-as-a-service, with all kinds of useful things bolted on top. The year is 2025 CE and GitHub leverages the vast power of &lt;code&gt;git&lt;/code&gt; and exposes it entirely to their users. Well, not entirely… One small feature of indomitable usefulness still holds out against the invaders. Well OK. Here the stories diverge.&lt;/p&gt;
&lt;p&gt;One &lt;code&gt;git&lt;/code&gt; feature that is not available via the &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt; web interface are “fast-forward (ff) merges”. It is among the highest &lt;code&gt;git&lt;/code&gt;-related feature requests with about 1500 upvotes.¹ To explain what that is and why one would want this, we have to take a detour first.&lt;/p&gt;
&lt;h2 id=&quot;intermezzo-merge-types&quot;&gt;Intermezzo: Merge Types&lt;/h2&gt;
&lt;p&gt;To set the ground for explaining fast-forward merging, I’ll cherry-pick (chuckle) a specific scenario.&lt;/p&gt;
&lt;p&gt;Let’s follow best practices where we have our &lt;code&gt;main&lt;/code&gt; branch protected, meaning that we cannot add changes to it directly. Any changes that should end up in &lt;code&gt;main&lt;/code&gt; will be merged via pull- (GitHub speak) or merge- (same, but GitLab speak) requests. That way there can be some auditing before code ends up in the &lt;code&gt;main&lt;/code&gt; branch. This could prevent minor hiccups like the &lt;a href=&quot;https://en.wikipedia.org/wiki/2024_CrowdStrike-related_IT_outages&quot;&gt;CrowdStrike-related IT outages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;nixCraft having a blast at CrowdstrikeGranted, I don’t think code pushed to &lt;code&gt;main&lt;/code&gt; was the cause for the global-scale IT outage, but it would have been funny if it was – however funny &lt;a href=&quot;https://www.businessinsider.com/businesses-claiming-losses-crowdstrike-outage-insurance-billions-losses-cyber-policies-2024-7&quot;&gt;~$10 billion in damages&lt;/a&gt; can be.&lt;/p&gt;
&lt;p&gt;A bit more opinionated than protecting &lt;code&gt;main&lt;/code&gt; is the choice to keep the &lt;code&gt;git&lt;/code&gt; commit history linear. With “commit” we mean a snapshot in time – a set of related changes to your code with a specific description – so you can find it back later. Reasons for a linear &lt;code&gt;git&lt;/code&gt; history could be that you follow the &lt;a href=&quot;https://finitestate.io/blog/git-v-branching-model&quot;&gt;Git V Branching Model&lt;/a&gt; or if you want to have &lt;a href=&quot;https://abelsiqueira.com/&quot;&gt;Abel&lt;/a&gt;’s &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;Utopic Git History&lt;/a&gt;. In general, &lt;code&gt;git&lt;/code&gt; commit graphs can look a bit complicated.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git&lt;/code&gt; commit graph: Guitar Hero 🎸
&lt;code&gt;git&lt;/code&gt; commit graph: Harp 🎵
&lt;code&gt;git&lt;/code&gt; commit graph: London Underground 🚇 (/s)&lt;/p&gt;
&lt;h2 id=&quot;branches&quot;&gt;Branches&lt;/h2&gt;
&lt;p&gt;To compartmentalize development tasks and to keep the repository tidy, we often use “branches”. These are alternative realities of your code-base, and you can jump back and forth between them like &lt;a href=&quot;https://marvelcinematicuniverse.fandom.com/wiki/Doctor_Strange&quot;&gt;Dr. Strange&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead of the mess above, let’s simplify our &lt;code&gt;git&lt;/code&gt; commit history such that it looks like a straight string of pearls. In the following visualizations, time progresses towards the right. The horizontal lines represent branches, and the nodes on them are commits with a certain commit message. They &lt;em&gt;also&lt;/em&gt; have a specific fingerprint, called “hash”, that uniquely identifies them. We will come back to that later.&lt;/p&gt;
&lt;p&gt;When we work on a feature or a bugfix (or anything, really) we usually do that on a separate branch, nicely separated. After we finished working on this branch, we want to &lt;em&gt;somehow&lt;/em&gt; get the changes we made back onto the &lt;code&gt;main&lt;/code&gt; branch. There are different approaches for that.&lt;/p&gt;
&lt;h3 id=&quot;merge-commit&quot;&gt;Merge Commit&lt;/h3&gt;
&lt;p&gt;“Standard” merge commits leave the history where exactly the code came from intact. An extra “merge commit” contains the changes from our &lt;code&gt;feature&lt;/code&gt; branch.&lt;/p&gt;
&lt;h3 id=&quot;rebase&quot;&gt;Rebase&lt;/h3&gt;
&lt;p&gt;Another way to keep the &lt;code&gt;git&lt;/code&gt; history linear is “rebasing”. This approach basically re-plays the new commits that happened on the &lt;code&gt;feature&lt;/code&gt; branch onto the &lt;code&gt;main&lt;/code&gt; branch. This means that there is no “merge commit” on the &lt;code&gt;main&lt;/code&gt; branch anymore. However, if there have been commits to &lt;code&gt;main&lt;/code&gt; after &lt;code&gt;feature&lt;/code&gt; has been branched off, the &lt;code&gt;feature&lt;/code&gt; commits are re-written. Do you remember the “hash” fingerprint, I mentioned before? Here it becomes important. When rebasing, the commit content and commit messages are the same, but since these are effectively “new” commits, the commit hashes are different! This means that anything that was attached to a certain hash, like signatures or tags, will point to the commits on the &lt;code&gt;feature&lt;/code&gt; branch. To demonstrate this, we attached a tag &lt;code&gt;v1.0.0&lt;/code&gt; to one commit on the &lt;code&gt;feature&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;Do you see how the tag is kept dangling on the now useless feature branch?&lt;/p&gt;
&lt;h3 id=&quot;fast-forward-merging&quot;&gt;Fast-forward Merging&lt;/h3&gt;
&lt;p&gt;“Fast-forward” merging can be achieved if &lt;code&gt;main&lt;/code&gt; did &lt;em&gt;not receive any commits&lt;/em&gt; in the meantime. So clean! Instead of re-writing the commits onto another branch, the &lt;code&gt;main&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;feature&lt;/code&gt; commits are basically pointers to the exact same commit.&lt;/p&gt;
&lt;p&gt;This looks very similar to rebasing, does it not?&lt;/p&gt;
&lt;p&gt;In fact, if the main branch did not receive any new commits since the branching, fast-forward merging is the same as rebasing…&lt;/p&gt;
&lt;h2 id=&quot;github-rebasing&quot;&gt;GitHub Rebasing&lt;/h2&gt;
&lt;p&gt;…unless you are using the GitHub web interface. When you rebase a &lt;code&gt;feature&lt;/code&gt; branch on GitHub onto an untouched &lt;code&gt;main&lt;/code&gt; branch, the commits are still re-written. This is contrary to how &lt;code&gt;git&lt;/code&gt; on the command line works. Why is that such a big deal? The commit messages are the same. The commit content is the same. Why worry about a different commit hash?&lt;/p&gt;
&lt;p&gt;It matters, because lots of things are tied to a commit hash. A commit signature is tied to its hash! The signature gets lost if the hash changes during a rebase. The same holds true for tags. &lt;code&gt;feature&lt;/code&gt; commit tags will point to the commits on the &lt;code&gt;feature&lt;/code&gt; branch, not to the re-written ones on &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;solutions&quot;&gt;Solutions&lt;/h2&gt;
&lt;p&gt;There are two ways to achieve fast-forward merging when using GitHub. One is convoluted and error prone. The other one is cursed. Choose wisely.&lt;/p&gt;
&lt;h3 id=&quot;using-local-git&quot;&gt;Using Local &lt;code&gt;git&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Protecting your &lt;code&gt;main&lt;/code&gt; branch means that you can’t commit to it directly. You can, however, push sanctioned changes from &lt;code&gt;main&lt;/code&gt; to your remote repository on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;. Wait, what? I thought you can’t touch &lt;code&gt;main&lt;/code&gt;? Follow me, I’ll show you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a pull request from &lt;code&gt;feature&lt;/code&gt; to &lt;code&gt;main&lt;/code&gt; on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open a terminal and create some magic:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;cd your/project/folder     # cd into your project directory
git pull    # get the latest changes to your local computer
git switch main    # select the &lt;code&gt;main&lt;/code&gt; branch, if necessary
git merge —ff-only feature    # ff-merge feature onto main
git push      # allowed! because you created a pull request&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pull request is automatically closed 🪄&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While rather low-tech, this relies on the workflow and discipline of the developers to work. This is a danger zone. It is 4:55pm on a Friday afternoon. You opened a pull request to contribute your work on the &lt;code&gt;feature&lt;/code&gt; branch and now watch patiently how the green circle closes that shows that all CI tests passed. Your fingers itch to wrap things up quickly so you can go home and wolf down the lasagna you prepared already the day before.&lt;/p&gt;
&lt;p&gt;The mouse cursor hovers over the fat, green “Merge pull request” button.&lt;/p&gt;
&lt;p&gt;Don’t. Don’t do it.Stop! Resist the temptation!**&lt;/p&gt;
&lt;p&gt;Click that button and you need to spend the next half hour undoing the rebased, re-written commits to &lt;code&gt;main&lt;/code&gt;, while sweating profusely because now you are messing directly with the &lt;code&gt;main&lt;/code&gt; branch, which you tried to prevent by protecting it in the first place. And by now, at home, your partner has finished both their and your piece of the lasagna.&lt;/p&gt;
&lt;p&gt;Instead of following the suggested path, you need to step away from the browser and open the terminal. You pull the changes, fast-forward merge locally and finally push to &lt;code&gt;main&lt;/code&gt;, as shown above.&lt;/p&gt;
&lt;h3 id=&quot;using-actions&quot;&gt;Using Actions&lt;/h3&gt;
&lt;p&gt;This approach needs some set-up, but is safer to use afterwards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disable the Merge Button&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We have learned now that the fat, green “Merge” button is dangerous², so we need to disable it. In your GitHub repository, go to&lt;/p&gt;
&lt;p&gt;Settings &lt;em&gt;→&lt;/em&gt; General &lt;em&gt;→&lt;/em&gt; Pull Requests*&lt;/p&gt;
&lt;p&gt;and allow only Squash Merging. Next, go to&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Settings &lt;em&gt;→&lt;/em&gt; Rules &lt;em&gt;→&lt;/em&gt; Rulesets&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;and add a new rule. Name it &lt;code&gt;disable_merge_button&lt;/code&gt;, set it to “Active”. Set the “Target branches” to the “default branch” a.k.a main . Check “Require a pull request before merging” and, while waving a magic wand, set “Allowed merge methods” to “Rebase”, contradicting the general repository settings. Check whichever other settings you would like and click on “Save changes”.&lt;/p&gt;
&lt;p&gt;Now pull requests cannot be merged anymore. Yay?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automate the Wizardry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Set up the “Fast Forward Merge” Action from the GitHub Marketplace: &lt;a href=&quot;https://github.com/marketplace/actions/fast-forward-merge&quot;&gt;https://github.com/marketplace/actions/fast-forward-merge&lt;/a&gt; . This gives you two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A message posted in the PR chat indicating whether fast-forward merging is possible.&lt;/li&gt;
&lt;li&gt;A GitHub Action that fast-forward merges your Pull Request. You trigger it by commenting &lt;code&gt;/fast-forward&lt;/code&gt; in the Pull Request chat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;N.B.: For the triggered ff-merge to work, the Action yml file has to already exist in the main branch. So you have to get it there &lt;em&gt;once&lt;/em&gt; via impure means.&lt;/p&gt;
&lt;p&gt;It works. Yet it feels dirty. You just made a forbidden deal with C̶t̶h̶u̶l̶h̶u̶ Octocat and you will probably need to sacrifice the lasagna you made so it does not come to haunt you at night.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-Up&lt;/h2&gt;
&lt;p&gt;By now you not only know what fast-forward merging is, you also have ways to use it on your external repository on &lt;a href=&quot;https://github.com&quot;&gt;github.com&lt;/a&gt;. You might have subscribed to &lt;a href=&quot;https://github.com/orgs/community/discussions/4618&quot;&gt;github.com/orgs/community/discussions/4618&lt;/a&gt; and now patiently wait for the powers-that-be to enable this feature on their website.&lt;/p&gt;
&lt;p&gt;Until that happens, feel free to choose one of the workarounds outlined above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Upvote count combines upvotes and thumbs-up from &lt;a href=&quot;https://github.com/orgs/community/discussions/4618&quot;&gt;https://github.com/orgs/community/discussions/4618&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you want to achieve fast-forward merging, that is.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cross post: &lt;a href=&quot;https://ole.mn/posts/fast-forward-github/&quot;&gt;https://ole.mn/posts/fast-forward-github/&lt;/a&gt;&lt;/p&gt;</content:encoded><author>ole</author></item><item><title>FAIR principles: 5000 years of common sense</title><link>https://blog.esciencecenter.nl/posts/2025-02-20---fair-principles-5000-years-of-common-sense</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-02-20---fair-principles-5000-years-of-common-sense</guid><description>&lt;p&gt;The FAIR acronym stands for Findable, Accessible, Interoperable and Reusable. If you are a researcher, certainly you’ve heard about FAIR principles. FAIR data, FAIR software, … It may sound as another extra, new responsibility to take care of. But, is it? We argue it is not extra, and most importantly, it’s definitely not new. Come with us on a journey through the history of knowledge sharing.&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://javierdelacueva.es/&quot;&gt;Javier de la Cueva&lt;/a&gt;, with &lt;a href=&quot;https://pabrod.github.io/&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; as coauthor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;FAIR principles: 5000 years of common sense&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;342&quot; src=&quot;https://blog.esciencecenter.nl/_astro/fair-principles-5000-years-of-common-sen-e12a18c3.CXM7Q9rk_Z1qfUac.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@paulmelki?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Paul Melki&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;seminal paper&lt;/a&gt; where the FAIR guiding principles were stated was published in the year 2016. If you are a researcher, most certainly you would have heard about FAIR principles, FAIR data or FAIR research software.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Backronym&quot;&gt;backronym&lt;/a&gt; FAIR stands for Findable, Accessible, Interoperable and Reusable. In many forums, FAIR principles are understood as a new added responsibility to take care of by science and data practitioners. Contrary to this idea, we argue that to comply with the FAIR guiding principles is not a novel requirement. Indeed, the ideas behind the FAIR guiding principles are no less than 5000 years old, and can be traced back to the first libraries.&lt;/p&gt;
&lt;p&gt;If a name is an acronym, it is likely to be a buzzword. According to &lt;a href=&quot;https://en.wikipedia.org/wiki/Postmodernism%2C_or%2C_the_Cultural_Logic_of_Late_Capitalism&quot;&gt;Fredric Jameson&lt;/a&gt;, postmodernism is characterized by a permanent rebranding of old concepts so they may be commercialized again as new. And, indeed, FAIR is an acronym. It is often applied to research data, research software and even, although less often, to research publications. We argue that, contrary to other acronyms, FAIR is here to stay. Why? Because it is not a rebranding but the logical evolution in the digital realm of the principles that governed the analogical archives.&lt;/p&gt;
&lt;h2 id=&quot;a-fair-library&quot;&gt;A FAIR library&lt;/h2&gt;
&lt;p&gt;Let’s forget about the digital world for a moment and take a walk to the neighborhood’s library. There we are, surrounded by elderly people quietly reading their newspapers, kids attending read-aloud sessions, students… well, studying, and all kind of people borrowing and returning books.&lt;/p&gt;
&lt;p&gt;Let’s take a look around with the FAIR principles in mind.&lt;/p&gt;
&lt;h2 id=&quot;findable&quot;&gt;Findable&lt;/h2&gt;
&lt;p&gt;The materials in the library are certainly findable. A good library contains thousands of volumes, so they better have a system in place. This is as true today as it was in the library of Alexandria. Some of us still remember the times when this system was a set of cardboard boxes. Nowadays, the system is usually digital. You can even browse it from home!&lt;/p&gt;
&lt;h2 id=&quot;accessible&quot;&gt;Accessible&lt;/h2&gt;
&lt;p&gt;Accessibility is also a trademark of public libraries. The building itself usually can be freely accessed by anyone, and memberships are free or, worst case scenario, very affordable.&lt;/p&gt;
&lt;p&gt;Furthermore, many libraries have sections with materials for users with special needs. Audiobooks, books typed in Braille or in extra large fonts or simplified-language versions.&lt;/p&gt;
&lt;h2 id=&quot;interoperable&quot;&gt;Interoperable&lt;/h2&gt;
&lt;p&gt;Standardized fonts are one of those everyday wonders we don’t even realize anymore. Can you imagine how hard would it be to read if all the content was hand-written, with the unique scripting style of each author?&lt;/p&gt;
&lt;p&gt;Even more, think of word separation. Believe it or not, thefactthatwedonotwritelikethis is a relatively late development. We take spaces between written words for granted, but they are an example of technology.&lt;/p&gt;
&lt;p&gt;And of course, translations allow readers to operate with books originally written in languages unknown to them.&lt;/p&gt;
&lt;h2 id=&quot;reusable&quot;&gt;Reusable&lt;/h2&gt;
&lt;p&gt;How do you reuse a book’s content? Well, by using the most quintessential library service: borrow and return.&lt;/p&gt;
&lt;p&gt;Citing a book is also a form of reusablity. In some cases, you can even go further than citing and create derivatives from it. Think of for instance of encyclopediae and dictionaries. Those are composed works, with many authors and, to a large extent, independent entries. They are, by definition, work in progress.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The attentive reader certainly noticed that some of the features of books and libraries could fit in more than one FAIR concepts. For instance, are standardized fonts improving accessibility or interoperability? What about translations? Please don’t take our examples as a matter of rigorous taxonomy, but stick to the spirit of the idea.&lt;/p&gt;
&lt;p&gt;When looking back in history, it is tempting to stop too early back in time. Instead of going back only 20 years, let’s explore a bit deeper. Let’s not fall victims of the palimpsestic syndrome, i.e.*: attributing the creation of a concept to the first person or institution you heard it from. All of the FAIR principles, with minor adjustments, have been present since literally millenia ago in the world of books.&lt;/p&gt;
&lt;p&gt;We also need the FAIR principles to fight the &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;reproducibility crisis&lt;/a&gt; that is taking place in science as we speak. And keep in mind that reproducibility is not only desirable, but a defining feature of scientific knowledge.&lt;/p&gt;
&lt;p&gt;So no, FAIR principles are not new. And no, FAIR principles are not optional. Not bad for a buzzword!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;We want to express our gratitude to &lt;a href=&quot;https://www.esciencecenter.nl/team/lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martínez-Ortiz&lt;/a&gt; for their excellent feedback.&lt;/p&gt;</description><pubDate>Thu, 20 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The FAIR acronym stands for Findable, Accessible, Interoperable and Reusable. If you are a researcher, certainly you’ve heard about FAIR principles. FAIR data, FAIR software, … It may sound as another extra, new responsibility to take care of. But, is it? We argue it is not extra, and most importantly, it’s definitely not new. Come with us on a journey through the history of knowledge sharing.&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://javierdelacueva.es/&quot;&gt;Javier de la Cueva&lt;/a&gt;, with &lt;a href=&quot;https://pabrod.github.io/&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; as coauthor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;FAIR principles: 5000 years of common sense&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;342&quot; src=&quot;https://blog.esciencecenter.nl/_astro/fair-principles-5000-years-of-common-sen-e12a18c3.CXM7Q9rk_Z1qfUac.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@paulmelki?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Paul Melki&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;seminal paper&lt;/a&gt; where the FAIR guiding principles were stated was published in the year 2016. If you are a researcher, most certainly you would have heard about FAIR principles, FAIR data or FAIR research software.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Backronym&quot;&gt;backronym&lt;/a&gt; FAIR stands for Findable, Accessible, Interoperable and Reusable. In many forums, FAIR principles are understood as a new added responsibility to take care of by science and data practitioners. Contrary to this idea, we argue that to comply with the FAIR guiding principles is not a novel requirement. Indeed, the ideas behind the FAIR guiding principles are no less than 5000 years old, and can be traced back to the first libraries.&lt;/p&gt;
&lt;p&gt;If a name is an acronym, it is likely to be a buzzword. According to &lt;a href=&quot;https://en.wikipedia.org/wiki/Postmodernism%2C_or%2C_the_Cultural_Logic_of_Late_Capitalism&quot;&gt;Fredric Jameson&lt;/a&gt;, postmodernism is characterized by a permanent rebranding of old concepts so they may be commercialized again as new. And, indeed, FAIR is an acronym. It is often applied to research data, research software and even, although less often, to research publications. We argue that, contrary to other acronyms, FAIR is here to stay. Why? Because it is not a rebranding but the logical evolution in the digital realm of the principles that governed the analogical archives.&lt;/p&gt;
&lt;h2 id=&quot;a-fair-library&quot;&gt;A FAIR library&lt;/h2&gt;
&lt;p&gt;Let’s forget about the digital world for a moment and take a walk to the neighborhood’s library. There we are, surrounded by elderly people quietly reading their newspapers, kids attending read-aloud sessions, students… well, studying, and all kind of people borrowing and returning books.&lt;/p&gt;
&lt;p&gt;Let’s take a look around with the FAIR principles in mind.&lt;/p&gt;
&lt;h2 id=&quot;findable&quot;&gt;Findable&lt;/h2&gt;
&lt;p&gt;The materials in the library are certainly findable. A good library contains thousands of volumes, so they better have a system in place. This is as true today as it was in the library of Alexandria. Some of us still remember the times when this system was a set of cardboard boxes. Nowadays, the system is usually digital. You can even browse it from home!&lt;/p&gt;
&lt;h2 id=&quot;accessible&quot;&gt;Accessible&lt;/h2&gt;
&lt;p&gt;Accessibility is also a trademark of public libraries. The building itself usually can be freely accessed by anyone, and memberships are free or, worst case scenario, very affordable.&lt;/p&gt;
&lt;p&gt;Furthermore, many libraries have sections with materials for users with special needs. Audiobooks, books typed in Braille or in extra large fonts or simplified-language versions.&lt;/p&gt;
&lt;h2 id=&quot;interoperable&quot;&gt;Interoperable&lt;/h2&gt;
&lt;p&gt;Standardized fonts are one of those everyday wonders we don’t even realize anymore. Can you imagine how hard would it be to read if all the content was hand-written, with the unique scripting style of each author?&lt;/p&gt;
&lt;p&gt;Even more, think of word separation. Believe it or not, thefactthatwedonotwritelikethis is a relatively late development. We take spaces between written words for granted, but they are an example of technology.&lt;/p&gt;
&lt;p&gt;And of course, translations allow readers to operate with books originally written in languages unknown to them.&lt;/p&gt;
&lt;h2 id=&quot;reusable&quot;&gt;Reusable&lt;/h2&gt;
&lt;p&gt;How do you reuse a book’s content? Well, by using the most quintessential library service: borrow and return.&lt;/p&gt;
&lt;p&gt;Citing a book is also a form of reusablity. In some cases, you can even go further than citing and create derivatives from it. Think of for instance of encyclopediae and dictionaries. Those are composed works, with many authors and, to a large extent, independent entries. They are, by definition, work in progress.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The attentive reader certainly noticed that some of the features of books and libraries could fit in more than one FAIR concepts. For instance, are standardized fonts improving accessibility or interoperability? What about translations? Please don’t take our examples as a matter of rigorous taxonomy, but stick to the spirit of the idea.&lt;/p&gt;
&lt;p&gt;When looking back in history, it is tempting to stop too early back in time. Instead of going back only 20 years, let’s explore a bit deeper. Let’s not fall victims of the palimpsestic syndrome, i.e.*: attributing the creation of a concept to the first person or institution you heard it from. All of the FAIR principles, with minor adjustments, have been present since literally millenia ago in the world of books.&lt;/p&gt;
&lt;p&gt;We also need the FAIR principles to fight the &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;reproducibility crisis&lt;/a&gt; that is taking place in science as we speak. And keep in mind that reproducibility is not only desirable, but a defining feature of scientific knowledge.&lt;/p&gt;
&lt;p&gt;So no, FAIR principles are not new. And no, FAIR principles are not optional. Not bad for a buzzword!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;We want to express our gratitude to &lt;a href=&quot;https://www.esciencecenter.nl/team/lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martínez-Ortiz&lt;/a&gt; for their excellent feedback.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/fair-principles-5000-years-of-common-sen-e12a18c3.CXM7Q9rk.jpg" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Reproducible research with The Turing Way</title><link>https://blog.esciencecenter.nl/posts/2025-02-10---reproducible-research-with-the-turing-way</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-02-10---reproducible-research-with-the-turing-way</guid><description>&lt;h2 id=&quot;the-netherlands-escience-center-and-turing-way-have-long-been-collaborating-on-the-common-goal-to-improve-reproducible-research-practices&quot;&gt;&lt;em&gt;The Netherlands eScience Center and Turing Way have long been collaborating on the common goal to improve reproducible research practices&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;A long time ago, in the far-away Amsterdam Science Park, the eScience Center created their own “&lt;a href=&quot;https://guide.esciencecenter.nl/&quot;&gt;eScience Center software development guide&lt;/a&gt;”. The aim of The Guide was for our RSEs to have a starting point to learn about how to write research software in adherence to open science practices. In other words, reproducible research software.&lt;/p&gt;
&lt;p&gt;After a few years, we came across &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;, and saw that there was a lot of overlap between our goals: we both wanted to share good practices in reproducible research in general, and reproducible research software specifically.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reproducible research with The Turing Way&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;522&quot; src=&quot;https://blog.esciencecenter.nl/_astro/reproducible-research-with-the-turing-wa-c5be87d6.CPPUEa3s_28q7kT.webp&quot; srcset=&quot;&quot;&gt;
Image by &lt;a href=&quot;https://www.scriberia.com/&quot;&gt;Scriberia&lt;/a&gt;In 2020, we decided to migrate our content to &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;, with a few exceptions. Our rule of thumb is: all content which is interesting to a general audience should be in &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; and; content which is eScience Center specific, should go in The Guide. For instance, the description of &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/licensing&quot;&gt;why one should use a license&lt;/a&gt; goes in The Turing Way, whereas &lt;a href=&quot;https://guide.esciencecenter.nl/#/best_practices?id=licensing&quot;&gt;our decision to use Apache2&lt;/a&gt;, goes in The Guide.&lt;/p&gt;
&lt;p&gt;We used to block time to work on The Guide (“guide sprints”), which was essentially the same concept as the “Book Dash” events. We decided, in the spirit of open science, to NOT duplicate efforts, but instead dedicate our efforts in contributing to &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;. For a few years now, we have been (together with colleagues at VU Amsterdam and TU/Delft) involved in organizing local Book Dash events.&lt;/p&gt;
&lt;p&gt;At a personal level, being involved in the project has allowed me to learn a lot about how to contribute to an open science community. Specifically, a community that works on a project based on Open Source principles — and you don’t have to be a skilled developer to contribute. I have also met many knowledgeable inspiring people! I have felt really welcome as part of the community.&lt;/p&gt;
&lt;p&gt;For the last couple of years, I have also been involved in the Book Dash working group. In this group, I am involved in planning the Book Dash events, and try to encourage the (remote) participation of the Dutch community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reproducible research with The Turing Way&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;560&quot; src=&quot;https://blog.esciencecenter.nl/_astro/reproducible-research-with-the-turing-wa-bb58223c.BAYU7S73_Z1Uuvws.webp&quot; srcset=&quot;&quot;&gt;
Image by &lt;a href=&quot;https://www.scriberia.com/&quot;&gt;Scriberia&lt;/a&gt;&lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;The Turing Way*&lt;/a&gt; has become an important reference resource for our internal use and as part of the resources we share with the research community in the Netherlands.&lt;/p&gt;
&lt;p&gt;Beyond the multiple times on this blog, &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; is mentioned in: our internal Project Management Protocol and our internal training resources, our &lt;a href=&quot;https://esciencecenter-digital-skills.github.io/research-software-support/&quot;&gt;Research Software Support&lt;/a&gt; training materials, our &lt;a href=&quot;https://doi.org/10.5281/zenodo.7038280&quot;&gt;Practical Guide to Software Management Plans&lt;/a&gt; and training materials developed in our &lt;a href=&quot;https://tdcc.nl/projects/project-initiatives-nes/tdcc-nes-bottleneck-projects/best-practices-for-sustainable-software/&quot;&gt;Best Practices for Sustainable software&lt;/a&gt; project point to different chapters as reference resources. It will also be part of the reference resources for the &lt;a href=&quot;https://everse.software/RSQKit/&quot;&gt;EVERSE Research Software Quality kit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the eScience Center,* &lt;em&gt;&lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; *is a priceless resource for sharing our expertise in contributing to reproducible research software.&lt;/p&gt;
&lt;p&gt;Has &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; helped you in your work? Please share your story &lt;a href=&quot;https://github.com/the-turing-way/the-turing-way/issues/4032#top&quot;&gt;here&lt;/a&gt;. If you are interested in joining a Book Dash, you can contact &lt;a href=&quot;https://github.com/c-martinez&quot;&gt;Carlos&lt;/a&gt; or &lt;a href=&quot;https://github.com/the-turing-way/the-turing-way?tab=readme-ov-file#get-in-touch&quot;&gt;get in touch&lt;/a&gt; with &lt;em&gt;The Turing Way&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 10 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-netherlands-escience-center-and-turing-way-have-long-been-collaborating-on-the-common-goal-to-improve-reproducible-research-practices&quot;&gt;&lt;em&gt;The Netherlands eScience Center and Turing Way have long been collaborating on the common goal to improve reproducible research practices&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;A long time ago, in the far-away Amsterdam Science Park, the eScience Center created their own “&lt;a href=&quot;https://guide.esciencecenter.nl/&quot;&gt;eScience Center software development guide&lt;/a&gt;”. The aim of The Guide was for our RSEs to have a starting point to learn about how to write research software in adherence to open science practices. In other words, reproducible research software.&lt;/p&gt;
&lt;p&gt;After a few years, we came across &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;, and saw that there was a lot of overlap between our goals: we both wanted to share good practices in reproducible research in general, and reproducible research software specifically.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reproducible research with The Turing Way&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;522&quot; src=&quot;https://blog.esciencecenter.nl/_astro/reproducible-research-with-the-turing-wa-c5be87d6.CPPUEa3s_28q7kT.webp&quot; srcset=&quot;&quot;&gt;
Image by &lt;a href=&quot;https://www.scriberia.com/&quot;&gt;Scriberia&lt;/a&gt;In 2020, we decided to migrate our content to &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;, with a few exceptions. Our rule of thumb is: all content which is interesting to a general audience should be in &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; and; content which is eScience Center specific, should go in The Guide. For instance, the description of &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/licensing&quot;&gt;why one should use a license&lt;/a&gt; goes in The Turing Way, whereas &lt;a href=&quot;https://guide.esciencecenter.nl/#/best_practices?id=licensing&quot;&gt;our decision to use Apache2&lt;/a&gt;, goes in The Guide.&lt;/p&gt;
&lt;p&gt;We used to block time to work on The Guide (“guide sprints”), which was essentially the same concept as the “Book Dash” events. We decided, in the spirit of open science, to NOT duplicate efforts, but instead dedicate our efforts in contributing to &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;. For a few years now, we have been (together with colleagues at VU Amsterdam and TU/Delft) involved in organizing local Book Dash events.&lt;/p&gt;
&lt;p&gt;At a personal level, being involved in the project has allowed me to learn a lot about how to contribute to an open science community. Specifically, a community that works on a project based on Open Source principles — and you don’t have to be a skilled developer to contribute. I have also met many knowledgeable inspiring people! I have felt really welcome as part of the community.&lt;/p&gt;
&lt;p&gt;For the last couple of years, I have also been involved in the Book Dash working group. In this group, I am involved in planning the Book Dash events, and try to encourage the (remote) participation of the Dutch community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reproducible research with The Turing Way&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;560&quot; src=&quot;https://blog.esciencecenter.nl/_astro/reproducible-research-with-the-turing-wa-bb58223c.BAYU7S73_Z1Uuvws.webp&quot; srcset=&quot;&quot;&gt;
Image by &lt;a href=&quot;https://www.scriberia.com/&quot;&gt;Scriberia&lt;/a&gt;&lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;The Turing Way*&lt;/a&gt; has become an important reference resource for our internal use and as part of the resources we share with the research community in the Netherlands.&lt;/p&gt;
&lt;p&gt;Beyond the multiple times on this blog, &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; is mentioned in: our internal Project Management Protocol and our internal training resources, our &lt;a href=&quot;https://esciencecenter-digital-skills.github.io/research-software-support/&quot;&gt;Research Software Support&lt;/a&gt; training materials, our &lt;a href=&quot;https://doi.org/10.5281/zenodo.7038280&quot;&gt;Practical Guide to Software Management Plans&lt;/a&gt; and training materials developed in our &lt;a href=&quot;https://tdcc.nl/projects/project-initiatives-nes/tdcc-nes-bottleneck-projects/best-practices-for-sustainable-software/&quot;&gt;Best Practices for Sustainable software&lt;/a&gt; project point to different chapters as reference resources. It will also be part of the reference resources for the &lt;a href=&quot;https://everse.software/RSQKit/&quot;&gt;EVERSE Research Software Quality kit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the eScience Center,* &lt;em&gt;&lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; *is a priceless resource for sharing our expertise in contributing to reproducible research software.&lt;/p&gt;
&lt;p&gt;Has &lt;a href=&quot;https://book.the-turing-way.org/&quot;&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt; helped you in your work? Please share your story &lt;a href=&quot;https://github.com/the-turing-way/the-turing-way/issues/4032#top&quot;&gt;here&lt;/a&gt;. If you are interested in joining a Book Dash, you can contact &lt;a href=&quot;https://github.com/c-martinez&quot;&gt;Carlos&lt;/a&gt; or &lt;a href=&quot;https://github.com/the-turing-way/the-turing-way?tab=readme-ov-file#get-in-touch&quot;&gt;get in touch&lt;/a&gt; with &lt;em&gt;The Turing Way&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/reproducible-research-with-the-turing-wa-c5be87d6.CPPUEa3s.png" medium="image"/><author>Carlos Martinez-Ortiz</author></item><item><title>A Different Game</title><link>https://blog.esciencecenter.nl/posts/2025-01-28---a-different-game</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-01-28---a-different-game</guid><description>&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;em&gt;According to a panel of football experts, the world’s best male player of the year 2024 was Rodri. The choice is naturally debatable, but even if you put him together with other stars like Erling Haaland and Kylian Mbappé, they will not stand a chance in a match against a full team of 11 amateurs. The world stars could perform great dribblings and accurate passes, but they cannot play the team sport called football.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;To build complex software, highly skilled programmers are essential. But only effective collaboration enables them to achieve big things in the world of modern software engineering.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-f432a766.ChfXoZ1z_ZQPtfd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@rleija_?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Ruben Leija&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;from-programmer-to-software-engineer&quot;&gt;From Programmer to Software Engineer&lt;/h2&gt;
&lt;p&gt;At the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, we do not play football, but we develop research software. We also teach &lt;a href=&quot;https://www.esciencecenter.nl/training-materials/&quot;&gt;courses and workshops&lt;/a&gt;, including &lt;em&gt;Collaborative Software Development&lt;/em&gt;. Compared to workshops about Deep Learning or GPU Programming, tools like &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt;, &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://gitlab.com/&quot;&gt;GitLab&lt;/a&gt; may not seem very advanced. Nevertheless, at the end of some workshops, some participants almost refuse to leave the room, enthusiastically finishing the collaborative setup for a project. Also, I vividly remember how a partner of ours spontaneously mentioned her most important learning while working with us: “I learned to cooperate with others!”&lt;/p&gt;
&lt;p&gt;The impact that the relatively little technical learnings have on the personal progress seems almost unreasonably large. That is because we do not just teach how to use the Git ecosystem, but how to collaborate. Mastering the tools gives a glimpse at another level of software development that may have seemed unreachable for many programmers — like a lonely football player that has practised his or her skills on the ball and suddenly finds themselves in a well-organized team of players.&lt;/p&gt;
&lt;p&gt;It is not a coincidence that Git was invented by the initiator of the most prominent open-source software. With his initial versions of Linux, Linus Torvalds made a great start. However, without good tooling, collaboration causes friction. To use &lt;a href=&quot;https://ideas.ted.com/the-wisdom-of-linus-torvalds/&quot;&gt;Linus’ own words&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We were in this bad spot where we had thousands of people who wanted to participate, but in many ways I was the break point.&lt;/p&gt;
&lt;p&gt;On his own, Linus could never have developed an operating system that now runs on millions of computers, including high-performance clusters, desktop PCs, laptops, phones, embedded systems and more. Seamless collaboration is the key:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The big point for me was not being alone and having ten, maybe 100 people being involved. […] Going from 100 people to a million people is not a big deal.&lt;/p&gt;
&lt;p&gt;The open-source software community turned Linux into high quality software in which bugs are fixed at a speed that software companies could only dream of, and new features come in by the day.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-9cf5e1f7.CBj888-K_Z2cJmk6.webp&quot; srcset=&quot;&quot;&gt;
A graph showing contributions to a Git repository.Epiphany moments emerge when individual software engineers realize — for instance during a workshop — that they can reach that new level of software engineering. In a collaborative setting, tools and methods like version control, automated testing, &lt;a href=&quot;https://en.wikipedia.org/wiki/Lint_%28software%29&quot;&gt;linting&lt;/a&gt;, and &lt;a href=&quot;https://www.redhat.com/en/topics/devops/what-is-ci-cd&quot;&gt;continuous integration&lt;/a&gt; are no longer merely aesthetic practices. Not surprisingly: the rules of the game make sense once you play it.&lt;/p&gt;
&lt;h2 id=&quot;incentives&quot;&gt;Incentives?&lt;/h2&gt;
&lt;p&gt;Software engineers working in the industry often pride themselves on their practical engineering skills. Partly understandably, because even Computer Science PhDs, hence highly skilled individuals, can seem like novices when they join a team and don’t know how to collaborate with them. This is, however, a comparison between players of different games: individual programming and collaborative software development, respectively.&lt;/p&gt;
&lt;p&gt;For a company, the ability to develop software collaboratively is essential to survive after the start-up stage. If they do not adopt methods to join their forces effectively, their software engineers drown in a swamp of ever-increasing maintenance efforts and dependencies on individualized knowledge.&lt;/p&gt;
&lt;h2 id=&quot;reality-check&quot;&gt;Reality Check&lt;/h2&gt;
&lt;p&gt;So why is collaborative software development not the default method? One reason is that collaborative methods imply some overhead: developers need to invest time in learning to apply the tools — which only pays off in a team that thinks beyond short-term goals.&lt;/p&gt;
&lt;p&gt;But collaborative development is more than tooling: it also requires open communication and mutual trust, which often comes into conflict with hierarchies and individualized reward systems. Each member of a team needs to find intrinsic motivation and confidence that they can contribute something meaningful.&lt;/p&gt;
&lt;p&gt;Collaborative development principles often compete with existing incentives. In academia, software may be necessary to run an experiment, but is frequently abandoned as soon as the corresponding paper is published. Terms like “project-ware”, “PhD-ware” and “professor-ware” are typically not used in a positive way, but the one-off approach concurs with the fact that individual performance is measured by the number of publications.&lt;/p&gt;
&lt;p&gt;Developing software so that other researchers can extend it for their own experiments brings no benefit — in a highly competitive environment, the opposite might even be the case. In the football analogy: a striker that is measured by how well they can shoot penalties does not benefit from practicing combination play with the team.&lt;/p&gt;
&lt;p&gt;The same applies in industry settings, even though playing the team game is more fundamental. Anyway, developers are hired, promoted and fired based on their individual performances. An engineer who quickly drops a new feature into production is more likely to be perceived as a mythical 10x engineer* than their peer who makes sure it still works after the next update, for instance by implementing integration tests.&lt;/p&gt;
&lt;h2 id=&quot;agile-waterfall-and-hierarchies&quot;&gt;Agile, Waterfall and Hierarchies&lt;/h2&gt;
&lt;p&gt;How to tackle the complexities of software development has been a hot topic for decades. The &lt;em&gt;Waterfall&lt;/em&gt; approach tries to plan a project as a sequence of clearly defined steps that eventually lead to the finish line. In the reality of software engineering, however, that finish line tends to be moving, while the intermediate steps face unforeseen obstacles and complexities that cannot be fully grasped by an individual engineer.&lt;/p&gt;
&lt;p&gt;To account for the inherent dynamics of software development, &lt;em&gt;Agile&lt;/em&gt; methods have proposed that planning has to be refined iteratively, involving continuous interaction between all stakeholders — requiring effective collaboration on various levels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-351e29e4.BEoFyw-g_ZBzg6q.webp&quot; srcset=&quot;&quot;&gt;
Collaboration is more than learning how to use Git. *Photo by Lisamarie Babik — Ted &amp;#x26; Ian. Uploaded by Edward, CC BY 2.0, *&lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=9546406&quot;&gt;&lt;em&gt;https://commons.wikimedia.org/w/index.php?curid=9546406&lt;/em&gt;&lt;/a&gt;However, the reality of organizational hierarchies, project-based budgeting and purely individual accountability conflicts with the radical changes that are required to have teams that can refine their (intermediate) goals autonomously. In practice, &lt;em&gt;Agile&lt;/em&gt; therefore often means not much more than introducing a level of fancy terminology and rituals.&lt;/p&gt;
&lt;h2 id=&quot;to-the-next-level&quot;&gt;To the Next Level&lt;/h2&gt;
&lt;p&gt;In any organization, collaboration remains a trade-off between immediate personal advancement on the one hand, and contributing to sustainable, collective progress on the other hand. The feedback that we get at &lt;em&gt;Collaborative Software Development&lt;/em&gt; workshops shows that many people like the team game: it allows them to shine as part of a team that is able to build things far bigger than what any member could achieve on their own.&lt;/p&gt;
&lt;p&gt;The topic of collaborative software development might be so fascinating because it touches upon many issues beyond engineering. Like forming an effective football team, software engineering is a social process that requires technical skills, but can also lead to questions about the structure of an entire organization.&lt;/p&gt;</description><pubDate>Tue, 28 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;em&gt;According to a panel of football experts, the world’s best male player of the year 2024 was Rodri. The choice is naturally debatable, but even if you put him together with other stars like Erling Haaland and Kylian Mbappé, they will not stand a chance in a match against a full team of 11 amateurs. The world stars could perform great dribblings and accurate passes, but they cannot play the team sport called football.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;To build complex software, highly skilled programmers are essential. But only effective collaboration enables them to achieve big things in the world of modern software engineering.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-f432a766.ChfXoZ1z_ZQPtfd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@rleija_?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Ruben Leija&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;from-programmer-to-software-engineer&quot;&gt;From Programmer to Software Engineer&lt;/h2&gt;
&lt;p&gt;At the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, we do not play football, but we develop research software. We also teach &lt;a href=&quot;https://www.esciencecenter.nl/training-materials/&quot;&gt;courses and workshops&lt;/a&gt;, including &lt;em&gt;Collaborative Software Development&lt;/em&gt;. Compared to workshops about Deep Learning or GPU Programming, tools like &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt;, &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://gitlab.com/&quot;&gt;GitLab&lt;/a&gt; may not seem very advanced. Nevertheless, at the end of some workshops, some participants almost refuse to leave the room, enthusiastically finishing the collaborative setup for a project. Also, I vividly remember how a partner of ours spontaneously mentioned her most important learning while working with us: “I learned to cooperate with others!”&lt;/p&gt;
&lt;p&gt;The impact that the relatively little technical learnings have on the personal progress seems almost unreasonably large. That is because we do not just teach how to use the Git ecosystem, but how to collaborate. Mastering the tools gives a glimpse at another level of software development that may have seemed unreachable for many programmers — like a lonely football player that has practised his or her skills on the ball and suddenly finds themselves in a well-organized team of players.&lt;/p&gt;
&lt;p&gt;It is not a coincidence that Git was invented by the initiator of the most prominent open-source software. With his initial versions of Linux, Linus Torvalds made a great start. However, without good tooling, collaboration causes friction. To use &lt;a href=&quot;https://ideas.ted.com/the-wisdom-of-linus-torvalds/&quot;&gt;Linus’ own words&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We were in this bad spot where we had thousands of people who wanted to participate, but in many ways I was the break point.&lt;/p&gt;
&lt;p&gt;On his own, Linus could never have developed an operating system that now runs on millions of computers, including high-performance clusters, desktop PCs, laptops, phones, embedded systems and more. Seamless collaboration is the key:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The big point for me was not being alone and having ten, maybe 100 people being involved. […] Going from 100 people to a million people is not a big deal.&lt;/p&gt;
&lt;p&gt;The open-source software community turned Linux into high quality software in which bugs are fixed at a speed that software companies could only dream of, and new features come in by the day.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-9cf5e1f7.CBj888-K_Z2cJmk6.webp&quot; srcset=&quot;&quot;&gt;
A graph showing contributions to a Git repository.Epiphany moments emerge when individual software engineers realize — for instance during a workshop — that they can reach that new level of software engineering. In a collaborative setting, tools and methods like version control, automated testing, &lt;a href=&quot;https://en.wikipedia.org/wiki/Lint_%28software%29&quot;&gt;linting&lt;/a&gt;, and &lt;a href=&quot;https://www.redhat.com/en/topics/devops/what-is-ci-cd&quot;&gt;continuous integration&lt;/a&gt; are no longer merely aesthetic practices. Not surprisingly: the rules of the game make sense once you play it.&lt;/p&gt;
&lt;h2 id=&quot;incentives&quot;&gt;Incentives?&lt;/h2&gt;
&lt;p&gt;Software engineers working in the industry often pride themselves on their practical engineering skills. Partly understandably, because even Computer Science PhDs, hence highly skilled individuals, can seem like novices when they join a team and don’t know how to collaborate with them. This is, however, a comparison between players of different games: individual programming and collaborative software development, respectively.&lt;/p&gt;
&lt;p&gt;For a company, the ability to develop software collaboratively is essential to survive after the start-up stage. If they do not adopt methods to join their forces effectively, their software engineers drown in a swamp of ever-increasing maintenance efforts and dependencies on individualized knowledge.&lt;/p&gt;
&lt;h2 id=&quot;reality-check&quot;&gt;Reality Check&lt;/h2&gt;
&lt;p&gt;So why is collaborative software development not the default method? One reason is that collaborative methods imply some overhead: developers need to invest time in learning to apply the tools — which only pays off in a team that thinks beyond short-term goals.&lt;/p&gt;
&lt;p&gt;But collaborative development is more than tooling: it also requires open communication and mutual trust, which often comes into conflict with hierarchies and individualized reward systems. Each member of a team needs to find intrinsic motivation and confidence that they can contribute something meaningful.&lt;/p&gt;
&lt;p&gt;Collaborative development principles often compete with existing incentives. In academia, software may be necessary to run an experiment, but is frequently abandoned as soon as the corresponding paper is published. Terms like “project-ware”, “PhD-ware” and “professor-ware” are typically not used in a positive way, but the one-off approach concurs with the fact that individual performance is measured by the number of publications.&lt;/p&gt;
&lt;p&gt;Developing software so that other researchers can extend it for their own experiments brings no benefit — in a highly competitive environment, the opposite might even be the case. In the football analogy: a striker that is measured by how well they can shoot penalties does not benefit from practicing combination play with the team.&lt;/p&gt;
&lt;p&gt;The same applies in industry settings, even though playing the team game is more fundamental. Anyway, developers are hired, promoted and fired based on their individual performances. An engineer who quickly drops a new feature into production is more likely to be perceived as a mythical 10x engineer* than their peer who makes sure it still works after the next update, for instance by implementing integration tests.&lt;/p&gt;
&lt;h2 id=&quot;agile-waterfall-and-hierarchies&quot;&gt;Agile, Waterfall and Hierarchies&lt;/h2&gt;
&lt;p&gt;How to tackle the complexities of software development has been a hot topic for decades. The &lt;em&gt;Waterfall&lt;/em&gt; approach tries to plan a project as a sequence of clearly defined steps that eventually lead to the finish line. In the reality of software engineering, however, that finish line tends to be moving, while the intermediate steps face unforeseen obstacles and complexities that cannot be fully grasped by an individual engineer.&lt;/p&gt;
&lt;p&gt;To account for the inherent dynamics of software development, &lt;em&gt;Agile&lt;/em&gt; methods have proposed that planning has to be refined iteratively, involving continuous interaction between all stakeholders — requiring effective collaboration on various levels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Different Game&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-different-game-351e29e4.BEoFyw-g_ZBzg6q.webp&quot; srcset=&quot;&quot;&gt;
Collaboration is more than learning how to use Git. *Photo by Lisamarie Babik — Ted &amp;#x26; Ian. Uploaded by Edward, CC BY 2.0, *&lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=9546406&quot;&gt;&lt;em&gt;https://commons.wikimedia.org/w/index.php?curid=9546406&lt;/em&gt;&lt;/a&gt;However, the reality of organizational hierarchies, project-based budgeting and purely individual accountability conflicts with the radical changes that are required to have teams that can refine their (intermediate) goals autonomously. In practice, &lt;em&gt;Agile&lt;/em&gt; therefore often means not much more than introducing a level of fancy terminology and rituals.&lt;/p&gt;
&lt;h2 id=&quot;to-the-next-level&quot;&gt;To the Next Level&lt;/h2&gt;
&lt;p&gt;In any organization, collaboration remains a trade-off between immediate personal advancement on the one hand, and contributing to sustainable, collective progress on the other hand. The feedback that we get at &lt;em&gt;Collaborative Software Development&lt;/em&gt; workshops shows that many people like the team game: it allows them to shine as part of a team that is able to build things far bigger than what any member could achieve on their own.&lt;/p&gt;
&lt;p&gt;The topic of collaborative software development might be so fascinating because it touches upon many issues beyond engineering. Like forming an effective football team, software engineering is a social process that requires technical skills, but can also lead to questions about the structure of an entire organization.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-different-game-f432a766.ChfXoZ1z.jpg" medium="image"/><author>Carsten Schnober</author></item><item><title>How to run a containerized Agent-Based Model on HPC</title><link>https://blog.esciencecenter.nl/posts/2025-01-23---how-to-run-a-containerized-agent-based-model-on-hpc</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-01-23---how-to-run-a-containerized-agent-based-model-on-hpc</guid><description>&lt;p&gt;&lt;em&gt;This blog was written by &lt;em&gt;&lt;a href=&quot;https://medium.com/@fdiblen&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/olga-lyashevska/&quot;&gt;&lt;em&gt;Olga Lyashevska&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Imagine you are preparing &lt;a href=&quot;https://en.wikipedia.org/wiki/Torta_caprese&quot;&gt;Torta Caprese&lt;/a&gt; for your friend’s birthday. You have a recipe that consistently delights everyone, but you want to ensure it turns out perfectly every time, regardless of the oven you are baking in or ambient temperature. To achieve this, you always use a cake tin for the batter, which gives its form. In the realm of software development, a similar concept exists — the container. Much like its culinary counterpart, a software container offers a lightweight, consistent and isolated environment for your application, just like the cake tin. The beauty of using a software container is that all the necessary ingredients and instructions are neatly packaged together, including code, dependencies, and runtime environment. This ensures that the application runs consistently and reliably across different computing environments and operating systems.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-642d9679.Bm-OR_PN_ZAnYGI.webp&quot; srcset=&quot;&quot;&gt;
Illustration: generated with &lt;a href=&quot;http://www.midjourney.com&quot;&gt;Midjourney&lt;/a&gt;Introduction**&lt;/p&gt;
&lt;p&gt;In this blog, we provide a step-by-step guide on running a containerized &lt;a href=&quot;https://en.wikipedia.org/wiki/Agent-based_model&quot;&gt;Agent Based Model&lt;/a&gt; (ABM) on High-Performance Computing (HPC) systems. We will explain how to package code and all dependencies in a container and execute on HPC in an easy way. As an example of ABM, we picked &lt;a href=&quot;https://ccl.northwestern.edu/netlogo/&quot;&gt;NetLogo&lt;/a&gt;, a widely popular software among users who may not be technically inclined.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;NetLogo is a multi-agent programmable modeling environment. It is used by tens of thousands of students, teachers and researchers worldwide.&lt;/p&gt;
&lt;p&gt;The steps outlined below are not limited to NetLogo or ABMs; you can follow this guide to run any application in a containerized format on HPC systems. So why might we want to run NetLogo on HPC? Let’s go back to our baker analogy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HPC and its significance in handling complex computational tasks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s imagine that your Torta Caprese has gained immense popularity, and now you are asked to bake it for a friend’s wedding. However, this time, you are not using your humble home oven (desktop computer); instead, you have access to a state-of-the-art industrial oven capable of efficiency and speed. This industrial oven represents HPC systems. HPC systems are known for their ability to process large volumes of data and complex computations at high speed. Do you want to risk any variation in the baking process? No. You are equally meticulous about the execution of your application on the HPC infrastructure. This is where the concept of containerization comes into the picture. By utilizing containers on HPC systems, you ensure that your application runs efficiently and consistently, regardless of the computing environment it is deployed.&lt;/p&gt;
&lt;p&gt;Back to NetLogo. Imagine you have a NetLogo model that has grown too complex and too slow to be run efficiently on your desktop and you decide to run it on HPC system. You have access to the HPC system via secure shell (SSH), but you do not have the necessary permissions to install NetLogo on the system or you do not know how to do it. Perhaps, you may even want to run the model without GUI (Graphical User Interface) because it avoids overhead and makes your model run faster.&lt;/p&gt;
&lt;p&gt;The purpose of this blog is to demonstrate how to run a single Netlogo model on HPC using &lt;a href=&quot;https://apptainer.org/&quot;&gt;Apptainer&lt;/a&gt; container. We use the &lt;a href=&quot;https://ccl.northwestern.edu/netlogo/6.3.0/NetLogo-6.3.0-64.tgz&quot;&gt;Netlogo&lt;/a&gt; distribution as a base for the container. Apptainer allows us to package the model and its dependencies (i.e. Netlogo) in a single image that can be run uniformly across different systems. Apptainer is particularly suitable for HPC, as it is designed to bring containers and reproducibility to the scientific community and does not require admin access to run. The container is then used to run the Netlogo model in headless mode. Headless mode is a mode in which the model is run without the GUI and the output is saved in a csv file.&lt;/p&gt;
&lt;p&gt;Let’s follow the next steps together. But first, you need to make sure that you have the following installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apptainer.org/&quot;&gt;Apptainer&lt;/a&gt; 1.2.5 or newer&lt;/li&gt;
&lt;li&gt;a Linux OS with sudo rights, any system will do&lt;/li&gt;
&lt;li&gt;shell, any shell will do&lt;/li&gt;
&lt;li&gt;access to an HPC system via SSH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we are going to follow these steps to run your model within a container on HPC:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 1. Create a definition file&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, we create a &lt;code&gt;netlogo-headless.def&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 2. Build a container&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We are going to build an apptainer container on your local machine from a definition file that we have just created in Step 1. For this, a Linux system with sudo rights is needed.&lt;/p&gt;
&lt;p&gt;This command will create an apptainer image &lt;code&gt;netlogo-headless.sif&lt;/code&gt; which we will use to run the model in headless mode on HPC.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 3. Prepare &lt;code&gt;job.sh&lt;/code&gt; file&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We need to create a shell script that contains the command to run the model in headless mode. First, we look at how to run the model in headless mode without a container.&lt;/p&gt;
&lt;p&gt;./netlogo-headless.sh — model “PATH_TO_MODEL” — experiment “EXPERIMENT_NAME” — table OUTPUT.CSVThe line of code above will execute a &lt;code&gt;netlogo-headless.sh&lt;/code&gt; command, where&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — model&lt;/code&gt; is an argument that specifies the NetLogo model to be run;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — experiment&lt;/code&gt; argument is optional and can be used to specify the name of the experiment;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — table&lt;/code&gt; argument is optional and can be used to specify the name of the output file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;apptainer exec netlogo-headless.sif netlogo-headless.sh — model “PATH_TO_MODEL” — experiment “EXPERIMENT_NAME” — table OUTPUT.CSVFor example, to run a model &lt;code&gt;Wolf Sheep Simple 5.nlogo&lt;/code&gt; with an experiment &lt;code&gt;Wolf Sheep Simple model analysis&lt;/code&gt; and save the output in &lt;code&gt;wolf_sheep_output.csv&lt;/code&gt;, use the following command.&lt;/p&gt;
&lt;p&gt;We save the code above as &lt;code&gt;job.sh&lt;/code&gt; and change permissions to make it executable with&lt;/p&gt;
&lt;p&gt;chmod +x job.shStep 3. Create an archive to be copied to HPC*&lt;/p&gt;
&lt;p&gt;To run our model on HPC, we need to copy all files to the remote machine. First, we create an archive on a local machine that contains the model, the container, and the shell script. For this, we create a directory and copy &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;netlogo-headless.sif&lt;/code&gt;, and &lt;code&gt;job.sh&lt;/code&gt; into it and call this directory &lt;code&gt;jobHPC&lt;/code&gt;. Then we create a gzip tarball of a directory.&lt;/p&gt;
&lt;p&gt;tar -czvf jobHPC.tar.gz jobHPC&lt;em&gt;Step 4. Copy to HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To copy &lt;code&gt;jobHPC.tar.gz&lt;/code&gt; file from your local machine to HPC cluster, we can use the &lt;code&gt;scp&lt;/code&gt; command. This command will copy &lt;code&gt;jobHPC.tar.gz&lt;/code&gt; file to the remote machine using SSH (Secure Shell) protocol for data transfer.&lt;/p&gt;
&lt;p&gt;scp jobHPC.tar.gz username@remote:/path/to/remote/directoryReplace &lt;code&gt;username@remote&lt;/code&gt; with your username and the address of the HPC cluster. Replace &lt;code&gt;/path/to/remote/directory&lt;/code&gt; with the path to the directory on the HPC cluster where you want to copy the file. This command will prompt you for your password on the HPC cluster before copying the file.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 5. Unpack the archive on HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once the file is copied to the HPC cluster, log into the remote machine and unpack the archive using the following command:&lt;/p&gt;
&lt;p&gt;tar -xzvf jobHPC.tar.gz&lt;em&gt;Step 6. Run model on HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Submit a job to a (&lt;a href=&quot;https://slurm.schedmd.com/&quot;&gt;SLURM&lt;/a&gt;) scheduler on HPC using the following command:&lt;/p&gt;
&lt;p&gt;Here, we set a limit of 2 hours for the job to run. You can change the time limit as per your requirements.&lt;/p&gt;
&lt;p&gt;Now you can pull up information about the jobs in the queue:&lt;/p&gt;
&lt;p&gt;squeue —user=your-usernameWe use here the &lt;code&gt;--user&lt;/code&gt;flag because we only want to see our job.&lt;/p&gt;
&lt;p&gt;You can stop your job with&lt;/p&gt;
&lt;p&gt;scancel your_job-id&lt;em&gt;Step 7. Retrieve results&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once finished you can retrieve your results. For this, you need to identify the files you need to retrieve. To copy the files to your local machine run:&lt;/p&gt;
&lt;p&gt;scp username@remote:/path/to/remote/file /path/to/local/destinationReplace &lt;code&gt;/path/to/remote/file&lt;/code&gt; with the path to the file on the HPC system, and &lt;code&gt;/path/to/local/destination&lt;/code&gt; with the path where you want to save the file on your local machine.&lt;/p&gt;
&lt;p&gt;For example, to copy &lt;code&gt;job_output.txt&lt;/code&gt; from the HPC system to your desktop:&lt;/p&gt;
&lt;p&gt;scp &lt;a href=&quot;mailto:user@hpc.example.com&quot;&gt;user@hpc.example.com&lt;/a&gt;:/home/user/job_output.txt ~/Desktop/Finally, if you want to copy multiple files, you need to add flag &lt;code&gt;--r&lt;/code&gt; which will allow you to copy all files in the directory &lt;code&gt;job_output&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;scp -r &lt;a href=&quot;mailto:user@hpc.example.com&quot;&gt;user@hpc.example.com&lt;/a&gt;:/home/user/job_output/ ~/Desktop/
&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-0680d40a.DNh6sdSk_Z1aV0V3.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lightsabercollection?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Lightsaber Collection&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Conclusion**&lt;/p&gt;
&lt;p&gt;To wrap up our containerization journey, we have covered some solid ground in getting your NetLogo models up and running on HPC systems. Containerization, much like the cake tin, provides a reliable and consistent environment for your applications, ensuring they perform as expected regardless of the computing setup. From creating our container image using Apptainer to running the job scripts to transfer files to the HPC cluster and running job, we have laid out all the steps. Whether you are diving into ABM or tackling real-world problems, containerization on HPC enables you to handle complex computational tasks.&lt;/p&gt;
&lt;p&gt;Now, go ahead and make a Torta Caprese for yourself to celebrate that you learned something new! Here is a &lt;a href=&quot;https://food52.com/recipes/64554-torta-caprese-chocolate-and-almond-flourless-cake&quot;&gt;recipe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-cd889241.C4i4tuNu_Z2dxwrf.webp&quot; srcset=&quot;&quot;&gt;
Image: &lt;a href=&quot;https://unsplash.com/&quot;&gt;https://unsplash.com&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 23 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog was written by &lt;em&gt;&lt;a href=&quot;https://medium.com/@fdiblen&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/olga-lyashevska/&quot;&gt;&lt;em&gt;Olga Lyashevska&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Imagine you are preparing &lt;a href=&quot;https://en.wikipedia.org/wiki/Torta_caprese&quot;&gt;Torta Caprese&lt;/a&gt; for your friend’s birthday. You have a recipe that consistently delights everyone, but you want to ensure it turns out perfectly every time, regardless of the oven you are baking in or ambient temperature. To achieve this, you always use a cake tin for the batter, which gives its form. In the realm of software development, a similar concept exists — the container. Much like its culinary counterpart, a software container offers a lightweight, consistent and isolated environment for your application, just like the cake tin. The beauty of using a software container is that all the necessary ingredients and instructions are neatly packaged together, including code, dependencies, and runtime environment. This ensures that the application runs consistently and reliably across different computing environments and operating systems.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-642d9679.Bm-OR_PN_ZAnYGI.webp&quot; srcset=&quot;&quot;&gt;
Illustration: generated with &lt;a href=&quot;http://www.midjourney.com&quot;&gt;Midjourney&lt;/a&gt;Introduction**&lt;/p&gt;
&lt;p&gt;In this blog, we provide a step-by-step guide on running a containerized &lt;a href=&quot;https://en.wikipedia.org/wiki/Agent-based_model&quot;&gt;Agent Based Model&lt;/a&gt; (ABM) on High-Performance Computing (HPC) systems. We will explain how to package code and all dependencies in a container and execute on HPC in an easy way. As an example of ABM, we picked &lt;a href=&quot;https://ccl.northwestern.edu/netlogo/&quot;&gt;NetLogo&lt;/a&gt;, a widely popular software among users who may not be technically inclined.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;NetLogo is a multi-agent programmable modeling environment. It is used by tens of thousands of students, teachers and researchers worldwide.&lt;/p&gt;
&lt;p&gt;The steps outlined below are not limited to NetLogo or ABMs; you can follow this guide to run any application in a containerized format on HPC systems. So why might we want to run NetLogo on HPC? Let’s go back to our baker analogy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HPC and its significance in handling complex computational tasks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s imagine that your Torta Caprese has gained immense popularity, and now you are asked to bake it for a friend’s wedding. However, this time, you are not using your humble home oven (desktop computer); instead, you have access to a state-of-the-art industrial oven capable of efficiency and speed. This industrial oven represents HPC systems. HPC systems are known for their ability to process large volumes of data and complex computations at high speed. Do you want to risk any variation in the baking process? No. You are equally meticulous about the execution of your application on the HPC infrastructure. This is where the concept of containerization comes into the picture. By utilizing containers on HPC systems, you ensure that your application runs efficiently and consistently, regardless of the computing environment it is deployed.&lt;/p&gt;
&lt;p&gt;Back to NetLogo. Imagine you have a NetLogo model that has grown too complex and too slow to be run efficiently on your desktop and you decide to run it on HPC system. You have access to the HPC system via secure shell (SSH), but you do not have the necessary permissions to install NetLogo on the system or you do not know how to do it. Perhaps, you may even want to run the model without GUI (Graphical User Interface) because it avoids overhead and makes your model run faster.&lt;/p&gt;
&lt;p&gt;The purpose of this blog is to demonstrate how to run a single Netlogo model on HPC using &lt;a href=&quot;https://apptainer.org/&quot;&gt;Apptainer&lt;/a&gt; container. We use the &lt;a href=&quot;https://ccl.northwestern.edu/netlogo/6.3.0/NetLogo-6.3.0-64.tgz&quot;&gt;Netlogo&lt;/a&gt; distribution as a base for the container. Apptainer allows us to package the model and its dependencies (i.e. Netlogo) in a single image that can be run uniformly across different systems. Apptainer is particularly suitable for HPC, as it is designed to bring containers and reproducibility to the scientific community and does not require admin access to run. The container is then used to run the Netlogo model in headless mode. Headless mode is a mode in which the model is run without the GUI and the output is saved in a csv file.&lt;/p&gt;
&lt;p&gt;Let’s follow the next steps together. But first, you need to make sure that you have the following installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apptainer.org/&quot;&gt;Apptainer&lt;/a&gt; 1.2.5 or newer&lt;/li&gt;
&lt;li&gt;a Linux OS with sudo rights, any system will do&lt;/li&gt;
&lt;li&gt;shell, any shell will do&lt;/li&gt;
&lt;li&gt;access to an HPC system via SSH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we are going to follow these steps to run your model within a container on HPC:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 1. Create a definition file&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, we create a &lt;code&gt;netlogo-headless.def&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 2. Build a container&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We are going to build an apptainer container on your local machine from a definition file that we have just created in Step 1. For this, a Linux system with sudo rights is needed.&lt;/p&gt;
&lt;p&gt;This command will create an apptainer image &lt;code&gt;netlogo-headless.sif&lt;/code&gt; which we will use to run the model in headless mode on HPC.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 3. Prepare &lt;code&gt;job.sh&lt;/code&gt; file&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We need to create a shell script that contains the command to run the model in headless mode. First, we look at how to run the model in headless mode without a container.&lt;/p&gt;
&lt;p&gt;./netlogo-headless.sh — model “PATH_TO_MODEL” — experiment “EXPERIMENT_NAME” — table OUTPUT.CSVThe line of code above will execute a &lt;code&gt;netlogo-headless.sh&lt;/code&gt; command, where&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — model&lt;/code&gt; is an argument that specifies the NetLogo model to be run;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — experiment&lt;/code&gt; argument is optional and can be used to specify the name of the experiment;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt; — table&lt;/code&gt; argument is optional and can be used to specify the name of the output file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;apptainer exec netlogo-headless.sif netlogo-headless.sh — model “PATH_TO_MODEL” — experiment “EXPERIMENT_NAME” — table OUTPUT.CSVFor example, to run a model &lt;code&gt;Wolf Sheep Simple 5.nlogo&lt;/code&gt; with an experiment &lt;code&gt;Wolf Sheep Simple model analysis&lt;/code&gt; and save the output in &lt;code&gt;wolf_sheep_output.csv&lt;/code&gt;, use the following command.&lt;/p&gt;
&lt;p&gt;We save the code above as &lt;code&gt;job.sh&lt;/code&gt; and change permissions to make it executable with&lt;/p&gt;
&lt;p&gt;chmod +x job.shStep 3. Create an archive to be copied to HPC*&lt;/p&gt;
&lt;p&gt;To run our model on HPC, we need to copy all files to the remote machine. First, we create an archive on a local machine that contains the model, the container, and the shell script. For this, we create a directory and copy &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;netlogo-headless.sif&lt;/code&gt;, and &lt;code&gt;job.sh&lt;/code&gt; into it and call this directory &lt;code&gt;jobHPC&lt;/code&gt;. Then we create a gzip tarball of a directory.&lt;/p&gt;
&lt;p&gt;tar -czvf jobHPC.tar.gz jobHPC&lt;em&gt;Step 4. Copy to HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To copy &lt;code&gt;jobHPC.tar.gz&lt;/code&gt; file from your local machine to HPC cluster, we can use the &lt;code&gt;scp&lt;/code&gt; command. This command will copy &lt;code&gt;jobHPC.tar.gz&lt;/code&gt; file to the remote machine using SSH (Secure Shell) protocol for data transfer.&lt;/p&gt;
&lt;p&gt;scp jobHPC.tar.gz username@remote:/path/to/remote/directoryReplace &lt;code&gt;username@remote&lt;/code&gt; with your username and the address of the HPC cluster. Replace &lt;code&gt;/path/to/remote/directory&lt;/code&gt; with the path to the directory on the HPC cluster where you want to copy the file. This command will prompt you for your password on the HPC cluster before copying the file.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Step 5. Unpack the archive on HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once the file is copied to the HPC cluster, log into the remote machine and unpack the archive using the following command:&lt;/p&gt;
&lt;p&gt;tar -xzvf jobHPC.tar.gz&lt;em&gt;Step 6. Run model on HPC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Submit a job to a (&lt;a href=&quot;https://slurm.schedmd.com/&quot;&gt;SLURM&lt;/a&gt;) scheduler on HPC using the following command:&lt;/p&gt;
&lt;p&gt;Here, we set a limit of 2 hours for the job to run. You can change the time limit as per your requirements.&lt;/p&gt;
&lt;p&gt;Now you can pull up information about the jobs in the queue:&lt;/p&gt;
&lt;p&gt;squeue —user=your-usernameWe use here the &lt;code&gt;--user&lt;/code&gt;flag because we only want to see our job.&lt;/p&gt;
&lt;p&gt;You can stop your job with&lt;/p&gt;
&lt;p&gt;scancel your_job-id&lt;em&gt;Step 7. Retrieve results&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once finished you can retrieve your results. For this, you need to identify the files you need to retrieve. To copy the files to your local machine run:&lt;/p&gt;
&lt;p&gt;scp username@remote:/path/to/remote/file /path/to/local/destinationReplace &lt;code&gt;/path/to/remote/file&lt;/code&gt; with the path to the file on the HPC system, and &lt;code&gt;/path/to/local/destination&lt;/code&gt; with the path where you want to save the file on your local machine.&lt;/p&gt;
&lt;p&gt;For example, to copy &lt;code&gt;job_output.txt&lt;/code&gt; from the HPC system to your desktop:&lt;/p&gt;
&lt;p&gt;scp &lt;a href=&quot;mailto:user@hpc.example.com&quot;&gt;user@hpc.example.com&lt;/a&gt;:/home/user/job_output.txt ~/Desktop/Finally, if you want to copy multiple files, you need to add flag &lt;code&gt;--r&lt;/code&gt; which will allow you to copy all files in the directory &lt;code&gt;job_output&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;scp -r &lt;a href=&quot;mailto:user@hpc.example.com&quot;&gt;user@hpc.example.com&lt;/a&gt;:/home/user/job_output/ ~/Desktop/
&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-0680d40a.DNh6sdSk_Z1aV0V3.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lightsabercollection?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Lightsaber Collection&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Conclusion**&lt;/p&gt;
&lt;p&gt;To wrap up our containerization journey, we have covered some solid ground in getting your NetLogo models up and running on HPC systems. Containerization, much like the cake tin, provides a reliable and consistent environment for your applications, ensuring they perform as expected regardless of the computing setup. From creating our container image using Apptainer to running the job scripts to transfer files to the HPC cluster and running job, we have laid out all the steps. Whether you are diving into ABM or tackling real-world problems, containerization on HPC enables you to handle complex computational tasks.&lt;/p&gt;
&lt;p&gt;Now, go ahead and make a Torta Caprese for yourself to celebrate that you learned something new! Here is a &lt;a href=&quot;https://food52.com/recipes/64554-torta-caprese-chocolate-and-almond-flourless-cake&quot;&gt;recipe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to run a containerized Agent-Based Model on HPC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-cd889241.C4i4tuNu_Z2dxwrf.webp&quot; srcset=&quot;&quot;&gt;
Image: &lt;a href=&quot;https://unsplash.com/&quot;&gt;https://unsplash.com&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-to-run-a-containerized-agent-based-m-642d9679.Bm-OR_PN.png" medium="image"/><author>Olga Lyashevska</author></item><item><title>My experience of getting codechecked</title><link>https://blog.esciencecenter.nl/posts/2025-01-16---my-experience-of-getting-codechecked</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2025-01-16---my-experience-of-getting-codechecked</guid><description>&lt;p&gt;6&lt;/p&gt;
&lt;p&gt;*By eScience Fellow *&lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/eduard-klapwijk/&quot;&gt;&lt;em&gt;Eduard Klapwijk&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This year I was finalizing and publishing one of my own research projects. My coauthors and I took many steps to make the project as reproducible as possible.&lt;/p&gt;
&lt;p&gt;Because I am setting up a codecheck workflow to check the reproducibility of research results for researchers at my institute, I was eager to submit my own work to the test. How reproducible would our work be when submitted to an external test?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My experience of getting codechecked&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/my-experience-of-getting-codechecked-fd5cf777.CFP8GMsa_WjAUO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@hjkp?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;henry perks&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-check-for-reproducibility&quot;&gt;A check for reproducibility&lt;/h2&gt;
&lt;p&gt;I submitted my work to the &lt;a href=&quot;https://codecheck.org.uk/&quot;&gt;CODECHECK&lt;/a&gt; (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-n%C3%BCst2021&quot;&gt;Nüst and Eglen 2021&lt;/a&gt;) community workflow, which means that an external codechecker will do a light-weight reproducibility check. They will try to re-run my code to see if results reported in the paper can be reproduced.&lt;/p&gt;
&lt;p&gt;A codecheck was the perfect opportunity for checking how reproducible our project was. At the same time, the experience of getting my own work codechecked would help in understanding a researcher’s perspective on the process. In this post, I will share my personal experience of getting codechecked. This will hopefully demystify the process for any reader new to codechecking or curious about what codecheck is all about.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My experience of getting codechecked&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;360&quot; src=&quot;https://blog.esciencecenter.nl/_astro/my-experience-of-getting-codechecked-c91a8ead.C3rwIrhs_Z1k7CIi.webp&quot; srcset=&quot;&quot;&gt;
Image: The &lt;a href=&quot;https://codecheck.org.uk/process/#figure-2-the-codecheck-example-process-implementation&quot;&gt;CODECHECK&lt;/a&gt; example workflow implementation.&lt;/p&gt;
&lt;h2 id=&quot;the-project-neuroup&quot;&gt;The project: neuroUp&lt;/h2&gt;
&lt;p&gt;The project submitted for the codecheck was in the making for about four years — a nice example of &lt;a href=&quot;https://linkinghub.elsevier.com/retrieve/pii/S1364661319302426&quot;&gt;Slow Science&lt;/a&gt; as per Uta Frith’s analogy. From the start of these four years, I tried to make all our scripts reproducible.&lt;/p&gt;
&lt;p&gt;A few years ago, we started out with a couple of unconnected R scripts. Only when I started drafting the research article, I combined the draft manuscript with the project’s code and computations in one place. I first used &lt;a href=&quot;https://rmarkdown.rstudio.com/&quot;&gt;R Markdown&lt;/a&gt; for this, and in the end of 2023 I switched to a similar tool now available in RStudio called &lt;a href=&quot;https://quarto.org/&quot;&gt;Quarto&lt;/a&gt;. On top of this, a key tool for reproducibility was the use of &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; and &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; for version control. This helped to systematically track the evolution of the project and its code and allowed us to go back to a previous state of the code if needed.&lt;/p&gt;
&lt;p&gt;An important phase in the project was the step from working with loosely connected R scripts to the development of an R package (we called it &lt;a href=&quot;https://eduardklap.github.io/neuroUp/&quot;&gt;neuroUp&lt;/a&gt;). With the help of the fantastic &lt;a href=&quot;https://r-pkgs.org/&quot;&gt;R packages&lt;/a&gt; book by Hadley Wickham and Jennifer Bryan, I managed to develop my first R package out of the code for this paper. Although after having done this, I believe that for most research projects developing a custom software package is an overkill, organizing code in a package does provide a lot of benefits that make your code much more reproducible. It organizes your project according to a convention, specifies dependencies, and bundles data, code, and documentation (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-marwick2018&quot;&gt;Marwick, Boettiger, and Mullen 2018&lt;/a&gt;). This means other researchers can install, cite and use the package without having to understand exactly how your code works.&lt;/p&gt;
&lt;p&gt;When we posted &lt;a href=&quot;https://doi.org/10.31234/osf.io/cz32t&quot;&gt;the preprint for our paper&lt;/a&gt;, we also published a &lt;a href=&quot;https://eduardklap.github.io/sample-size-fmri/&quot;&gt;reproducible version of the manuscript&lt;/a&gt; online. That was the moment that we turned to the CODECHECK community workflow to check whether results were indeed reproducible, at least according to one independent codechecker who was not part of the research team.&lt;/p&gt;
&lt;h2 id=&quot;submitting-work-to-be-codechecked&quot;&gt;Submitting work to be codechecked&lt;/h2&gt;
&lt;p&gt;I chose CODECHECK because they offer a journal-independent community workflow. To be honest, submitting the work was daunting at first. I hesitated because based on the &lt;a href=&quot;https://codecheck.org.uk/guide/community-workflow-author#2-requirements&quot;&gt;instructions for authors&lt;/a&gt;, I thought I had to partly restructure my project and provide a new README and metadata file. Luckily, looking at some of the forked repositories in the &lt;a href=&quot;https://github.com/orgs/codecheckers/repositories&quot;&gt;codecheckers GitHub organization&lt;/a&gt; really helped. That made me realize that some were much more detailed than others and that I could suffice with just describing the files in the repository and instructions on how to run the code (I liked &lt;a href=&quot;https://github.com/codecheckers/mb11CalculusPilot&quot;&gt;this example&lt;/a&gt; by Bjørn Bartholdy and based my README on it).&lt;/p&gt;
&lt;p&gt;After the preparations, the procedure was straightforward. Using my GitHub account, I opened an issue on the codecheckers GitHub, which is made easy using their &lt;a href=&quot;https://github.com/codecheckers/register/issues/new/choose&quot;&gt;template issue&lt;/a&gt;. The only thing that confused me a little was the instruction to “link to the repository in the codecheckers organisation with the code”. Once I figured that I could also link to my own public repository that would be forked by the codechecker in the process, my project was ready to go!&lt;/p&gt;
&lt;h2 id=&quot;getting-the-results-of-the-check&quot;&gt;Getting the results of the check&lt;/h2&gt;
&lt;p&gt;After a short waiting time, I got notified with some good news: the checker was able to reproduce my work and we got a certificate (see &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-r%C3%B6seler2024&quot;&gt;Röseler 2024&lt;/a&gt;)! Of course, I was very happy. This meant that at least one other person at another moment in time was able to reproduce our work with the help of our data and code.&lt;/p&gt;
&lt;p&gt;But, as I also experienced when I later code-checked someone else’s work (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-joeytang2024&quot;&gt;Joey Tang et al. 2024&lt;/a&gt;), when everything is working smoothly (eventually maybe after debugging some dependencies), the whole process is not overly exciting. The machine is doing most of the work in that case, you just see a bunch of identical images or tables appearing on your screen.&lt;/p&gt;
&lt;p&gt;The kind of reproducibility that is checked (computational or methods reproducibility) is in the end actually quite basic. What is being checked is nothing more than a minimum but necessary condition of good and believable research: what is verified is whether the results can be independently re-run using the same data and code. Other relating concepts for reliable and trustworthy research results such as replicability, generalizibility, and robustness, may be more exciting, but require also much more effort or even new studies to check.&lt;/p&gt;
&lt;h2 id=&quot;final-reflections&quot;&gt;Final reflections&lt;/h2&gt;
&lt;p&gt;As with most things in life, preparing for the codecheck (by making sure your work is reproducible) is most of the work. Here are some key points to consider (see also these ten simple rules for reproducible research: &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-sandve2013&quot;&gt;Sandve et al. 2013&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record all the steps taken to process and analyze your data in scripts and avoid manual steps that are harder to reproduce.&lt;/li&gt;
&lt;li&gt;Documenting your code is key. Explain what steps are needed to reproduce the results (see our &lt;a href=&quot;https://github.com/codecheckers/sample-size-codecheck/&quot;&gt;README&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Make sure you systematically list all dependencies (software and packages).&lt;/li&gt;
&lt;li&gt;Use tools for version control.&lt;/li&gt;
&lt;li&gt;Use tools like &lt;a href=&quot;https://quarto.org/&quot;&gt;Quarto&lt;/a&gt;, &lt;a href=&quot;https://rmarkdown.rstudio.com/&quot;&gt;R markdown&lt;/a&gt;, or &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebooks&lt;/a&gt;. They provide a great way to share code, narrative text, and output in one document, making it much easier to clearly describe the steps that were taken to process and analyse the data.&lt;/li&gt;
&lt;li&gt;Partial reproducibility is always better than zero reproducibility! Don’t let the perfect be the enemy of the good.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In conclusion, getting our research codechecked was a very nice experience. With just a few extra steps (providing a short metadata file, adapting our README, requesting the check), we managed to obtain a nice certificate confirming that the computations underlying our article could be independently executed. I believe this additional check — next to traditional peer review — gives a nice extra boost to the credibility of our work. We therefore happily cited the CODECHECK certificate in our paper that got published recently (see &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-klapwijk2025&quot;&gt;Klapwijk et al. 2025&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Did you work hard to make your research reproducible? Then definitely have it codechecked!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I would like to thank Lieke de Boer for excellent feedback on a draft version of this post.&lt;/p&gt;
&lt;p&gt;This post was initially published &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/&quot;&gt;here&lt;/a&gt;. For attribution, please cite this work as:&lt;/p&gt;
&lt;p&gt;Klapwijk, Eduard T. 2025. “My Experience of Getting Codechecked.” January 16, 2025. &lt;a href=&quot;https://doi.org/10.5281/zenodo.14651307&quot;&gt;https://doi.org/10.5281/zenodo.14651307&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;6&lt;/p&gt;
&lt;p&gt;*By eScience Fellow *&lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/eduard-klapwijk/&quot;&gt;&lt;em&gt;Eduard Klapwijk&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This year I was finalizing and publishing one of my own research projects. My coauthors and I took many steps to make the project as reproducible as possible.&lt;/p&gt;
&lt;p&gt;Because I am setting up a codecheck workflow to check the reproducibility of research results for researchers at my institute, I was eager to submit my own work to the test. How reproducible would our work be when submitted to an external test?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My experience of getting codechecked&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/my-experience-of-getting-codechecked-fd5cf777.CFP8GMsa_WjAUO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@hjkp?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;henry perks&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-check-for-reproducibility&quot;&gt;A check for reproducibility&lt;/h2&gt;
&lt;p&gt;I submitted my work to the &lt;a href=&quot;https://codecheck.org.uk/&quot;&gt;CODECHECK&lt;/a&gt; (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-n%C3%BCst2021&quot;&gt;Nüst and Eglen 2021&lt;/a&gt;) community workflow, which means that an external codechecker will do a light-weight reproducibility check. They will try to re-run my code to see if results reported in the paper can be reproduced.&lt;/p&gt;
&lt;p&gt;A codecheck was the perfect opportunity for checking how reproducible our project was. At the same time, the experience of getting my own work codechecked would help in understanding a researcher’s perspective on the process. In this post, I will share my personal experience of getting codechecked. This will hopefully demystify the process for any reader new to codechecking or curious about what codecheck is all about.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My experience of getting codechecked&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;360&quot; src=&quot;https://blog.esciencecenter.nl/_astro/my-experience-of-getting-codechecked-c91a8ead.C3rwIrhs_Z1k7CIi.webp&quot; srcset=&quot;&quot;&gt;
Image: The &lt;a href=&quot;https://codecheck.org.uk/process/#figure-2-the-codecheck-example-process-implementation&quot;&gt;CODECHECK&lt;/a&gt; example workflow implementation.&lt;/p&gt;
&lt;h2 id=&quot;the-project-neuroup&quot;&gt;The project: neuroUp&lt;/h2&gt;
&lt;p&gt;The project submitted for the codecheck was in the making for about four years — a nice example of &lt;a href=&quot;https://linkinghub.elsevier.com/retrieve/pii/S1364661319302426&quot;&gt;Slow Science&lt;/a&gt; as per Uta Frith’s analogy. From the start of these four years, I tried to make all our scripts reproducible.&lt;/p&gt;
&lt;p&gt;A few years ago, we started out with a couple of unconnected R scripts. Only when I started drafting the research article, I combined the draft manuscript with the project’s code and computations in one place. I first used &lt;a href=&quot;https://rmarkdown.rstudio.com/&quot;&gt;R Markdown&lt;/a&gt; for this, and in the end of 2023 I switched to a similar tool now available in RStudio called &lt;a href=&quot;https://quarto.org/&quot;&gt;Quarto&lt;/a&gt;. On top of this, a key tool for reproducibility was the use of &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; and &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; for version control. This helped to systematically track the evolution of the project and its code and allowed us to go back to a previous state of the code if needed.&lt;/p&gt;
&lt;p&gt;An important phase in the project was the step from working with loosely connected R scripts to the development of an R package (we called it &lt;a href=&quot;https://eduardklap.github.io/neuroUp/&quot;&gt;neuroUp&lt;/a&gt;). With the help of the fantastic &lt;a href=&quot;https://r-pkgs.org/&quot;&gt;R packages&lt;/a&gt; book by Hadley Wickham and Jennifer Bryan, I managed to develop my first R package out of the code for this paper. Although after having done this, I believe that for most research projects developing a custom software package is an overkill, organizing code in a package does provide a lot of benefits that make your code much more reproducible. It organizes your project according to a convention, specifies dependencies, and bundles data, code, and documentation (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-marwick2018&quot;&gt;Marwick, Boettiger, and Mullen 2018&lt;/a&gt;). This means other researchers can install, cite and use the package without having to understand exactly how your code works.&lt;/p&gt;
&lt;p&gt;When we posted &lt;a href=&quot;https://doi.org/10.31234/osf.io/cz32t&quot;&gt;the preprint for our paper&lt;/a&gt;, we also published a &lt;a href=&quot;https://eduardklap.github.io/sample-size-fmri/&quot;&gt;reproducible version of the manuscript&lt;/a&gt; online. That was the moment that we turned to the CODECHECK community workflow to check whether results were indeed reproducible, at least according to one independent codechecker who was not part of the research team.&lt;/p&gt;
&lt;h2 id=&quot;submitting-work-to-be-codechecked&quot;&gt;Submitting work to be codechecked&lt;/h2&gt;
&lt;p&gt;I chose CODECHECK because they offer a journal-independent community workflow. To be honest, submitting the work was daunting at first. I hesitated because based on the &lt;a href=&quot;https://codecheck.org.uk/guide/community-workflow-author#2-requirements&quot;&gt;instructions for authors&lt;/a&gt;, I thought I had to partly restructure my project and provide a new README and metadata file. Luckily, looking at some of the forked repositories in the &lt;a href=&quot;https://github.com/orgs/codecheckers/repositories&quot;&gt;codecheckers GitHub organization&lt;/a&gt; really helped. That made me realize that some were much more detailed than others and that I could suffice with just describing the files in the repository and instructions on how to run the code (I liked &lt;a href=&quot;https://github.com/codecheckers/mb11CalculusPilot&quot;&gt;this example&lt;/a&gt; by Bjørn Bartholdy and based my README on it).&lt;/p&gt;
&lt;p&gt;After the preparations, the procedure was straightforward. Using my GitHub account, I opened an issue on the codecheckers GitHub, which is made easy using their &lt;a href=&quot;https://github.com/codecheckers/register/issues/new/choose&quot;&gt;template issue&lt;/a&gt;. The only thing that confused me a little was the instruction to “link to the repository in the codecheckers organisation with the code”. Once I figured that I could also link to my own public repository that would be forked by the codechecker in the process, my project was ready to go!&lt;/p&gt;
&lt;h2 id=&quot;getting-the-results-of-the-check&quot;&gt;Getting the results of the check&lt;/h2&gt;
&lt;p&gt;After a short waiting time, I got notified with some good news: the checker was able to reproduce my work and we got a certificate (see &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-r%C3%B6seler2024&quot;&gt;Röseler 2024&lt;/a&gt;)! Of course, I was very happy. This meant that at least one other person at another moment in time was able to reproduce our work with the help of our data and code.&lt;/p&gt;
&lt;p&gt;But, as I also experienced when I later code-checked someone else’s work (&lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-joeytang2024&quot;&gt;Joey Tang et al. 2024&lt;/a&gt;), when everything is working smoothly (eventually maybe after debugging some dependencies), the whole process is not overly exciting. The machine is doing most of the work in that case, you just see a bunch of identical images or tables appearing on your screen.&lt;/p&gt;
&lt;p&gt;The kind of reproducibility that is checked (computational or methods reproducibility) is in the end actually quite basic. What is being checked is nothing more than a minimum but necessary condition of good and believable research: what is verified is whether the results can be independently re-run using the same data and code. Other relating concepts for reliable and trustworthy research results such as replicability, generalizibility, and robustness, may be more exciting, but require also much more effort or even new studies to check.&lt;/p&gt;
&lt;h2 id=&quot;final-reflections&quot;&gt;Final reflections&lt;/h2&gt;
&lt;p&gt;As with most things in life, preparing for the codecheck (by making sure your work is reproducible) is most of the work. Here are some key points to consider (see also these ten simple rules for reproducible research: &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-sandve2013&quot;&gt;Sandve et al. 2013&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record all the steps taken to process and analyze your data in scripts and avoid manual steps that are harder to reproduce.&lt;/li&gt;
&lt;li&gt;Documenting your code is key. Explain what steps are needed to reproduce the results (see our &lt;a href=&quot;https://github.com/codecheckers/sample-size-codecheck/&quot;&gt;README&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Make sure you systematically list all dependencies (software and packages).&lt;/li&gt;
&lt;li&gt;Use tools for version control.&lt;/li&gt;
&lt;li&gt;Use tools like &lt;a href=&quot;https://quarto.org/&quot;&gt;Quarto&lt;/a&gt;, &lt;a href=&quot;https://rmarkdown.rstudio.com/&quot;&gt;R markdown&lt;/a&gt;, or &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebooks&lt;/a&gt;. They provide a great way to share code, narrative text, and output in one document, making it much easier to clearly describe the steps that were taken to process and analyse the data.&lt;/li&gt;
&lt;li&gt;Partial reproducibility is always better than zero reproducibility! Don’t let the perfect be the enemy of the good.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In conclusion, getting our research codechecked was a very nice experience. With just a few extra steps (providing a short metadata file, adapting our README, requesting the check), we managed to obtain a nice certificate confirming that the computations underlying our article could be independently executed. I believe this additional check — next to traditional peer review — gives a nice extra boost to the credibility of our work. We therefore happily cited the CODECHECK certificate in our paper that got published recently (see &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/#ref-klapwijk2025&quot;&gt;Klapwijk et al. 2025&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Did you work hard to make your research reproducible? Then definitely have it codechecked!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I would like to thank Lieke de Boer for excellent feedback on a draft version of this post.&lt;/p&gt;
&lt;p&gt;This post was initially published &lt;a href=&quot;https://eduardklap.github.io/repro-checks/posts/2025-01-16-experience-getting-codechecked/&quot;&gt;here&lt;/a&gt;. For attribution, please cite this work as:&lt;/p&gt;
&lt;p&gt;Klapwijk, Eduard T. 2025. “My Experience of Getting Codechecked.” January 16, 2025. &lt;a href=&quot;https://doi.org/10.5281/zenodo.14651307&quot;&gt;https://doi.org/10.5281/zenodo.14651307&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/my-experience-of-getting-codechecked-fd5cf777.CFP8GMsa.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Out of office: holiday mode activated</title><link>https://blog.esciencecenter.nl/posts/2024-12-20---out-of-office-holiday-mode-activated</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-20---out-of-office-holiday-mode-activated</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;711&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Lgda4zrJwtyb8A-E-JQ7Jg-1e176f31.Bbnqjlvu_1wPykP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As the year winds down, the Netherlands eScience Center editorial team will be taking a short hiatus for the holidays to recharge and prepare for an exciting year ahead. While we’re away, we’ve curated a list of thought-provoking blog posts for you to explore. From open science innovations to the latest in data-driven research, these articles will keep you inspired. Wishing you a joyful holiday season and see you in the new year!&lt;/p&gt;
&lt;p&gt;Blogs to read while we’re away:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4?sk=a9d1492d69a1737156859679d895e5a0&quot;&gt;Beyond Research&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-helpful-noob-540229f13ac0?sk=d1438f07a60c4fb95c646fd7c87129e2&quot;&gt;A Helpful Noob&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/what-research-software-engineers-can-learn-from-taylor-swift-92bf955a5bb4?sk=941654c629a8c43fe4c1dd7242358711&quot;&gt;What Research Software Engineers can learn from Taylor Swift&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/un-wieldy-workflows-with-wrf-4a4947b88a98?sk=4e04510a60fcb53354019aaddda217b3&quot;&gt;(Un)wieldy workflows with WRF&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 20 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;711&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Lgda4zrJwtyb8A-E-JQ7Jg-1e176f31.Bbnqjlvu_1wPykP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As the year winds down, the Netherlands eScience Center editorial team will be taking a short hiatus for the holidays to recharge and prepare for an exciting year ahead. While we’re away, we’ve curated a list of thought-provoking blog posts for you to explore. From open science innovations to the latest in data-driven research, these articles will keep you inspired. Wishing you a joyful holiday season and see you in the new year!&lt;/p&gt;
&lt;p&gt;Blogs to read while we’re away:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4?sk=a9d1492d69a1737156859679d895e5a0&quot;&gt;Beyond Research&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-helpful-noob-540229f13ac0?sk=d1438f07a60c4fb95c646fd7c87129e2&quot;&gt;A Helpful Noob&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/what-research-software-engineers-can-learn-from-taylor-swift-92bf955a5bb4?sk=941654c629a8c43fe4c1dd7242358711&quot;&gt;What Research Software Engineers can learn from Taylor Swift&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/un-wieldy-workflows-with-wrf-4a4947b88a98?sk=4e04510a60fcb53354019aaddda217b3&quot;&gt;(Un)wieldy workflows with WRF&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_Lgda4zrJwtyb8A-E-JQ7Jg-1e176f31.Bbnqjlvu.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Amsterdam as seen by a weather model</title><link>https://blog.esciencecenter.nl/posts/2024-12-10---amsterdam-as-seen-by-a-weather-model</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-10---amsterdam-as-seen-by-a-weather-model</guid><description>&lt;h2 id=&quot;visualizing-local-climate-zones-in-3d-with-the-cityblocks-package&quot;&gt;Visualizing local climate zones in 3D with the Cityblocks package&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What sets a weather model apart from a video game? While video games prioritize stunning visuals over strict realism, weather models focus entirely on physics. Visualizations come as an afterthought at best. A missed opportunity, since good visualizations can reveal fascinating insights into how these models interpret the world. In this blogpost we bring Amsterdam to life in 3D through the eyes of a weather model — and invite you to try it for your city as well.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Weather models have a peculiar view of a city. To them, the world is made of boxes. Many roughly rectangular boxes. A typical grid box contains more than one building, so weather models see cities at a block level.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;660&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_l4MLhZBrZbnuEC8AjIcJuQ-6d434fb4.BITi-oSW_Z1JXlcN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Weather and climate models divide the earth in grid cells. Each grid cell encompasses a wealth of information and processes, which must be represented in a simplified form. Source: wikipedia&lt;/p&gt;
&lt;p&gt;To describe cities at block level, one option is to use &lt;a href=&quot;https://doi.org/10.1016/j.rse.2023.113573&quot;&gt;local climate zones&lt;/a&gt; (LCZs): a set of typical building blocks modeled after cities across the globe. Each LCZ is associated with certain properties, such as the typical building height, street width, or green fraction. With that, weather models have all the info they need to simulate the interaction between the city and the atmosphere, in a simplified form.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1104&quot; height=&quot;384&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_I_qyITwlKMyiXrfSdUfluQ-7ef7b6a6.BdNWV3xD_1bOLvl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Left: Illustration of the local climate zones ( source ). Right: map of local climate zones for Amsterdam ( ).&lt;/p&gt;
&lt;p&gt;Typically, maps of local climate zones are displayed in 2D — a flat map. In principle, this is good enough, as we have only one LCZ per grid cell. But it doesn’t really appeal to the imagination. From the map above, I cannot tell how realistic this representation of Amsterdam actually is.&lt;/p&gt;
&lt;p&gt;That’s why I started playing around with 3D visualizations instead. The idea is to reproduce the tiles from the illustration above as building blocks, and then place them on a plane in accordance with the pixels on the 2D map. Below, we detail two approaches, one with CityJSON, and one with QGIS.&lt;/p&gt;
&lt;h2 id=&quot;building-a-city-in-cityjson&quot;&gt;Building a city in CityJSON&lt;/h2&gt;
&lt;p&gt;CityJSON file format is intended as a lightweight and developer-friendly format for spatial information. Like JSON, it is basically a set of key-value pairs. The &lt;a href=&quot;https://www.cityjson.org/specs/overview/&quot;&gt;CityJSON format&lt;/a&gt; specifies which keys are allowed/required and what values they can have. I was not familiar with the format, so this part of the blogpost also represents my learning experience. A simple CityJSON file could look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;CityJSON&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;metadata&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;geographicalExtent&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;transform&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;scale&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;translate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;extensions&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;vertices&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;CityObjects&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;id-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;geometry&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;boundaries&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;lod&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Solid&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;attributes&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;something&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;GenericCityObject&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;vertices&lt;/code&gt; represent points in 3D space. This file specifies 8 points. Each &lt;code&gt;CityObject&lt;/code&gt; specifies an array of &lt;code&gt;boundaries&lt;/code&gt;, which are essentially surfaces obtained by connecting the vertices. Here we have 6 surfaces, and if you draw them all up, you will see that this is simply a model for a cube.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.cityjson.org/&quot;&gt;CityJSON home page&lt;/a&gt; is very welcoming. It contains lots of useful information and examples. There is an official online CityJSON &lt;a href=&quot;https://validator.cityjson.org/&quot;&gt;validator&lt;/a&gt;, as well as a &lt;a href=&quot;https://viewer.cityjson.org/&quot;&gt;viewer&lt;/a&gt; called Ninja. So once you’ve obtained a CityJSON file, you can easily validate it and display it in the browser.&lt;/p&gt;
&lt;p&gt;I started with the &lt;a href=&quot;https://www.cityjson.org/datasets/#simple-geometries&quot;&gt;example&lt;/a&gt; of 2 cubes, and wrote &lt;a href=&quot;https://github.com/Urban-M4/cityjson-generator&quot;&gt;some Python code&lt;/a&gt; to reproduce them as templates, such that I could place blocks randomly everywhere, and scale them in width and height. I created multiple combinations of blocks to reproduce the LCZ archetypes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;406&quot; height=&quot;387&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EwYAPHFMN43apRcsZYo7QQ-18380ed7.B5AGWn_A_Z1X8E6D.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;LCZ archetypes reproduced in CityJSON.&lt;/p&gt;
&lt;p&gt;Next, I played a little bit with some random data to see how big of a city I could render. I found that 100 by 100 tiles still worked okay in the Ninja viewer. Effectively, this corresponds to a city of 10 by 10 km. I downloaded the global LCZ map from &lt;a href=&quot;https://doi.org/10.5281/zenodo.7670653&quot;&gt;Demuzere et al.&lt;/a&gt; and cut out the Amsterdam area. The last step was to loop over all pixels in the image, and add the corresponding tile to the CityJSON file.&lt;/p&gt;
&lt;p&gt;The code ran quite slowly, but it worked. The Ninja viewer went into “performance mode”, but eventually was able to display the data just fine. I was ready to observe the highly anticipating result…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;462&quot; height=&quot;387&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_qw1Ym7xaVw_aT_FnEQHvAw-bdc06d5d.DkKxDMRf_1s33Wy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Amsterdam rendered as 3D LCZ tiles. Blue designates correspond to water, yellow designates all other non-urban land use pixels.&lt;/p&gt;
&lt;p&gt;Admittedly, that looks a bit less spectacular than I had hoped for. The interactive view is a bit better, but still. While you can recognize the river, a canal, some parks and different types of buildings, this doesn’t really appeal to the imagination as I had hoped.&lt;/p&gt;
&lt;p&gt;One way to improve upon this initial view would be to render the different LCZ classes with different colors, and make the tiles prettier with things like trees, just like on the example tiles above. However, it seemed the online CityJSON viewer doesn’t support rendering materials, and I was already pushing its limits.&lt;/p&gt;
&lt;p&gt;In order to proceed with CityJSON, we would need to speed things up, and use a better viewer. There are several ways to speed things up. For example, by using &lt;a href=&quot;https://www.cityjson.org/cityjsonseq/&quot;&gt;CityJSON Sequence&lt;/a&gt; s and maybe converting to &lt;a href=&quot;https://github.com/3DGI/tyler&quot;&gt;3D Tiles&lt;/a&gt;. Concerning the viewer, I tried using the Blender and QGIS plugins, but I struggled to use them properly. In the long run, I would like to publish something like this on an interactive webpage, so I would prefer to look at other solutions. The standard viewer uses &lt;a href=&quot;https://threejs.org/&quot;&gt;three.js&lt;/a&gt; under the hood. It seems quite doable to embed such a viewer in a static website hosted from GitHub pages, for example. As such, anyone could clone the template and host their own city model with ease.&lt;/p&gt;
&lt;h2 id=&quot;making-it-beautiful-with-qgis&quot;&gt;Making it beautiful with QGIS&lt;/h2&gt;
&lt;p&gt;At this point I was showing my progress to my colleague Maurice. He is one of our GIS experts and helped me to reproduce the workflow in &lt;a href=&quot;https://www.qgis.org/&quot;&gt;QGIS&lt;/a&gt;. This alleviated some of the issues we had with the CityJSON viewer. With QGIS, we could render tiles in different colors, and use true coordinates to combine the tiles with other map layers. For example, here is a version where the colours of the tiles correspond to those on the 2D map above.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;733&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LlwYC1PNrl72OFSl81SLpA-65cd6b3e.DyFh8ZIo_1ptwiL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;3D rendering of local climate zones and other land use types for Amsterdam, using data from the global dataset from Demuzere et al.&lt;/p&gt;
&lt;p&gt;With QGIS, we took a slightly different approach. Instead of storing 3D cityblocks, we made 2D imprints of the LCZ types, and extruded them to a set height during the 3D render. We used Python with &lt;a href=&quot;https://rasterio.readthedocs.io/en/stable/&quot;&gt;rasterio&lt;/a&gt; and &lt;a href=&quot;https://geopandas.org/en/stable/&quot;&gt;geopandas&lt;/a&gt; to read and crop the original data and generate the 2D tiles. Intermediate data was stored as a &lt;a href=&quot;https://en.wikipedia.org/wiki/GeoPackage&quot;&gt;GeoPackage&lt;/a&gt;, which can easily be loaded in QGIS.&lt;/p&gt;
&lt;h3 id=&quot;introducing-cityblocks-a-simple-tool-to-visualize-your-own-city&quot;&gt;Introducing Cityblocks: a simple tool to visualize your own city&lt;/h3&gt;
&lt;p&gt;We decided to spend a bit more time to make this workflow available for anyone. We polished the code and converted it into a small and easy to use Python utility called &lt;a href=&quot;https://pypi.org/project/cityblocks/&quot;&gt;Cityblocks&lt;/a&gt;. You can use it to download the global dataset, extract an area of interest, and convert the data into tiles. Subsequently, the data can be visualized in QGIS, or something else in case you prefer. You can find the code and instructions &lt;a href=&quot;https://github.com/Urban-M4/cityblocks&quot;&gt;here&lt;/a&gt;. At the moment, this is mostly tested for our Amsterdam use case, so we are very curious to get feedback on your experience with it for other cities.&lt;/p&gt;
&lt;h2 id=&quot;making-it-beautiful&quot;&gt;Making it beautiful&lt;/h2&gt;
&lt;p&gt;At this point, we though it’d be nice to turn this little side quest into a real map that would stand its ground in an atlas of eScience Center projects.&lt;/p&gt;
&lt;p&gt;A good map tells a story that jumps at the viewer without much context. We considered many different options, and settled on a design that places the tiles on a background map of Amsterdam, with a subtle raster to hint at the gridded nature of weather models. Here is the final result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1414&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_C8-_I_H5hGt1j7SPd-BK0Q-1a1ebcf6.BOPdODeY_Z2dXLNL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;3D Local climate zones overlaid on an aerial photograph of Amsterdam. The aerial photograph comes from PDOK.&lt;/p&gt;
&lt;p&gt;Seeing the map with and without LCZs makes it easy to compare the “human” view to the “weather model view”. Notice that most of the riverbank area, including the station, is classified as “heavy industry”, whereas the city center is dominated by “compact to open midrise”, for example. Apart from evaluating the classification itself, this view also reveals the relatively coarse structure the weather model sees, and how rigid the city looks. Perhaps it is a sobering view that reminds us that even sophisticated weather models are only an approximation of reality.&lt;/p&gt;
&lt;p&gt;But it is inspiring at the same time! How can we improve upon this? One of the obvious wins is to use local properties like building height, rather than using fixed values from the LCZ classification. We started doing that several years ago in a project called &lt;a href=&quot;https://research-software-directory.org/projects/summer-in-the-city&quot;&gt;Summer in the City&lt;/a&gt;. In that project, we identified properties like building height and “urban fraction” for the Netherlands. Now, in the &lt;a href=&quot;https://research-software-directory.org/projects/urban-m4&quot;&gt;Urban-M4&lt;/a&gt; project, we are adding information on the radiative properties of buildings, by using open street view imagery. At the same time, our project partners at Wageningen University are collecting information on building age and other properties to add better-localized information on things like insulation status.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;I also have some ideas regarding the workflow and visualization. If time permits, here are some things I’d like to improve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generalize tile creation: currently the position and dimensions of the buildings are hardcoded based on a tile size of 100x100m. It would be nice to generate them on the fly instead, so we could accomadate various resolutions.&lt;/li&gt;
&lt;li&gt;Randomize the tiles: related to the above, I’ve been thinking a bit on how to add some natural variation to the positioning of buildings. For example by randomly shifting tiles across periodic boundaries.&lt;/li&gt;
&lt;li&gt;Beyond LCZs: a generic tile creation routine could generate tiles based on some key properties like road width, building width, green fraction, et cetera. That would make it possible to vary these parameters independently, rather than coupled through LCZs.&lt;/li&gt;
&lt;li&gt;Combining the workflows for QGIS and CityJSON. Currently they have diverged a bit, but they share many steps. With a bit of work we could streamline and generalize the workflow and add support for other output formats as well.&lt;/li&gt;
&lt;li&gt;Procedural generation: automatically create artificial worlds and gamify urban weather and climate simulation 🙂&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;concluding-remarks&quot;&gt;Concluding remarks&lt;/h2&gt;
&lt;p&gt;When it comes to visualization in weather and climate modelling, we often focus on output data. Here, we introduce an original visualization of the methodology instead. This provides valuable insights into the power and limitations of the LCZ approach. It appeals to the imagination can make our work more captivating.&lt;/p&gt;
&lt;p&gt;What are your thoughs about using visualizations like this? Do you have other ideas, or want to share your own maps made with the Cityblocks package? We have created a &lt;a href=&quot;https://github.com/Urban-M4/cityblocks/issues/9&quot;&gt;GitHub issue&lt;/a&gt; to collect images of cities across the globe. It would be awesome if you would contribute your city as well!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Claire Donnely and Ole Mussmann for providing comments on an earlier version, and to Tim Tensen and Maurice de Kleijn for creating the beautiful QGIS map. A chatbot was used to improve the formulation of a few sentences.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Tue, 10 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;visualizing-local-climate-zones-in-3d-with-the-cityblocks-package&quot;&gt;Visualizing local climate zones in 3D with the Cityblocks package&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What sets a weather model apart from a video game? While video games prioritize stunning visuals over strict realism, weather models focus entirely on physics. Visualizations come as an afterthought at best. A missed opportunity, since good visualizations can reveal fascinating insights into how these models interpret the world. In this blogpost we bring Amsterdam to life in 3D through the eyes of a weather model — and invite you to try it for your city as well.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Weather models have a peculiar view of a city. To them, the world is made of boxes. Many roughly rectangular boxes. A typical grid box contains more than one building, so weather models see cities at a block level.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;660&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_l4MLhZBrZbnuEC8AjIcJuQ-6d434fb4.BITi-oSW_Z1JXlcN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Weather and climate models divide the earth in grid cells. Each grid cell encompasses a wealth of information and processes, which must be represented in a simplified form. Source: wikipedia&lt;/p&gt;
&lt;p&gt;To describe cities at block level, one option is to use &lt;a href=&quot;https://doi.org/10.1016/j.rse.2023.113573&quot;&gt;local climate zones&lt;/a&gt; (LCZs): a set of typical building blocks modeled after cities across the globe. Each LCZ is associated with certain properties, such as the typical building height, street width, or green fraction. With that, weather models have all the info they need to simulate the interaction between the city and the atmosphere, in a simplified form.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1104&quot; height=&quot;384&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_I_qyITwlKMyiXrfSdUfluQ-7ef7b6a6.BdNWV3xD_1bOLvl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Left: Illustration of the local climate zones ( source ). Right: map of local climate zones for Amsterdam ( ).&lt;/p&gt;
&lt;p&gt;Typically, maps of local climate zones are displayed in 2D — a flat map. In principle, this is good enough, as we have only one LCZ per grid cell. But it doesn’t really appeal to the imagination. From the map above, I cannot tell how realistic this representation of Amsterdam actually is.&lt;/p&gt;
&lt;p&gt;That’s why I started playing around with 3D visualizations instead. The idea is to reproduce the tiles from the illustration above as building blocks, and then place them on a plane in accordance with the pixels on the 2D map. Below, we detail two approaches, one with CityJSON, and one with QGIS.&lt;/p&gt;
&lt;h2 id=&quot;building-a-city-in-cityjson&quot;&gt;Building a city in CityJSON&lt;/h2&gt;
&lt;p&gt;CityJSON file format is intended as a lightweight and developer-friendly format for spatial information. Like JSON, it is basically a set of key-value pairs. The &lt;a href=&quot;https://www.cityjson.org/specs/overview/&quot;&gt;CityJSON format&lt;/a&gt; specifies which keys are allowed/required and what values they can have. I was not familiar with the format, so this part of the blogpost also represents my learning experience. A simple CityJSON file could look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;CityJSON&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;metadata&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;geographicalExtent&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;transform&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;scale&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.001&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;translate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;extensions&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;vertices&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;CityObjects&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;id-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;geometry&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;boundaries&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              [[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;lod&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Solid&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;attributes&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;something&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;GenericCityObject&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;vertices&lt;/code&gt; represent points in 3D space. This file specifies 8 points. Each &lt;code&gt;CityObject&lt;/code&gt; specifies an array of &lt;code&gt;boundaries&lt;/code&gt;, which are essentially surfaces obtained by connecting the vertices. Here we have 6 surfaces, and if you draw them all up, you will see that this is simply a model for a cube.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.cityjson.org/&quot;&gt;CityJSON home page&lt;/a&gt; is very welcoming. It contains lots of useful information and examples. There is an official online CityJSON &lt;a href=&quot;https://validator.cityjson.org/&quot;&gt;validator&lt;/a&gt;, as well as a &lt;a href=&quot;https://viewer.cityjson.org/&quot;&gt;viewer&lt;/a&gt; called Ninja. So once you’ve obtained a CityJSON file, you can easily validate it and display it in the browser.&lt;/p&gt;
&lt;p&gt;I started with the &lt;a href=&quot;https://www.cityjson.org/datasets/#simple-geometries&quot;&gt;example&lt;/a&gt; of 2 cubes, and wrote &lt;a href=&quot;https://github.com/Urban-M4/cityjson-generator&quot;&gt;some Python code&lt;/a&gt; to reproduce them as templates, such that I could place blocks randomly everywhere, and scale them in width and height. I created multiple combinations of blocks to reproduce the LCZ archetypes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;406&quot; height=&quot;387&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EwYAPHFMN43apRcsZYo7QQ-18380ed7.B5AGWn_A_Z1X8E6D.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;LCZ archetypes reproduced in CityJSON.&lt;/p&gt;
&lt;p&gt;Next, I played a little bit with some random data to see how big of a city I could render. I found that 100 by 100 tiles still worked okay in the Ninja viewer. Effectively, this corresponds to a city of 10 by 10 km. I downloaded the global LCZ map from &lt;a href=&quot;https://doi.org/10.5281/zenodo.7670653&quot;&gt;Demuzere et al.&lt;/a&gt; and cut out the Amsterdam area. The last step was to loop over all pixels in the image, and add the corresponding tile to the CityJSON file.&lt;/p&gt;
&lt;p&gt;The code ran quite slowly, but it worked. The Ninja viewer went into “performance mode”, but eventually was able to display the data just fine. I was ready to observe the highly anticipating result…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;462&quot; height=&quot;387&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_qw1Ym7xaVw_aT_FnEQHvAw-bdc06d5d.DkKxDMRf_1s33Wy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Amsterdam rendered as 3D LCZ tiles. Blue designates correspond to water, yellow designates all other non-urban land use pixels.&lt;/p&gt;
&lt;p&gt;Admittedly, that looks a bit less spectacular than I had hoped for. The interactive view is a bit better, but still. While you can recognize the river, a canal, some parks and different types of buildings, this doesn’t really appeal to the imagination as I had hoped.&lt;/p&gt;
&lt;p&gt;One way to improve upon this initial view would be to render the different LCZ classes with different colors, and make the tiles prettier with things like trees, just like on the example tiles above. However, it seemed the online CityJSON viewer doesn’t support rendering materials, and I was already pushing its limits.&lt;/p&gt;
&lt;p&gt;In order to proceed with CityJSON, we would need to speed things up, and use a better viewer. There are several ways to speed things up. For example, by using &lt;a href=&quot;https://www.cityjson.org/cityjsonseq/&quot;&gt;CityJSON Sequence&lt;/a&gt; s and maybe converting to &lt;a href=&quot;https://github.com/3DGI/tyler&quot;&gt;3D Tiles&lt;/a&gt;. Concerning the viewer, I tried using the Blender and QGIS plugins, but I struggled to use them properly. In the long run, I would like to publish something like this on an interactive webpage, so I would prefer to look at other solutions. The standard viewer uses &lt;a href=&quot;https://threejs.org/&quot;&gt;three.js&lt;/a&gt; under the hood. It seems quite doable to embed such a viewer in a static website hosted from GitHub pages, for example. As such, anyone could clone the template and host their own city model with ease.&lt;/p&gt;
&lt;h2 id=&quot;making-it-beautiful-with-qgis&quot;&gt;Making it beautiful with QGIS&lt;/h2&gt;
&lt;p&gt;At this point I was showing my progress to my colleague Maurice. He is one of our GIS experts and helped me to reproduce the workflow in &lt;a href=&quot;https://www.qgis.org/&quot;&gt;QGIS&lt;/a&gt;. This alleviated some of the issues we had with the CityJSON viewer. With QGIS, we could render tiles in different colors, and use true coordinates to combine the tiles with other map layers. For example, here is a version where the colours of the tiles correspond to those on the 2D map above.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;733&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LlwYC1PNrl72OFSl81SLpA-65cd6b3e.DyFh8ZIo_1ptwiL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;3D rendering of local climate zones and other land use types for Amsterdam, using data from the global dataset from Demuzere et al.&lt;/p&gt;
&lt;p&gt;With QGIS, we took a slightly different approach. Instead of storing 3D cityblocks, we made 2D imprints of the LCZ types, and extruded them to a set height during the 3D render. We used Python with &lt;a href=&quot;https://rasterio.readthedocs.io/en/stable/&quot;&gt;rasterio&lt;/a&gt; and &lt;a href=&quot;https://geopandas.org/en/stable/&quot;&gt;geopandas&lt;/a&gt; to read and crop the original data and generate the 2D tiles. Intermediate data was stored as a &lt;a href=&quot;https://en.wikipedia.org/wiki/GeoPackage&quot;&gt;GeoPackage&lt;/a&gt;, which can easily be loaded in QGIS.&lt;/p&gt;
&lt;h3 id=&quot;introducing-cityblocks-a-simple-tool-to-visualize-your-own-city&quot;&gt;Introducing Cityblocks: a simple tool to visualize your own city&lt;/h3&gt;
&lt;p&gt;We decided to spend a bit more time to make this workflow available for anyone. We polished the code and converted it into a small and easy to use Python utility called &lt;a href=&quot;https://pypi.org/project/cityblocks/&quot;&gt;Cityblocks&lt;/a&gt;. You can use it to download the global dataset, extract an area of interest, and convert the data into tiles. Subsequently, the data can be visualized in QGIS, or something else in case you prefer. You can find the code and instructions &lt;a href=&quot;https://github.com/Urban-M4/cityblocks&quot;&gt;here&lt;/a&gt;. At the moment, this is mostly tested for our Amsterdam use case, so we are very curious to get feedback on your experience with it for other cities.&lt;/p&gt;
&lt;h2 id=&quot;making-it-beautiful&quot;&gt;Making it beautiful&lt;/h2&gt;
&lt;p&gt;At this point, we though it’d be nice to turn this little side quest into a real map that would stand its ground in an atlas of eScience Center projects.&lt;/p&gt;
&lt;p&gt;A good map tells a story that jumps at the viewer without much context. We considered many different options, and settled on a design that places the tiles on a background map of Amsterdam, with a subtle raster to hint at the gridded nature of weather models. Here is the final result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1414&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_C8-_I_H5hGt1j7SPd-BK0Q-1a1ebcf6.BOPdODeY_Z2dXLNL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;3D Local climate zones overlaid on an aerial photograph of Amsterdam. The aerial photograph comes from PDOK.&lt;/p&gt;
&lt;p&gt;Seeing the map with and without LCZs makes it easy to compare the “human” view to the “weather model view”. Notice that most of the riverbank area, including the station, is classified as “heavy industry”, whereas the city center is dominated by “compact to open midrise”, for example. Apart from evaluating the classification itself, this view also reveals the relatively coarse structure the weather model sees, and how rigid the city looks. Perhaps it is a sobering view that reminds us that even sophisticated weather models are only an approximation of reality.&lt;/p&gt;
&lt;p&gt;But it is inspiring at the same time! How can we improve upon this? One of the obvious wins is to use local properties like building height, rather than using fixed values from the LCZ classification. We started doing that several years ago in a project called &lt;a href=&quot;https://research-software-directory.org/projects/summer-in-the-city&quot;&gt;Summer in the City&lt;/a&gt;. In that project, we identified properties like building height and “urban fraction” for the Netherlands. Now, in the &lt;a href=&quot;https://research-software-directory.org/projects/urban-m4&quot;&gt;Urban-M4&lt;/a&gt; project, we are adding information on the radiative properties of buildings, by using open street view imagery. At the same time, our project partners at Wageningen University are collecting information on building age and other properties to add better-localized information on things like insulation status.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;I also have some ideas regarding the workflow and visualization. If time permits, here are some things I’d like to improve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generalize tile creation: currently the position and dimensions of the buildings are hardcoded based on a tile size of 100x100m. It would be nice to generate them on the fly instead, so we could accomadate various resolutions.&lt;/li&gt;
&lt;li&gt;Randomize the tiles: related to the above, I’ve been thinking a bit on how to add some natural variation to the positioning of buildings. For example by randomly shifting tiles across periodic boundaries.&lt;/li&gt;
&lt;li&gt;Beyond LCZs: a generic tile creation routine could generate tiles based on some key properties like road width, building width, green fraction, et cetera. That would make it possible to vary these parameters independently, rather than coupled through LCZs.&lt;/li&gt;
&lt;li&gt;Combining the workflows for QGIS and CityJSON. Currently they have diverged a bit, but they share many steps. With a bit of work we could streamline and generalize the workflow and add support for other output formats as well.&lt;/li&gt;
&lt;li&gt;Procedural generation: automatically create artificial worlds and gamify urban weather and climate simulation 🙂&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;concluding-remarks&quot;&gt;Concluding remarks&lt;/h2&gt;
&lt;p&gt;When it comes to visualization in weather and climate modelling, we often focus on output data. Here, we introduce an original visualization of the methodology instead. This provides valuable insights into the power and limitations of the LCZ approach. It appeals to the imagination can make our work more captivating.&lt;/p&gt;
&lt;p&gt;What are your thoughs about using visualizations like this? Do you have other ideas, or want to share your own maps made with the Cityblocks package? We have created a &lt;a href=&quot;https://github.com/Urban-M4/cityblocks/issues/9&quot;&gt;GitHub issue&lt;/a&gt; to collect images of cities across the globe. It would be awesome if you would contribute your city as well!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Claire Donnely and Ole Mussmann for providing comments on an earlier version, and to Tim Tensen and Maurice de Kleijn for creating the beautiful QGIS map. A chatbot was used to improve the formulation of a few sentences.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_l4MLhZBrZbnuEC8AjIcJuQ-6d434fb4.BITi-oSW.png" medium="image"/><author>Peter Kalverla</author></item><item><title>How much research output is really open, and how can we tell?</title><link>https://blog.esciencecenter.nl/posts/2024-12-06---how-much-research-output-is-really-open-and-how-can-we-tell</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-06---how-much-research-output-is-really-open-and-how-can-we-tell</guid><description>&lt;p&gt;Written by &lt;a href=&quot;https://estherplomp.github.io/&quot;&gt;Esther Plomp&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/meron-vermaas/&quot;&gt;Meron Vermaas&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt;, &lt;a href=&quot;https://nemoandrea.github.io/#primarySection/greeterSlider&quot;&gt;Nemo Andrea&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt;, &lt;a href=&quot;https://www.uu.nl/medewerkers/FPWeijdema&quot;&gt;Felix Weijdema&lt;/a&gt;, &lt;a href=&quot;https://www.uu.nl/medewerkers/DCHuijser&quot;&gt;Dorien Huijser&lt;/a&gt;, &lt;a href=&quot;https://www.openscience.nl/en/marta-teperek&quot;&gt;Marta Teperek&lt;/a&gt;, &lt;a href=&quot;https://www.tudelft.nl/library/research-data-management/r/support/data-stewardship/contact/bjoern-bartholdy&quot;&gt;Bjørn Bartholdy&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://www.universiteitleiden.nl/en/staffmembers/ana-parron-cabanero#tab-1&quot;&gt;Ana Parrón Cabañero&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;During the Open Science Festival in Maastricht on 22 October 2024, we gathered a full room for the session &lt;em&gt;&lt;a href=&quot;http://web.archive.org/web/20241107150720/https://www.opensciencefestival.nl/en/programme/tracking-research-objects-levelling-the-playing-field-in-research-assessment&quot;&gt;&lt;em&gt;Tracking Research Objects: Levelling the playing field in research assessment&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;! This was a topic that eScience Fellows Meron Vermaas and Esther Plomp were interested in investigating as a part of their &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;&lt;em&gt;eScience Center Fellowship&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; project. Read on to find out how you can investigate this using their methods!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How much research output is really open, and how can we tell?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-much-research-output-is-really-open--20fe968e.cQyvYruU_Z1kYsox.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@maplerockdesign?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Richard Bell&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We currently know a lot about how much research is published in Open Access publications for the Netherlands, to the degree that there are complete data and percentages available. For example, &lt;a href=&quot;https://www.tudelft.nl/en/library/support/library-for-researchers/publishing-outreach/creating-your-publishing-strategy/open-access-publishing&quot;&gt;TU Delft researchers published 98% of their publications Open Access in 2023&lt;/a&gt;. How much of the other research outputs are published openly remains a wild guess, as it is a lot more difficult to measure research objects such as datasets, software repositories, protocols, podcasts, community outreach projects and so forth.&lt;/p&gt;
&lt;p&gt;Just because these research objects are difficult to measure, does not necessarily mean they should not be measured. Being able to measure the degree of Open Access has led to positive attention for research outputs being openly available, and measuring this for other research objects may also result in increased sharing and recognition of these efforts.&lt;/p&gt;
&lt;p&gt;We therefore started our session with some case studies on how other research objects can be made more visible. Esther presented on a project from TU Delft, and Meron presented on two projects he has been involved with from the Vrije Universiteit Amsterdam and the HvA. See &lt;a href=&quot;https://doi.org/10.5281/zenodo.13952611&quot;&gt;their slides&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How much research output is really open, and how can we tell?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;671&quot; height=&quot;138&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-much-research-output-is-really-open--9a0295d3.4X1PY1Tg_1gzJm9.webp&quot; srcset=&quot;&quot;&gt;
Esther and Meron worked together during their eScience Fellowship projects with &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt; from the Netherlands eScience Center to set up a workflow that could deduce from the DOIs of a journal article whether accompanying research objects are available. It turns out that it is possible to measure this fairly easily with a script that Ewan worked on, as long as the research objects are cited within the publication. This &lt;a href=&quot;https://github.com/EstherPlomp/TNW-Tracking/blob/main/main.py&quot;&gt;script is available on GitHub&lt;/a&gt; for others to try out and reuse.&lt;/p&gt;
&lt;p&gt;According to this data/script, the amount of shared research objects for the TU Delft Faculty of Applied Sciences in the period 2020–2023 range from 0–28%. This is likely to be an underestimate, as not all researchers cite the underlying/associated research objects within the article. The next steps for this project are to set up guidelines for researchers to make them aware why citation of these research objects are important, as well as perform text scraping to see how many other research objects are overlooked if we only look at cited research objects within the articles. For this, they will use a workflow that Meron has previously worked on during his &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/meron-vermaas/&quot;&gt;eScience Fellowship&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Meron and Ewan created a workflow to find code repositories created by researchers at the VU. Because it is not yet possible to track these in a straightforward way, they found them by looking into mentions of software repositories in scientific papers. While around 70% of the researchers mention the use of a research software (such as Python or R), only ~10% mention a code repository. However, mentioning a code repository does not automatically mean the code was created by the authors of the paper. Thus, this is probably an overestimation of the amount of software that was actually produced and published by researchers from the VU. As a next step &lt;a href=&quot;https://github.com/meronvermaas/PURE_fulltext_analysis&quot;&gt;the scripts (available on GitHub&lt;/a&gt;) also searched through the code repositories and checked if the contributors are affiliated to the VU. This allows for finding and then reaching out to researchers who shared their code, so that support can be offered to make the code repositories more FAIR. Getting in touch with those researchers is an ongoing effort.&lt;/p&gt;
&lt;h3 id=&quot;community-input-on-research-object-tracking&quot;&gt;Community input on research object tracking&lt;/h3&gt;
&lt;p&gt;After a presentation on these efforts, the group split into six groups that discussed questions related to research object tracking for ~ 15 minutes, and at the end of the session we reported back to the full group on our findings. Below follows a short summary for each of the groups:&lt;/p&gt;
&lt;p&gt;Group 1: Should we track research objects (what are the disadvantages?)?**&lt;/p&gt;
&lt;p&gt;This group thought it would be beneficial to track research objects and did not discuss any disadvantages. The group thought it was important for recognising the work, as well as the possibility of validating and verifying research. Careful attention should be paid to the gamification of this system, however, as well as the costs that may be involved in making these research objects available in a reusable and trackable manner. There needs to be incentives for the researchers and professional staff involved in these efforts to make it worthwhile.&lt;/p&gt;
&lt;p&gt;It also needs to be clearer what the definition of a research object is and what the scope is. Potentially every research output can be considered a research object — even non-digital objects such as physical samples (blood samples, synthetic materials, or geological samples).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 2: In what way would tracking of research objects nurture a culture of sharing research outputs?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By tracking research objects individuals involved in research can be made aware of the benefits of sharing research objects: the visibility and accessibility of research outputs are important. To promote sharing practices we can develop and provide workshops and share recommended practices (research objects need a DOI, be registered in CRIS (current research information system), and/or made discoverable via preprint servers or data repositories).&lt;/p&gt;
&lt;p&gt;Nevertheless, sharing research objects may be discipline dependent, and may not apply to all disciplines, or may apply differently (what about law and history?). Not all research may result in research objects that are trackable!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 3: What (existing) technological infrastructure would be needed to effectively track research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This group discussed how ORCID could also be used to automatically track research objects. ORCID has options to connect with existing research-object infrastructures and automatically add the publications, protocols and software to a researcher’s profiles. Since ORCID is not widely used for tracking research objects, more awareness of these capabilities may be needed.&lt;/p&gt;
&lt;p&gt;For data and software sharing the existing infrastructure are already available. For example, there are hosting services that make use of Git such as GitHub, or open source alternatives such as GitLab and GitTea, in combination with data repositories. For the sharing of protocols, there are protocols servers that can be used such as &lt;a href=&quot;http://protocols.io&quot;&gt;protocols.io&lt;/a&gt;, or open source alternatives such as &lt;a href=&quot;https://osf.io/&quot;&gt;OSF&lt;/a&gt;. Since the infrastructure already exists for many purposes, the limiting factor seems to be the awareness of the resources available, and the practical implementation of citing research objects in publications. An example is the self-citation needed to automatically detect shared research objects (as done in the case study described by Esther). To solve this problem, the group came up with an idea of a tool where researchers can upload their text of a version of their article (before submitting to a journal!), that will analyse the text content and check for missing links and DOIs (for example: “you mentioned a GitHub repository but no DOI for data was found” or “no data repository was found, did you know you can upload your data free of charge to 4TU.ReseachData”). This way, researchers are automatically notified about any missing links or citations to research objects. Currently, there is a proposal (by a group not part of the session) to develop a software called “&lt;a href=&quot;https://osf.io/z3tr9&quot;&gt;Transparency Check&lt;/a&gt;” that will provide an automatic assessment and suggestions for the improvement of the transparency of data and methods in research reports before they are published.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 4: How can we balance quantitative metrics and qualitative indicators in the evaluation of research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They also discussed the dangers of quantitative metrics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Counting outputs can lead to prioritising quantity over quality (such as splitting up a dataset and publishing the subsets to have “more” datasets published).&lt;/li&gt;
&lt;li&gt;Quantitative metrics are subjected to circumventing, hacking and gaming.&lt;/li&gt;
&lt;li&gt;Quantitative metrics do not describe how the funding was used throughout the project and provide little context.&lt;/li&gt;
&lt;li&gt;It is difficult to quantify open science related work.&lt;/li&gt;
&lt;li&gt;Comparing metrics between institutes may lead to counterproductive competition and not be representative of the actual work that went into the outputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Group 5: What would you use research object tracking for? How can tracking research objects promote equity and inclusion within the research community?**&lt;/p&gt;
&lt;p&gt;This group noted that tracking research objects can be helpful to measure impact of research, and may also be very relevant to funders. It can also help to provide input for policies and to provide ways to guide support distribution, as it would be possible to establish targeted support based on the tracking research objects. Tracking research objects could promote equity and inclusion within the research community as it would provide recognition for all research outputs, not just papers, also datasets, podcasts and other research objects. This could include recognition for all staff involved in research, also professional staff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 6: How do we track research objects in a way that helps us to understand how behaviour changes over time?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The last group came up with their own question to address, and focused on working backwards from what type of behaviour we would like to track or change. The end goal is not to track research objects: we want the broader adoption of open science practices. The group pondered how the why behind all of this could be changing — why would researchers want to share their research objects? What research objects could they create, and which of those are being tracked? They also discussed whether Data Management Plans could be a tool to change behaviour, and whether monitoring data management plans would be helpful: are Data Management Plans updated — when and why?&lt;/p&gt;
&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;/h2&gt;
&lt;p&gt;We also distributed a survey/form with 9 respondents to collect examples of best practices across the Dutch and international landscape:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which infrastructures are used in your organisation to track research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The majority (8 out of 9) mentioned their current research information system (CRIS), generally PURE. Three cases mention tracking the use of &lt;a href=&quot;http://www.isaac.nwo.nl/en&quot;&gt;ISAAC&lt;/a&gt;, &lt;a href=&quot;https://dataverse.nl/&quot;&gt;dataverse&lt;/a&gt;, &lt;a href=&quot;https://data.4tu.nl/&quot;&gt;the inhouse repository&lt;/a&gt; and &lt;a href=&quot;https://openalex.org/&quot;&gt;OpenAlex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which research objects are being tracked?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Considering the majority using PURE as their main tracking system, it does not come as a surprise that publications are also the main research object being tracked. Six also mention datasets and there are isolated occurrences of tracking code, media appearances, supervised theses, keynote lectures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does your organisation use research object tracking for?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most responses mention reporting, evaluation and assessment. Also the ambition to use it to effectively recognise and reward non traditional research outputs.One institute responded that descriptive reports on scientific activities at departmental level are used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you know of other successful examples of research object tracking?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Positive responses were sparse in this question. The &lt;a href=&quot;https://theplosblog.plos.org/2023/06/open-science-indicators-update-q1-2023/&quot;&gt;PLOS Open Science Indicators&lt;/a&gt; were mentioned and a &lt;a href=&quot;https://fairdashboard.helmholtz-metadaten.de/en/data_in_helmholtz&quot;&gt;FAIR dashboard &lt;/a&gt;was shared. A promising outlook into the future was mentioned where an institute is working on creating a platform to keep track of the research outputs (as well as the Research Data Management &amp;#x26; Open Science compliance documents such as Data Management Plans, Software Management Plans, Privacy and Ethics). In the session slide initiatives such as &lt;a href=&quot;https://quest-dashboard.charite.de/&quot;&gt;Charité Metrics Dashboard&lt;/a&gt;, &lt;a href=&quot;https://frenchopensciencemonitor.esr.gouv.fr/&quot;&gt;French Open Science monitor&lt;/a&gt; and the &lt;a href=&quot;https://open-science-monitoring.org/&quot;&gt;Open Science Monitoring Initiative&lt;/a&gt; were mentioned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Collaborative initiatives can create a more equitable research assessment framework that recognizes diverse contributions to science. If you’re passionate about advancing Open Science and interested in contributing to similar community projects, consider applying for the &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;eScience Center Fellowship program&lt;/a&gt;. The Fellowship gives researchers and supporters the opportunity to work on technical solutions for open science challenges while collaborating with experts in the field.&lt;/p&gt;</description><pubDate>Fri, 06 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by &lt;a href=&quot;https://estherplomp.github.io/&quot;&gt;Esther Plomp&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/meron-vermaas/&quot;&gt;Meron Vermaas&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt;, &lt;a href=&quot;https://nemoandrea.github.io/#primarySection/greeterSlider&quot;&gt;Nemo Andrea&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt;, &lt;a href=&quot;https://www.uu.nl/medewerkers/FPWeijdema&quot;&gt;Felix Weijdema&lt;/a&gt;, &lt;a href=&quot;https://www.uu.nl/medewerkers/DCHuijser&quot;&gt;Dorien Huijser&lt;/a&gt;, &lt;a href=&quot;https://www.openscience.nl/en/marta-teperek&quot;&gt;Marta Teperek&lt;/a&gt;, &lt;a href=&quot;https://www.tudelft.nl/library/research-data-management/r/support/data-stewardship/contact/bjoern-bartholdy&quot;&gt;Bjørn Bartholdy&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://www.universiteitleiden.nl/en/staffmembers/ana-parron-cabanero#tab-1&quot;&gt;Ana Parrón Cabañero&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;During the Open Science Festival in Maastricht on 22 October 2024, we gathered a full room for the session &lt;em&gt;&lt;a href=&quot;http://web.archive.org/web/20241107150720/https://www.opensciencefestival.nl/en/programme/tracking-research-objects-levelling-the-playing-field-in-research-assessment&quot;&gt;&lt;em&gt;Tracking Research Objects: Levelling the playing field in research assessment&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;! This was a topic that eScience Fellows Meron Vermaas and Esther Plomp were interested in investigating as a part of their &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;&lt;em&gt;eScience Center Fellowship&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; project. Read on to find out how you can investigate this using their methods!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How much research output is really open, and how can we tell?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-much-research-output-is-really-open--20fe968e.cQyvYruU_Z1kYsox.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@maplerockdesign?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Richard Bell&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We currently know a lot about how much research is published in Open Access publications for the Netherlands, to the degree that there are complete data and percentages available. For example, &lt;a href=&quot;https://www.tudelft.nl/en/library/support/library-for-researchers/publishing-outreach/creating-your-publishing-strategy/open-access-publishing&quot;&gt;TU Delft researchers published 98% of their publications Open Access in 2023&lt;/a&gt;. How much of the other research outputs are published openly remains a wild guess, as it is a lot more difficult to measure research objects such as datasets, software repositories, protocols, podcasts, community outreach projects and so forth.&lt;/p&gt;
&lt;p&gt;Just because these research objects are difficult to measure, does not necessarily mean they should not be measured. Being able to measure the degree of Open Access has led to positive attention for research outputs being openly available, and measuring this for other research objects may also result in increased sharing and recognition of these efforts.&lt;/p&gt;
&lt;p&gt;We therefore started our session with some case studies on how other research objects can be made more visible. Esther presented on a project from TU Delft, and Meron presented on two projects he has been involved with from the Vrije Universiteit Amsterdam and the HvA. See &lt;a href=&quot;https://doi.org/10.5281/zenodo.13952611&quot;&gt;their slides&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How much research output is really open, and how can we tell?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;671&quot; height=&quot;138&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-much-research-output-is-really-open--9a0295d3.4X1PY1Tg_1gzJm9.webp&quot; srcset=&quot;&quot;&gt;
Esther and Meron worked together during their eScience Fellowship projects with &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt; from the Netherlands eScience Center to set up a workflow that could deduce from the DOIs of a journal article whether accompanying research objects are available. It turns out that it is possible to measure this fairly easily with a script that Ewan worked on, as long as the research objects are cited within the publication. This &lt;a href=&quot;https://github.com/EstherPlomp/TNW-Tracking/blob/main/main.py&quot;&gt;script is available on GitHub&lt;/a&gt; for others to try out and reuse.&lt;/p&gt;
&lt;p&gt;According to this data/script, the amount of shared research objects for the TU Delft Faculty of Applied Sciences in the period 2020–2023 range from 0–28%. This is likely to be an underestimate, as not all researchers cite the underlying/associated research objects within the article. The next steps for this project are to set up guidelines for researchers to make them aware why citation of these research objects are important, as well as perform text scraping to see how many other research objects are overlooked if we only look at cited research objects within the articles. For this, they will use a workflow that Meron has previously worked on during his &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/meron-vermaas/&quot;&gt;eScience Fellowship&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Meron and Ewan created a workflow to find code repositories created by researchers at the VU. Because it is not yet possible to track these in a straightforward way, they found them by looking into mentions of software repositories in scientific papers. While around 70% of the researchers mention the use of a research software (such as Python or R), only ~10% mention a code repository. However, mentioning a code repository does not automatically mean the code was created by the authors of the paper. Thus, this is probably an overestimation of the amount of software that was actually produced and published by researchers from the VU. As a next step &lt;a href=&quot;https://github.com/meronvermaas/PURE_fulltext_analysis&quot;&gt;the scripts (available on GitHub&lt;/a&gt;) also searched through the code repositories and checked if the contributors are affiliated to the VU. This allows for finding and then reaching out to researchers who shared their code, so that support can be offered to make the code repositories more FAIR. Getting in touch with those researchers is an ongoing effort.&lt;/p&gt;
&lt;h3 id=&quot;community-input-on-research-object-tracking&quot;&gt;Community input on research object tracking&lt;/h3&gt;
&lt;p&gt;After a presentation on these efforts, the group split into six groups that discussed questions related to research object tracking for ~ 15 minutes, and at the end of the session we reported back to the full group on our findings. Below follows a short summary for each of the groups:&lt;/p&gt;
&lt;p&gt;Group 1: Should we track research objects (what are the disadvantages?)?**&lt;/p&gt;
&lt;p&gt;This group thought it would be beneficial to track research objects and did not discuss any disadvantages. The group thought it was important for recognising the work, as well as the possibility of validating and verifying research. Careful attention should be paid to the gamification of this system, however, as well as the costs that may be involved in making these research objects available in a reusable and trackable manner. There needs to be incentives for the researchers and professional staff involved in these efforts to make it worthwhile.&lt;/p&gt;
&lt;p&gt;It also needs to be clearer what the definition of a research object is and what the scope is. Potentially every research output can be considered a research object — even non-digital objects such as physical samples (blood samples, synthetic materials, or geological samples).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 2: In what way would tracking of research objects nurture a culture of sharing research outputs?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By tracking research objects individuals involved in research can be made aware of the benefits of sharing research objects: the visibility and accessibility of research outputs are important. To promote sharing practices we can develop and provide workshops and share recommended practices (research objects need a DOI, be registered in CRIS (current research information system), and/or made discoverable via preprint servers or data repositories).&lt;/p&gt;
&lt;p&gt;Nevertheless, sharing research objects may be discipline dependent, and may not apply to all disciplines, or may apply differently (what about law and history?). Not all research may result in research objects that are trackable!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 3: What (existing) technological infrastructure would be needed to effectively track research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This group discussed how ORCID could also be used to automatically track research objects. ORCID has options to connect with existing research-object infrastructures and automatically add the publications, protocols and software to a researcher’s profiles. Since ORCID is not widely used for tracking research objects, more awareness of these capabilities may be needed.&lt;/p&gt;
&lt;p&gt;For data and software sharing the existing infrastructure are already available. For example, there are hosting services that make use of Git such as GitHub, or open source alternatives such as GitLab and GitTea, in combination with data repositories. For the sharing of protocols, there are protocols servers that can be used such as &lt;a href=&quot;http://protocols.io&quot;&gt;protocols.io&lt;/a&gt;, or open source alternatives such as &lt;a href=&quot;https://osf.io/&quot;&gt;OSF&lt;/a&gt;. Since the infrastructure already exists for many purposes, the limiting factor seems to be the awareness of the resources available, and the practical implementation of citing research objects in publications. An example is the self-citation needed to automatically detect shared research objects (as done in the case study described by Esther). To solve this problem, the group came up with an idea of a tool where researchers can upload their text of a version of their article (before submitting to a journal!), that will analyse the text content and check for missing links and DOIs (for example: “you mentioned a GitHub repository but no DOI for data was found” or “no data repository was found, did you know you can upload your data free of charge to 4TU.ReseachData”). This way, researchers are automatically notified about any missing links or citations to research objects. Currently, there is a proposal (by a group not part of the session) to develop a software called “&lt;a href=&quot;https://osf.io/z3tr9&quot;&gt;Transparency Check&lt;/a&gt;” that will provide an automatic assessment and suggestions for the improvement of the transparency of data and methods in research reports before they are published.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 4: How can we balance quantitative metrics and qualitative indicators in the evaluation of research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They also discussed the dangers of quantitative metrics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Counting outputs can lead to prioritising quantity over quality (such as splitting up a dataset and publishing the subsets to have “more” datasets published).&lt;/li&gt;
&lt;li&gt;Quantitative metrics are subjected to circumventing, hacking and gaming.&lt;/li&gt;
&lt;li&gt;Quantitative metrics do not describe how the funding was used throughout the project and provide little context.&lt;/li&gt;
&lt;li&gt;It is difficult to quantify open science related work.&lt;/li&gt;
&lt;li&gt;Comparing metrics between institutes may lead to counterproductive competition and not be representative of the actual work that went into the outputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Group 5: What would you use research object tracking for? How can tracking research objects promote equity and inclusion within the research community?**&lt;/p&gt;
&lt;p&gt;This group noted that tracking research objects can be helpful to measure impact of research, and may also be very relevant to funders. It can also help to provide input for policies and to provide ways to guide support distribution, as it would be possible to establish targeted support based on the tracking research objects. Tracking research objects could promote equity and inclusion within the research community as it would provide recognition for all research outputs, not just papers, also datasets, podcasts and other research objects. This could include recognition for all staff involved in research, also professional staff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group 6: How do we track research objects in a way that helps us to understand how behaviour changes over time?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The last group came up with their own question to address, and focused on working backwards from what type of behaviour we would like to track or change. The end goal is not to track research objects: we want the broader adoption of open science practices. The group pondered how the why behind all of this could be changing — why would researchers want to share their research objects? What research objects could they create, and which of those are being tracked? They also discussed whether Data Management Plans could be a tool to change behaviour, and whether monitoring data management plans would be helpful: are Data Management Plans updated — when and why?&lt;/p&gt;
&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;/h2&gt;
&lt;p&gt;We also distributed a survey/form with 9 respondents to collect examples of best practices across the Dutch and international landscape:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which infrastructures are used in your organisation to track research objects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The majority (8 out of 9) mentioned their current research information system (CRIS), generally PURE. Three cases mention tracking the use of &lt;a href=&quot;http://www.isaac.nwo.nl/en&quot;&gt;ISAAC&lt;/a&gt;, &lt;a href=&quot;https://dataverse.nl/&quot;&gt;dataverse&lt;/a&gt;, &lt;a href=&quot;https://data.4tu.nl/&quot;&gt;the inhouse repository&lt;/a&gt; and &lt;a href=&quot;https://openalex.org/&quot;&gt;OpenAlex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which research objects are being tracked?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Considering the majority using PURE as their main tracking system, it does not come as a surprise that publications are also the main research object being tracked. Six also mention datasets and there are isolated occurrences of tracking code, media appearances, supervised theses, keynote lectures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does your organisation use research object tracking for?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most responses mention reporting, evaluation and assessment. Also the ambition to use it to effectively recognise and reward non traditional research outputs.One institute responded that descriptive reports on scientific activities at departmental level are used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you know of other successful examples of research object tracking?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Positive responses were sparse in this question. The &lt;a href=&quot;https://theplosblog.plos.org/2023/06/open-science-indicators-update-q1-2023/&quot;&gt;PLOS Open Science Indicators&lt;/a&gt; were mentioned and a &lt;a href=&quot;https://fairdashboard.helmholtz-metadaten.de/en/data_in_helmholtz&quot;&gt;FAIR dashboard &lt;/a&gt;was shared. A promising outlook into the future was mentioned where an institute is working on creating a platform to keep track of the research outputs (as well as the Research Data Management &amp;#x26; Open Science compliance documents such as Data Management Plans, Software Management Plans, Privacy and Ethics). In the session slide initiatives such as &lt;a href=&quot;https://quest-dashboard.charite.de/&quot;&gt;Charité Metrics Dashboard&lt;/a&gt;, &lt;a href=&quot;https://frenchopensciencemonitor.esr.gouv.fr/&quot;&gt;French Open Science monitor&lt;/a&gt; and the &lt;a href=&quot;https://open-science-monitoring.org/&quot;&gt;Open Science Monitoring Initiative&lt;/a&gt; were mentioned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Collaborative initiatives can create a more equitable research assessment framework that recognizes diverse contributions to science. If you’re passionate about advancing Open Science and interested in contributing to similar community projects, consider applying for the &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;eScience Center Fellowship program&lt;/a&gt;. The Fellowship gives researchers and supporters the opportunity to work on technical solutions for open science challenges while collaborating with experts in the field.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-much-research-output-is-really-open--20fe968e.cQyvYruU.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>How is research software managed at UMCs? Insights from a first meetup</title><link>https://blog.esciencecenter.nl/posts/2024-12-05---how-is-research-software-managed-at-umcs-insights-from-a-fir</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-05---how-is-research-software-managed-at-umcs-insights-from-a-fir</guid><description>&lt;p&gt;Written by eScience Center Fellow &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/thomas-pronk/&quot;&gt;Thomas Pronk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On October 7th, 2024, the Digital Competence Centers (DCCs) of the seven Dutch University Medical Centers (UMCs) had a meetup, joined by representatives from Health-RI, ELIXIR-NL, The Netherlands eScience Center, and TDCC-LSH. We discussed Research Software Management (RSM) in the context of Dutch UMCs, identifying shared challenges, opportunities for collaboration, and how we could connect with the broader landscape of organizations, communities, and networks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How is research software managed at UMCs? Insights from a first meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-is-research-software-managed-at-umcs-df70a4a2.DUuGwGrS_1mHgx2.webp&quot; srcset=&quot;&quot;&gt;
We discussed Research Software Management (RSM) in the context of Dutch UMCs, identifying shared challenges, opportunities for collaboration, and how we could connect with the broader landscape of organizations, communities, and networks.&lt;/p&gt;
&lt;p&gt;Medical research often concerns highly sensitive data and interventions that impact lives. Consequently, we put stringent demands on privacy, security, quality, and reproducibility. In pursuit of meeting these demands, the Dutch UMCs have developed a strong tradition of collaboration and expertise in data stewardship. Our RSM approaches have drawn from these, along with well-established software development practices. However, the institution-wide introduction of RSM policies is relatively new. Correspondingly, RSM at Dutch UMCs is currently at a formative stage. We have the opportunity to jointly address the challenges that come with introducing RSM and we are well-equipped to do so.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How is research software managed at UMCs? Insights from a first meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-is-research-software-managed-at-umcs-39265be3.DxWHpVV5_Z17sfJL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@zhenh2424?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Zhen H&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To get started, we each listed our top three challenges, opportunities, and projects to know about, in a survey. Based on the results, we jointly identified five focus areas in pursuing joint RSM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Distill guidelines from decentral expertise.** There is already substantial expertise in research software spread out over departments at Dutch UMCs. At the central level, we can learn from this experience to develop good practice guidelines that are attuned with practice, can be developed into policies, and are aligned with national and international efforts such as the&lt;a href=&quot;https://tdcc.nl/projects/tdcc-lsh-project-initiatives/&quot;&gt; TDCC-LSH FAIR Tool framework&lt;/a&gt;,&lt;a href=&quot;https://everse.software/&quot;&gt; EOSC EVERSE&lt;/a&gt; and&lt;a href=&quot;https://openebench.bsc.es/&quot;&gt; OpenEBench&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardize Software Management Plans (SMPs).&lt;/strong&gt; By working together to standardize on a common format, we can link SMP sections to common support materials and offer default answers based on common best practices. Recognizing the variety of software types and roles, the standard could be made adaptive to its use cases (e.g.,&lt;a href=&quot;https://doi.org/10.5281/zenodo.7248877&quot;&gt; Practical Guide to SMPs&lt;/a&gt;,&lt;a href=&quot;https://smw.dsw.elixir-europe.org/wizard/&quot;&gt; ELIXIR Software Management Wizard&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Develop intermediate-level training.&lt;/strong&gt; Basic research software training can draw from existing initiatives such as those from the eScience Center, LCRDM, and The Carpentries (see&lt;a href=&quot;https://researchsoftwaretraining.nl/resources/&quot;&gt; Research Software Training NL&lt;/a&gt;). However, there is a need for intermediate training that focuses on more advanced skills and best practices adapted to the specific needs of medical research. The intermediate training could take a variety of forms, such as&lt;a href=&quot;https://www.reprohack.org/&quot;&gt; ReproHacks&lt;/a&gt;,&lt;a href=&quot;https://code-cafes-nl.github.io/cafe_playbook/&quot;&gt; Programming CAFEs&lt;/a&gt;, and mentoring schemes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define research software-related job profiles.&lt;/strong&gt; Embedding RSM on an institutional level requires a range of new roles with well-defined responsibilities. Here, we can draw inspiration from work on Data Stewardship (e.g.,&lt;a href=&quot;https://zenodo.org/records/2669150&quot;&gt; Ingeborg et al., 2019&lt;/a&gt;;&lt;a href=&quot;https://zenodo.org/records/3490855&quot;&gt; Scholtens, 2019&lt;/a&gt;) and Research Software Engineering (e.g., eScience Center RSE&lt;a href=&quot;https://doi.org/10.5281/zenodo.7805870&quot;&gt; Job Role Descriptions&lt;/a&gt; and&lt;a href=&quot;https://zenodo.org/records/7805870&quot;&gt; Job Profiles&lt;/a&gt;,&lt;a href=&quot;https://rsetoolkit.github.io/rse-competencies-toolkit/&quot;&gt; Research Software Competencies Toolkit&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to national and international networks.&lt;/strong&gt; In pursuit of the above, we seek to align our output with internationally recognized standards, tools, and platforms for (biomedical, life sciences, and health) research software. Natural candidates are offered by our membership of the European ELIXIR network, for instance, the RDM Toolkit&lt;a href=&quot;https://rdmkit.elixir-europe.org/tool_assembly&quot;&gt; tool assemblies&lt;/a&gt; and&lt;a href=&quot;https://rdmkit.elixir-europe.org/nl_resources&quot;&gt; regional resource index&lt;/a&gt;, the ELIXIR&lt;a href=&quot;https://elixir-europe.org/platforms/tools&quot;&gt; Tools Platform&lt;/a&gt;,&lt;a href=&quot;https://tess.elixir-europe.org/&quot;&gt; TeSS training platform,&lt;/a&gt; &lt;a href=&quot;https://everse.software/&quot;&gt;EOSC EVERSE&lt;/a&gt; and&lt;a href=&quot;https://elixir-europe.org/about-us/how-funded/eu-projects/steers&quot;&gt; ELIXIR-STEERS&lt;/a&gt;. Other relevant networks for research software are the national research software engineer (RSE) network (&lt;a href=&quot;https://nl-rse.org/&quot;&gt;NL-RSE&lt;/a&gt;) and the various regional and national &lt;a href=&quot;https://society-rse.org/international-rse-organisations/&quot;&gt;RSE organizations around the globe&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This meeting was made possible by funding from the eScience Center for the Fellowship Project &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/thomas-pronk/&quot;&gt;Implementing software management plans in medical science to improve science and safety*&lt;/a&gt;. If any of the focus areas above strike your fancy, then you might make a great &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;eScience Center Fellow&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 05 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by eScience Center Fellow &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/thomas-pronk/&quot;&gt;Thomas Pronk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On October 7th, 2024, the Digital Competence Centers (DCCs) of the seven Dutch University Medical Centers (UMCs) had a meetup, joined by representatives from Health-RI, ELIXIR-NL, The Netherlands eScience Center, and TDCC-LSH. We discussed Research Software Management (RSM) in the context of Dutch UMCs, identifying shared challenges, opportunities for collaboration, and how we could connect with the broader landscape of organizations, communities, and networks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How is research software managed at UMCs? Insights from a first meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-is-research-software-managed-at-umcs-df70a4a2.DUuGwGrS_1mHgx2.webp&quot; srcset=&quot;&quot;&gt;
We discussed Research Software Management (RSM) in the context of Dutch UMCs, identifying shared challenges, opportunities for collaboration, and how we could connect with the broader landscape of organizations, communities, and networks.&lt;/p&gt;
&lt;p&gt;Medical research often concerns highly sensitive data and interventions that impact lives. Consequently, we put stringent demands on privacy, security, quality, and reproducibility. In pursuit of meeting these demands, the Dutch UMCs have developed a strong tradition of collaboration and expertise in data stewardship. Our RSM approaches have drawn from these, along with well-established software development practices. However, the institution-wide introduction of RSM policies is relatively new. Correspondingly, RSM at Dutch UMCs is currently at a formative stage. We have the opportunity to jointly address the challenges that come with introducing RSM and we are well-equipped to do so.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How is research software managed at UMCs? Insights from a first meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-is-research-software-managed-at-umcs-39265be3.DxWHpVV5_Z17sfJL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@zhenh2424?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Zhen H&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To get started, we each listed our top three challenges, opportunities, and projects to know about, in a survey. Based on the results, we jointly identified five focus areas in pursuing joint RSM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Distill guidelines from decentral expertise.** There is already substantial expertise in research software spread out over departments at Dutch UMCs. At the central level, we can learn from this experience to develop good practice guidelines that are attuned with practice, can be developed into policies, and are aligned with national and international efforts such as the&lt;a href=&quot;https://tdcc.nl/projects/tdcc-lsh-project-initiatives/&quot;&gt; TDCC-LSH FAIR Tool framework&lt;/a&gt;,&lt;a href=&quot;https://everse.software/&quot;&gt; EOSC EVERSE&lt;/a&gt; and&lt;a href=&quot;https://openebench.bsc.es/&quot;&gt; OpenEBench&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardize Software Management Plans (SMPs).&lt;/strong&gt; By working together to standardize on a common format, we can link SMP sections to common support materials and offer default answers based on common best practices. Recognizing the variety of software types and roles, the standard could be made adaptive to its use cases (e.g.,&lt;a href=&quot;https://doi.org/10.5281/zenodo.7248877&quot;&gt; Practical Guide to SMPs&lt;/a&gt;,&lt;a href=&quot;https://smw.dsw.elixir-europe.org/wizard/&quot;&gt; ELIXIR Software Management Wizard&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Develop intermediate-level training.&lt;/strong&gt; Basic research software training can draw from existing initiatives such as those from the eScience Center, LCRDM, and The Carpentries (see&lt;a href=&quot;https://researchsoftwaretraining.nl/resources/&quot;&gt; Research Software Training NL&lt;/a&gt;). However, there is a need for intermediate training that focuses on more advanced skills and best practices adapted to the specific needs of medical research. The intermediate training could take a variety of forms, such as&lt;a href=&quot;https://www.reprohack.org/&quot;&gt; ReproHacks&lt;/a&gt;,&lt;a href=&quot;https://code-cafes-nl.github.io/cafe_playbook/&quot;&gt; Programming CAFEs&lt;/a&gt;, and mentoring schemes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define research software-related job profiles.&lt;/strong&gt; Embedding RSM on an institutional level requires a range of new roles with well-defined responsibilities. Here, we can draw inspiration from work on Data Stewardship (e.g.,&lt;a href=&quot;https://zenodo.org/records/2669150&quot;&gt; Ingeborg et al., 2019&lt;/a&gt;;&lt;a href=&quot;https://zenodo.org/records/3490855&quot;&gt; Scholtens, 2019&lt;/a&gt;) and Research Software Engineering (e.g., eScience Center RSE&lt;a href=&quot;https://doi.org/10.5281/zenodo.7805870&quot;&gt; Job Role Descriptions&lt;/a&gt; and&lt;a href=&quot;https://zenodo.org/records/7805870&quot;&gt; Job Profiles&lt;/a&gt;,&lt;a href=&quot;https://rsetoolkit.github.io/rse-competencies-toolkit/&quot;&gt; Research Software Competencies Toolkit&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to national and international networks.&lt;/strong&gt; In pursuit of the above, we seek to align our output with internationally recognized standards, tools, and platforms for (biomedical, life sciences, and health) research software. Natural candidates are offered by our membership of the European ELIXIR network, for instance, the RDM Toolkit&lt;a href=&quot;https://rdmkit.elixir-europe.org/tool_assembly&quot;&gt; tool assemblies&lt;/a&gt; and&lt;a href=&quot;https://rdmkit.elixir-europe.org/nl_resources&quot;&gt; regional resource index&lt;/a&gt;, the ELIXIR&lt;a href=&quot;https://elixir-europe.org/platforms/tools&quot;&gt; Tools Platform&lt;/a&gt;,&lt;a href=&quot;https://tess.elixir-europe.org/&quot;&gt; TeSS training platform,&lt;/a&gt; &lt;a href=&quot;https://everse.software/&quot;&gt;EOSC EVERSE&lt;/a&gt; and&lt;a href=&quot;https://elixir-europe.org/about-us/how-funded/eu-projects/steers&quot;&gt; ELIXIR-STEERS&lt;/a&gt;. Other relevant networks for research software are the national research software engineer (RSE) network (&lt;a href=&quot;https://nl-rse.org/&quot;&gt;NL-RSE&lt;/a&gt;) and the various regional and national &lt;a href=&quot;https://society-rse.org/international-rse-organisations/&quot;&gt;RSE organizations around the globe&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This meeting was made possible by funding from the eScience Center for the Fellowship Project &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/thomas-pronk/&quot;&gt;Implementing software management plans in medical science to improve science and safety*&lt;/a&gt;. If any of the focus areas above strike your fancy, then you might make a great &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;eScience Center Fellow&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-is-research-software-managed-at-umcs-df70a4a2.DUuGwGrS.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Tackling Advent of Code</title><link>https://blog.esciencecenter.nl/posts/2024-12-03---tackling-advent-of-code</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-03---tackling-advent-of-code</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://adventofcode.com/2024&quot;&gt;&lt;em&gt;Advent of Code 2024&lt;/em&gt;&lt;/a&gt;* has started this week! If you are not familiar with Advent of Code, it’s an annual coding challenge created by Eric Wastl. It’s like an &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Advent_calendar&quot;&gt;&lt;em&gt;advent calendar&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for coding challenges containing 25 daily programming puzzles, released once a day between December 1–25. You can still join this year’s edition, and even join our Dutch research community leaderboard when you sign up &lt;em&gt;&lt;a href=&quot;https://forms.office.com/e/fr8wAeNRin&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-b3260b36.C86THPBM_2guL0r.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markusspiske?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Markus Spiske&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whether you’re new to Advent of Code or if you want to brush up on your programming skills, below you can find a list of useful tricks, data structures and algorithms that are often needed when solving the challenges. Some of these are accompanied with links on how to use them in a few popular programming languages.&lt;/p&gt;
&lt;p&gt;Note, the list is rather large. We recommend only picking a few items where you think your knowledge is lacking.&lt;/p&gt;
&lt;h3 id=&quot;parsing-the-input&quot;&gt;Parsing the input**&lt;/h3&gt;
&lt;p&gt;In almost every exercise, you are given input, presented as plain text, that you have to parse (i.e. transform it into some structure that is useful for solving the problem). There are a few techniques you can use to accomplish this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;read the input line by line into a list (&lt;a href=&quot;https://www.w3schools.com/python/ref_file_readlines.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.statology.org/readlines-in-r/&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://medium.com/@AlexanderObregon/javas-files-readalllines-method-explained-14312314c1c4&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;split a string, useful if data is delimited by e.g. whitespace or a comma (&lt;a href=&quot;https://www.w3schools.com/python/ref_string_split.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://builtin.com/articles/strsplit&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/ref_string_split.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;parsing a string to an integer (&lt;a href=&quot;https://www.w3schools.com/python/ref_func_int.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://stat.ethz.ch/R-manual/R-devel/library/base/html/strtoi.html&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Integer.html#parseInt(java.lang.String)&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(Java only) use &lt;a href=&quot;https://www.w3schools.com/java/java_user_input.asp&quot;&gt;Java’s Scanner&lt;/a&gt; to easily parse various types of data&lt;/li&gt;
&lt;li&gt;(advanced) use regular expressions to parse the input (&lt;a href=&quot;https://www.w3schools.com/python/python_regex.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.datacamp.com/tutorial/regex-r-regular-expressions-guide&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_regex.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-f19971cc.7M8QaTuk_ZFVrqi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@chrisliverani?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Chris Liverani&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;integer-division-and-modular-arithmetic&quot;&gt;Integer division and modular arithmetic&lt;/h3&gt;
&lt;p&gt;In Advent of Code, you’ll often have to use integer division (where e.g. &lt;code&gt;11 / 4 = 2&lt;/code&gt; instead of &lt;code&gt;2.75&lt;/code&gt;). For Python, have a look at the &lt;a href=&quot;https://www.learndatasci.com/solutions/python-double-slash-operator-floor-division/&quot;&gt;double slash operator&lt;/a&gt; (&lt;code&gt;//&lt;/code&gt;) and for R use &lt;code&gt;%/%&lt;/code&gt; (see &lt;a href=&quot;https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Operators&quot;&gt;R operators&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;You’ll also have to use modular arithmetic, where you want to know the remainder after integer division (e.g. &lt;code&gt;11 % 4 = 3&lt;/code&gt;, because 4 fits 2 times into 11 and then you have 3 remaining). You’ll use these when, for example, you have to “wrap around” an array, i.e., when you reach the end of an array, you have to return to the start of the array. For Python, use the&lt;a href=&quot;https://realpython.com/python-modulo-operator/&quot;&gt; modulo operator&lt;/a&gt; &lt;code&gt;%&lt;/code&gt;, for R use &lt;code&gt;[%%](https://www.datacamp.com/doc/r/operators)&lt;/code&gt; and for Java use&lt;code&gt;[%](https://www.baeldung.com/modulo-java)&lt;/code&gt;. Also look up how your language behaves when any of the numbers is negative.&lt;/p&gt;
&lt;h3 id=&quot;working-with-large-integers&quot;&gt;Working with large integers&lt;/h3&gt;
&lt;p&gt;Sometimes, you need to handle large integers (especially when multiplying numbers). In some languages, where there are several integer types of several sizes, you need to prevent&lt;a href=&quot;https://www.acunetix.com/blog/web-security-zone/what-is-integer-overflow/&quot;&gt; integer overflow&lt;/a&gt;. This is sometimes a problem when working with &lt;a href=&quot;https://en.wikipedia.org/wiki/32-bit_computing&quot;&gt;32 bit integers&lt;/a&gt;. Usually, using 64 bit integers (keyword: &lt;code&gt;long&lt;/code&gt;) is sufficient for Advent of Code. In Python, this is &lt;a href=&quot;https://docs.python.org/3/c-api/long.html#integer-objects&quot;&gt;not needed&lt;/a&gt;, as it supports arbitrary large integers. For R, have a look at &lt;a href=&quot;https://www.stats.bris.ac.uk/R/web/packages/bit64/index.html&quot;&gt;this package&lt;/a&gt; for 64 bit integers. For Java, use the&lt;a href=&quot;https://www.w3schools.com/java/java_data_types.asp&quot;&gt; long type&lt;/a&gt; or, if that is not sufficient, use the &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/BigInteger.html&quot;&gt;BigInteger&lt;/a&gt; class.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-72c97208.18Q3hMhL_Z2wONXy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sortino?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Joshua Sortino&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-structures&quot;&gt;Data structures&lt;/h3&gt;
&lt;p&gt;Using the right data structure is crucial to solving the problems. These are the most commonly used ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_arrays.php&quot;&gt;array&lt;/a&gt;: An array is a fixed-size, ordered data structure, consisting of multiple entries of the same type in a row. You can save and retrieve data in an array by using an index (usually a number from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;n — 1&lt;/code&gt; (inclusive) if the array has length n. While Python’s standard library doesn’t have built-in arrays, the &lt;a href=&quot;https://numpy.org/&quot;&gt;NumPy&lt;/a&gt; library provides a powerful array implementation that’s widely considered a de-facto standard for numerical computing in Python. In R, one-dimensional arrays are referred to as vectors, and are indexed starting from &lt;code&gt;1&lt;/code&gt; (so you can index a number from &lt;code&gt;1 to n&lt;/code&gt;). Used when storing data without further requirements or when the order of the data is important. (&lt;a href=&quot;https://www.w3schools.com/r/r_arrays.asp&quot;&gt;R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_arrays.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;list (vector): A data structure that stores multiple entries of (usually) the same type in a row, with dynamic size that grows automatically as needed. While lists offer flexibility, arrays generally provide better performance due to their fixed size and contiguous memory allocation. Arrays are particularly advantageous in Python when using NumPy, as they enable efficient vectorized operations that can significantly speed up numerical computations. Choose arrays when performance and vectorization are priorities, and lists when frequent size changes are required. (&lt;a href=&quot;https://www.w3schools.com/python/python_lists.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/r/r_lists.asp&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_arraylist.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_hashmaps.php&quot;&gt;dictionary/(hash)map&lt;/a&gt;: A data structure that stores key-value pairs. If you want to store/retrieve data by something more complex than an index (as with arrays and lists), like a string, this is the data structure to use. While R does not technically have a dictionary data structure, you can often use a named vector as a quick-and-dirty replacement (&lt;a href=&quot;https://www.w3schools.com/python/python_dictionaries.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://chryswoods.com/beginning_r/dictionaries.html&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_hashmap.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_hashsets.php&quot;&gt;(hash)set&lt;/a&gt;: An unordered data structure that cannot contain duplicates of an element. Useful when you often need to check if some element is present in a data structure (often used in graph traversal algorithms, see below). (&lt;a href=&quot;https://www.w3schools.com/python/python_sets.asp&quot;&gt;Python&lt;/a&gt;, R has external libraries, such as &lt;a href=&quot;https://cran.r-project.org/web/packages/r2r/index.html&quot;&gt;r2r&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_hashset.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_queues.php&quot;&gt;queue&lt;/a&gt;: A first in, first out (FIFO) data structure where elements are added to the end and removed from the front. While Python lists can be used as queues, this is inefficient due to their underlying array implementation — removing from the front requires shifting all remaining elements. For better performance, use Python’s &lt;code&gt;collections.deque&lt;/code&gt; which is optimized for both front and back operations. Lists are better suited as stacks (last in, first out). Queues are commonly used in breadth-first search algorithms in graphs (see section on graphs below). (for&lt;a href=&quot;https://www.w3schools.com/python/python_lists.asp&quot;&gt; Python&lt;/a&gt; and&lt;a href=&quot;https://www.w3schools.com/r/r_lists.asp&quot;&gt; R&lt;/a&gt;, you can use the list as a queue, or you can use &lt;a href=&quot;https://realpython.com/python-deque/&quot;&gt;Python’s deque&lt;/a&gt;,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Queue.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_stacks.php&quot;&gt;stack&lt;/a&gt;: A last* in, first out data structure, meaning you can add and/or remove elements to the front of the stack only. Used in &lt;em&gt;depth-first search&lt;/em&gt; algorithms (see below). (see queue for Python and R,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Deque.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(advanced) &lt;a href=&quot;https://www.programiz.com/dsa/priority-queue&quot;&gt;priority queue/heap&lt;/a&gt;: Similar to a queue, except that the elements in the queue have a &lt;em&gt;priority&lt;/em&gt;, and the element with the highest priority will always be served first when retrieving/removing an element, independent of the order in which the elements where added. Used in Dijkstra’s algorithm (see below). (&lt;a href=&quot;https://www.geeksforgeeks.org/heap-queue-or-heapq-in-python/&quot;&gt;Python&lt;/a&gt;, look for external packages for R,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/PriorityQueue.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;algorithms&quot;&gt;Algorithms&lt;/h3&gt;
&lt;p&gt;Many problems can be solved with (a variation of) a well known algorithm. Below are listed some commonly needed algorithms for Advent of Code. This is by no means an exhaustive list. Furthermore, you are encouraged to do more research on these algorithms.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sorting an array/list: You don’t have to implement your own sorting algorithm, but you have to know how to call the built-in sorting functionality of your language, sometimes using a custom sort function/comparator. (&lt;a href=&quot;https://www.w3schools.com/python/python_lists_sort.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://r-coder.com/sort-r/&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/ref_arrays_sort.asp&quot;&gt; Java arrays&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_sort_list.asp&quot;&gt; Java lists&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Breadth-first_search&quot;&gt;breadth-first search&lt;/a&gt;: An algorithm for finding a node in a graph with a certain property. Used for example when looking for the shortest path between two nodes in a graph, when all edge weights have the same value. This uses a queue.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Depth-first_search&quot;&gt;depth-first search&lt;/a&gt;: An algorithm for finding a node in a graph with a certain property. Used for example when the node(s) you’re looking for in a graph are far away from the starting point. This uses a stack.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_algo_graphs_dijkstra.php&quot;&gt;Dijkstra’s algorithm&lt;/a&gt;: An algorithm for finding a shortest path from a fixed starting point to every other node in a graph, when the edge costs have varying values.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_ref_memoization.php&quot;&gt;memoization&lt;/a&gt;: Not an algorithm, but rather a technique, in which you store (cache) intermediate results so that you don’t have to recompute these over and over again. These intermediate results are usually stored in a dictionary/(hash)map.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;️-closing-words-️&quot;&gt;❄️ Closing words ❄️&lt;/h2&gt;
&lt;p&gt;I hope this overview is useful to you. I’m not that well-versed in the Python or R ecosystem, so if you know of better resources or techniques on any of the topics presented, please let me know.&lt;/p&gt;
&lt;p&gt;Is your favourite technique/algorithm/programming language missing? Feel free to add it below!&lt;/p&gt;
&lt;p&gt;Good luck this year!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Raoul Schram and Bj&lt;/em&gt;ø&lt;em&gt;rn Bartholdy for comments&lt;/em&gt;&lt;/p&gt;</description><pubDate>Tue, 03 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/ewan-cahen/&quot;&gt;Ewan Cahen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://adventofcode.com/2024&quot;&gt;&lt;em&gt;Advent of Code 2024&lt;/em&gt;&lt;/a&gt;* has started this week! If you are not familiar with Advent of Code, it’s an annual coding challenge created by Eric Wastl. It’s like an &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Advent_calendar&quot;&gt;&lt;em&gt;advent calendar&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for coding challenges containing 25 daily programming puzzles, released once a day between December 1–25. You can still join this year’s edition, and even join our Dutch research community leaderboard when you sign up &lt;em&gt;&lt;a href=&quot;https://forms.office.com/e/fr8wAeNRin&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-b3260b36.C86THPBM_2guL0r.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markusspiske?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Markus Spiske&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whether you’re new to Advent of Code or if you want to brush up on your programming skills, below you can find a list of useful tricks, data structures and algorithms that are often needed when solving the challenges. Some of these are accompanied with links on how to use them in a few popular programming languages.&lt;/p&gt;
&lt;p&gt;Note, the list is rather large. We recommend only picking a few items where you think your knowledge is lacking.&lt;/p&gt;
&lt;h3 id=&quot;parsing-the-input&quot;&gt;Parsing the input**&lt;/h3&gt;
&lt;p&gt;In almost every exercise, you are given input, presented as plain text, that you have to parse (i.e. transform it into some structure that is useful for solving the problem). There are a few techniques you can use to accomplish this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;read the input line by line into a list (&lt;a href=&quot;https://www.w3schools.com/python/ref_file_readlines.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.statology.org/readlines-in-r/&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://medium.com/@AlexanderObregon/javas-files-readalllines-method-explained-14312314c1c4&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;split a string, useful if data is delimited by e.g. whitespace or a comma (&lt;a href=&quot;https://www.w3schools.com/python/ref_string_split.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://builtin.com/articles/strsplit&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/ref_string_split.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;parsing a string to an integer (&lt;a href=&quot;https://www.w3schools.com/python/ref_func_int.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://stat.ethz.ch/R-manual/R-devel/library/base/html/strtoi.html&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Integer.html#parseInt(java.lang.String)&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(Java only) use &lt;a href=&quot;https://www.w3schools.com/java/java_user_input.asp&quot;&gt;Java’s Scanner&lt;/a&gt; to easily parse various types of data&lt;/li&gt;
&lt;li&gt;(advanced) use regular expressions to parse the input (&lt;a href=&quot;https://www.w3schools.com/python/python_regex.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.datacamp.com/tutorial/regex-r-regular-expressions-guide&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_regex.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-f19971cc.7M8QaTuk_ZFVrqi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@chrisliverani?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Chris Liverani&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;integer-division-and-modular-arithmetic&quot;&gt;Integer division and modular arithmetic&lt;/h3&gt;
&lt;p&gt;In Advent of Code, you’ll often have to use integer division (where e.g. &lt;code&gt;11 / 4 = 2&lt;/code&gt; instead of &lt;code&gt;2.75&lt;/code&gt;). For Python, have a look at the &lt;a href=&quot;https://www.learndatasci.com/solutions/python-double-slash-operator-floor-division/&quot;&gt;double slash operator&lt;/a&gt; (&lt;code&gt;//&lt;/code&gt;) and for R use &lt;code&gt;%/%&lt;/code&gt; (see &lt;a href=&quot;https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Operators&quot;&gt;R operators&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;You’ll also have to use modular arithmetic, where you want to know the remainder after integer division (e.g. &lt;code&gt;11 % 4 = 3&lt;/code&gt;, because 4 fits 2 times into 11 and then you have 3 remaining). You’ll use these when, for example, you have to “wrap around” an array, i.e., when you reach the end of an array, you have to return to the start of the array. For Python, use the&lt;a href=&quot;https://realpython.com/python-modulo-operator/&quot;&gt; modulo operator&lt;/a&gt; &lt;code&gt;%&lt;/code&gt;, for R use &lt;code&gt;[%%](https://www.datacamp.com/doc/r/operators)&lt;/code&gt; and for Java use&lt;code&gt;[%](https://www.baeldung.com/modulo-java)&lt;/code&gt;. Also look up how your language behaves when any of the numbers is negative.&lt;/p&gt;
&lt;h3 id=&quot;working-with-large-integers&quot;&gt;Working with large integers&lt;/h3&gt;
&lt;p&gt;Sometimes, you need to handle large integers (especially when multiplying numbers). In some languages, where there are several integer types of several sizes, you need to prevent&lt;a href=&quot;https://www.acunetix.com/blog/web-security-zone/what-is-integer-overflow/&quot;&gt; integer overflow&lt;/a&gt;. This is sometimes a problem when working with &lt;a href=&quot;https://en.wikipedia.org/wiki/32-bit_computing&quot;&gt;32 bit integers&lt;/a&gt;. Usually, using 64 bit integers (keyword: &lt;code&gt;long&lt;/code&gt;) is sufficient for Advent of Code. In Python, this is &lt;a href=&quot;https://docs.python.org/3/c-api/long.html#integer-objects&quot;&gt;not needed&lt;/a&gt;, as it supports arbitrary large integers. For R, have a look at &lt;a href=&quot;https://www.stats.bris.ac.uk/R/web/packages/bit64/index.html&quot;&gt;this package&lt;/a&gt; for 64 bit integers. For Java, use the&lt;a href=&quot;https://www.w3schools.com/java/java_data_types.asp&quot;&gt; long type&lt;/a&gt; or, if that is not sufficient, use the &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/BigInteger.html&quot;&gt;BigInteger&lt;/a&gt; class.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tackling Advent of Code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-72c97208.18Q3hMhL_Z2wONXy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sortino?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Joshua Sortino&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-structures&quot;&gt;Data structures&lt;/h3&gt;
&lt;p&gt;Using the right data structure is crucial to solving the problems. These are the most commonly used ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_arrays.php&quot;&gt;array&lt;/a&gt;: An array is a fixed-size, ordered data structure, consisting of multiple entries of the same type in a row. You can save and retrieve data in an array by using an index (usually a number from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;n — 1&lt;/code&gt; (inclusive) if the array has length n. While Python’s standard library doesn’t have built-in arrays, the &lt;a href=&quot;https://numpy.org/&quot;&gt;NumPy&lt;/a&gt; library provides a powerful array implementation that’s widely considered a de-facto standard for numerical computing in Python. In R, one-dimensional arrays are referred to as vectors, and are indexed starting from &lt;code&gt;1&lt;/code&gt; (so you can index a number from &lt;code&gt;1 to n&lt;/code&gt;). Used when storing data without further requirements or when the order of the data is important. (&lt;a href=&quot;https://www.w3schools.com/r/r_arrays.asp&quot;&gt;R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_arrays.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;list (vector): A data structure that stores multiple entries of (usually) the same type in a row, with dynamic size that grows automatically as needed. While lists offer flexibility, arrays generally provide better performance due to their fixed size and contiguous memory allocation. Arrays are particularly advantageous in Python when using NumPy, as they enable efficient vectorized operations that can significantly speed up numerical computations. Choose arrays when performance and vectorization are priorities, and lists when frequent size changes are required. (&lt;a href=&quot;https://www.w3schools.com/python/python_lists.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/r/r_lists.asp&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_arraylist.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_hashmaps.php&quot;&gt;dictionary/(hash)map&lt;/a&gt;: A data structure that stores key-value pairs. If you want to store/retrieve data by something more complex than an index (as with arrays and lists), like a string, this is the data structure to use. While R does not technically have a dictionary data structure, you can often use a named vector as a quick-and-dirty replacement (&lt;a href=&quot;https://www.w3schools.com/python/python_dictionaries.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://chryswoods.com/beginning_r/dictionaries.html&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_hashmap.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_hashsets.php&quot;&gt;(hash)set&lt;/a&gt;: An unordered data structure that cannot contain duplicates of an element. Useful when you often need to check if some element is present in a data structure (often used in graph traversal algorithms, see below). (&lt;a href=&quot;https://www.w3schools.com/python/python_sets.asp&quot;&gt;Python&lt;/a&gt;, R has external libraries, such as &lt;a href=&quot;https://cran.r-project.org/web/packages/r2r/index.html&quot;&gt;r2r&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_hashset.asp&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_queues.php&quot;&gt;queue&lt;/a&gt;: A first in, first out (FIFO) data structure where elements are added to the end and removed from the front. While Python lists can be used as queues, this is inefficient due to their underlying array implementation — removing from the front requires shifting all remaining elements. For better performance, use Python’s &lt;code&gt;collections.deque&lt;/code&gt; which is optimized for both front and back operations. Lists are better suited as stacks (last in, first out). Queues are commonly used in breadth-first search algorithms in graphs (see section on graphs below). (for&lt;a href=&quot;https://www.w3schools.com/python/python_lists.asp&quot;&gt; Python&lt;/a&gt; and&lt;a href=&quot;https://www.w3schools.com/r/r_lists.asp&quot;&gt; R&lt;/a&gt;, you can use the list as a queue, or you can use &lt;a href=&quot;https://realpython.com/python-deque/&quot;&gt;Python’s deque&lt;/a&gt;,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Queue.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_data_stacks.php&quot;&gt;stack&lt;/a&gt;: A last* in, first out data structure, meaning you can add and/or remove elements to the front of the stack only. Used in &lt;em&gt;depth-first search&lt;/em&gt; algorithms (see below). (see queue for Python and R,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Deque.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(advanced) &lt;a href=&quot;https://www.programiz.com/dsa/priority-queue&quot;&gt;priority queue/heap&lt;/a&gt;: Similar to a queue, except that the elements in the queue have a &lt;em&gt;priority&lt;/em&gt;, and the element with the highest priority will always be served first when retrieving/removing an element, independent of the order in which the elements where added. Used in Dijkstra’s algorithm (see below). (&lt;a href=&quot;https://www.geeksforgeeks.org/heap-queue-or-heapq-in-python/&quot;&gt;Python&lt;/a&gt;, look for external packages for R,&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/PriorityQueue.html&quot;&gt; Java&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;algorithms&quot;&gt;Algorithms&lt;/h3&gt;
&lt;p&gt;Many problems can be solved with (a variation of) a well known algorithm. Below are listed some commonly needed algorithms for Advent of Code. This is by no means an exhaustive list. Furthermore, you are encouraged to do more research on these algorithms.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sorting an array/list: You don’t have to implement your own sorting algorithm, but you have to know how to call the built-in sorting functionality of your language, sometimes using a custom sort function/comparator. (&lt;a href=&quot;https://www.w3schools.com/python/python_lists_sort.asp&quot;&gt;Python&lt;/a&gt;,&lt;a href=&quot;https://r-coder.com/sort-r/&quot;&gt; R&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/ref_arrays_sort.asp&quot;&gt; Java arrays&lt;/a&gt;,&lt;a href=&quot;https://www.w3schools.com/java/java_sort_list.asp&quot;&gt; Java lists&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Breadth-first_search&quot;&gt;breadth-first search&lt;/a&gt;: An algorithm for finding a node in a graph with a certain property. Used for example when looking for the shortest path between two nodes in a graph, when all edge weights have the same value. This uses a queue.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Depth-first_search&quot;&gt;depth-first search&lt;/a&gt;: An algorithm for finding a node in a graph with a certain property. Used for example when the node(s) you’re looking for in a graph are far away from the starting point. This uses a stack.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_algo_graphs_dijkstra.php&quot;&gt;Dijkstra’s algorithm&lt;/a&gt;: An algorithm for finding a shortest path from a fixed starting point to every other node in a graph, when the edge costs have varying values.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/dsa/dsa_ref_memoization.php&quot;&gt;memoization&lt;/a&gt;: Not an algorithm, but rather a technique, in which you store (cache) intermediate results so that you don’t have to recompute these over and over again. These intermediate results are usually stored in a dictionary/(hash)map.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;️-closing-words-️&quot;&gt;❄️ Closing words ❄️&lt;/h2&gt;
&lt;p&gt;I hope this overview is useful to you. I’m not that well-versed in the Python or R ecosystem, so if you know of better resources or techniques on any of the topics presented, please let me know.&lt;/p&gt;
&lt;p&gt;Is your favourite technique/algorithm/programming language missing? Feel free to add it below!&lt;/p&gt;
&lt;p&gt;Good luck this year!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Raoul Schram and Bj&lt;/em&gt;ø&lt;em&gt;rn Bartholdy for comments&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/tackling-advent-of-code-b3260b36.C86THPBM.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>The ‘do-it-yourself’ Computed Tomography scanner</title><link>https://blog.esciencecenter.nl/posts/2024-12-03---the-do-it-yourself-computed-tomography-scanner</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-12-03---the-do-it-yourself-computed-tomography-scanner</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Researchers developed a method to use existing X-ray imaging facilities for Computed Tomography (CT) scanning&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;598&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-69f18984.CF1BWYP4_Z2chW3l.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@socalcaral?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Cara Shelton&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a cross-post from our fellow &lt;a href=&quot;https://www.linkedin.com/in/francien-bossema-a587b012a/&quot;&gt;Dr. Francien Bossema&lt;/a&gt;. Originally published on the &lt;a href=&quot;https://www.cwi.nl/en/news/the-do-it-yourself-ct-scanner/&quot;&gt;CWI website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More information on our Fellowship programme &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;What if you could saw a wooden sculpture through to look at the tree rings? Could a clay sculpture be hollow? What type of instruments were used to craft art objects? These questions could be answered by X-ray imaging. In particular, CT-scans are useful to investigate historical art objects on the inside. The CT-scans that are suitable for this application are however not easily accessible for researchers and quite expensive to acquire. An international team of researchers led by CWI, the Dutch national research center for mathematics and computer science, has therefore developed a method to use existing X-ray imaging facilities for CT scanning. The results have been published &lt;a href=&quot;https://www.nature.com/articles/s41467-024-48102-w&quot;&gt;on the 14th of May in Nature Communications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Research facilities of large museums, such as the Rijksmuseum in Amsterdam, often house an X-ray imaging machine, with which they can perform live inspection of objects. This works in the same way as when you have to have an X-ray image taken at the hospital because of a broken bone. On such an image the bone can be seen, because it has a higher density than the muscles and tissue surrounding it. Usually, a few images are taken, so that the fracture can be inspected from different sides. For more complex problems, a CT scan is made. The technique behind CT scans is similar to X-ray images. For a CT scan hundreds of X-ray images are taken from different angles and then combined into a 3D image using reconstruction algorithms. This 3D image can then be ‘sliced open’ to obtain cross sections showing the interior.&lt;/p&gt;
&lt;p&gt;Over the past years, this technique has been increasingly applied to art objects, because it gives the possibility to investigate the interior without damaging the object. It is possible to date wooden objects by looking at the tree rings, assess the internal damage by an insect infestation or search for clues about the techniques used by the artist.&lt;/p&gt;
&lt;h2 id=&quot;no-ct-scanner-no-problem&quot;&gt;No CT scanner? No problem!&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-7f9418ba.CA__ftPK_c8ACr.webp&quot; srcset=&quot;&quot;&gt;
CT scans provide more information than X-ray images. In museums, however, simple X-ray imaging setups are more common. The components of the machine are similar (an X-ray tube, rotation stage and a detector), but for a CT scan the positions of these components during the scan need to be known very accurately. The researchers from CWI have therefore developed a method to calculate these positions after a data acquisition, with nothing more than a few small metal balls. These balls are put in a piece of foam and scanned alongside the object. Based on the location of the balls on the X-ray images, all the necessary positions can be calculated. These are then used to obtain a CT-scan.&lt;/p&gt;
&lt;p&gt;This unique project is a collaboration between a team of international researchers from CWI (Amsterdam), Leiden Institute of Advanced Computer Science (Leiden), Rijksmuseum (Amsterdam), The British Museum (London, UK) and the J. Paul Getty Museum (Los Angeles, USA). The X-ray imaging facilities of each of these museums, as well as the FleX-ray laboratory at CWI, have been used to test the new method and compare results in different facilities. The X-ray setups at the Rijksmuseum and the J. Paul Getty museum have been used for CT scans for the first time.&lt;/p&gt;
&lt;p&gt;The first author of the associated Nature Communications article &lt;a href=&quot;https://www.cwi.nl/en/people/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt; will defend her PhD thesis at Leiden University on the topic of CT scanning for cultural heritage on the 23rd of May.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can do something that was not possible before. CT scanning is an important imaging method for museums, because researchers can digitally cut open an object without damaging it. Our method makes it possible to further integrate this technique into research practices in the museum, without obtaining new hardware. We only use small metal balls of the type you also have in the pedals of your bike and algorithms specifically designed for this purpose. This means no extra investments are needed, while still providing an additional imaging technique.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Francien Bossema, CWI&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-method-gives-insights-into-the-making-process-of-a-sculpture&quot;&gt;New method gives insights into the making process of a sculpture&lt;/h2&gt;
&lt;p&gt;After the development of this technique, a sculpture made of plaster from the J. Paul Getty Museum was studied: &lt;em&gt;Python Killing a Gnu&lt;/em&gt;, by Antoine-Louis Barye (J. Paul Getty Museum, 85.SE.48). The sculpture originally had a different configuration, it was smaller and more compact because it was initially used as a model for a group of sculptures that was displayed on a dining table. The artist later decided to change the model to open and enlarge the arrangement and turn it into a stand-alone sculpture. The possibility to CT-scan the object was welcomed by the conservator who was investigating this object, Madeline Corona (Getty Museum): ‘On the X-ray images, we could see that areas had been broken, altered, and filled but it was difficult to understand exactly how the artist made these changes because there were too many overlapping features. The CT-scan gave us an incredible opportunity to obtain clearer and more detailed images of these areas of change. In the end, it provided important insights that allowed us to confirm some of our hypotheses about Barye’s working methods, something we could not have done without this technique.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-db1b697e.C0e1gOve_Z2g08pl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;359&quot; height=&quot;326&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-66c789e0.BgsP8rXT_Z2vQbdT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;more-information&quot;&gt;More information&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Article &lt;a href=&quot;https://www.nature.com/articles/s41467-024-48102-w&quot;&gt;&lt;em&gt;Enabling 3D CT-scanning of cultural heritage objects using only in-house 2D X-ray equipment in museums&lt;/em&gt;&lt;/a&gt; in Nature Communications 14 May 2024.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/people/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt; (CWI/Rijksmuseum), &lt;a href=&quot;mailto:bossema@cwi.nl&quot;&gt;bossema@cwi.nl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/people/joost-batenburg/&quot;&gt;Prof. dr. Joost Batenburg&lt;/a&gt; (LIACS), &lt;a href=&quot;mailto:k.j.batenburg@liacs.leidenuniv.nl&quot;&gt;k.j.batenburg@liacs.leidenuniv.nl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getty.edu/author/corona-madeline/&quot;&gt;Madeline Corona&lt;/a&gt; (Getty Museum), &lt;a href=&quot;mailto:MCorona@getty.edu&quot;&gt;MCorona@getty.edu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/collaboration/labs/flex-ray-lab/&quot;&gt;FleX-ray CT lab at CWI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/groups/computational-imaging/&quot;&gt;Computational Imaging group at CWI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Tue, 03 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Researchers developed a method to use existing X-ray imaging facilities for Computed Tomography (CT) scanning&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;598&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-69f18984.CF1BWYP4_Z2chW3l.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@socalcaral?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Cara Shelton&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a cross-post from our fellow &lt;a href=&quot;https://www.linkedin.com/in/francien-bossema-a587b012a/&quot;&gt;Dr. Francien Bossema&lt;/a&gt;. Originally published on the &lt;a href=&quot;https://www.cwi.nl/en/news/the-do-it-yourself-ct-scanner/&quot;&gt;CWI website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More information on our Fellowship programme &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;What if you could saw a wooden sculpture through to look at the tree rings? Could a clay sculpture be hollow? What type of instruments were used to craft art objects? These questions could be answered by X-ray imaging. In particular, CT-scans are useful to investigate historical art objects on the inside. The CT-scans that are suitable for this application are however not easily accessible for researchers and quite expensive to acquire. An international team of researchers led by CWI, the Dutch national research center for mathematics and computer science, has therefore developed a method to use existing X-ray imaging facilities for CT scanning. The results have been published &lt;a href=&quot;https://www.nature.com/articles/s41467-024-48102-w&quot;&gt;on the 14th of May in Nature Communications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Research facilities of large museums, such as the Rijksmuseum in Amsterdam, often house an X-ray imaging machine, with which they can perform live inspection of objects. This works in the same way as when you have to have an X-ray image taken at the hospital because of a broken bone. On such an image the bone can be seen, because it has a higher density than the muscles and tissue surrounding it. Usually, a few images are taken, so that the fracture can be inspected from different sides. For more complex problems, a CT scan is made. The technique behind CT scans is similar to X-ray images. For a CT scan hundreds of X-ray images are taken from different angles and then combined into a 3D image using reconstruction algorithms. This 3D image can then be ‘sliced open’ to obtain cross sections showing the interior.&lt;/p&gt;
&lt;p&gt;Over the past years, this technique has been increasingly applied to art objects, because it gives the possibility to investigate the interior without damaging the object. It is possible to date wooden objects by looking at the tree rings, assess the internal damage by an insect infestation or search for clues about the techniques used by the artist.&lt;/p&gt;
&lt;h2 id=&quot;no-ct-scanner-no-problem&quot;&gt;No CT scanner? No problem!&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-7f9418ba.CA__ftPK_c8ACr.webp&quot; srcset=&quot;&quot;&gt;
CT scans provide more information than X-ray images. In museums, however, simple X-ray imaging setups are more common. The components of the machine are similar (an X-ray tube, rotation stage and a detector), but for a CT scan the positions of these components during the scan need to be known very accurately. The researchers from CWI have therefore developed a method to calculate these positions after a data acquisition, with nothing more than a few small metal balls. These balls are put in a piece of foam and scanned alongside the object. Based on the location of the balls on the X-ray images, all the necessary positions can be calculated. These are then used to obtain a CT-scan.&lt;/p&gt;
&lt;p&gt;This unique project is a collaboration between a team of international researchers from CWI (Amsterdam), Leiden Institute of Advanced Computer Science (Leiden), Rijksmuseum (Amsterdam), The British Museum (London, UK) and the J. Paul Getty Museum (Los Angeles, USA). The X-ray imaging facilities of each of these museums, as well as the FleX-ray laboratory at CWI, have been used to test the new method and compare results in different facilities. The X-ray setups at the Rijksmuseum and the J. Paul Getty museum have been used for CT scans for the first time.&lt;/p&gt;
&lt;p&gt;The first author of the associated Nature Communications article &lt;a href=&quot;https://www.cwi.nl/en/people/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt; will defend her PhD thesis at Leiden University on the topic of CT scanning for cultural heritage on the 23rd of May.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can do something that was not possible before. CT scanning is an important imaging method for museums, because researchers can digitally cut open an object without damaging it. Our method makes it possible to further integrate this technique into research practices in the museum, without obtaining new hardware. We only use small metal balls of the type you also have in the pedals of your bike and algorithms specifically designed for this purpose. This means no extra investments are needed, while still providing an additional imaging technique.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Francien Bossema, CWI&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-method-gives-insights-into-the-making-process-of-a-sculpture&quot;&gt;New method gives insights into the making process of a sculpture&lt;/h2&gt;
&lt;p&gt;After the development of this technique, a sculpture made of plaster from the J. Paul Getty Museum was studied: &lt;em&gt;Python Killing a Gnu&lt;/em&gt;, by Antoine-Louis Barye (J. Paul Getty Museum, 85.SE.48). The sculpture originally had a different configuration, it was smaller and more compact because it was initially used as a model for a group of sculptures that was displayed on a dining table. The artist later decided to change the model to open and enlarge the arrangement and turn it into a stand-alone sculpture. The possibility to CT-scan the object was welcomed by the conservator who was investigating this object, Madeline Corona (Getty Museum): ‘On the X-ray images, we could see that areas had been broken, altered, and filled but it was difficult to understand exactly how the artist made these changes because there were too many overlapping features. The CT-scan gave us an incredible opportunity to obtain clearer and more detailed images of these areas of change. In the end, it provided important insights that allowed us to confirm some of our hypotheses about Barye’s working methods, something we could not have done without this technique.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-db1b697e.C0e1gOve_Z2g08pl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The ‘do-it-yourself’ Computed Tomography scanner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;359&quot; height=&quot;326&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-66c789e0.BgsP8rXT_Z2vQbdT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;more-information&quot;&gt;More information&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Article &lt;a href=&quot;https://www.nature.com/articles/s41467-024-48102-w&quot;&gt;&lt;em&gt;Enabling 3D CT-scanning of cultural heritage objects using only in-house 2D X-ray equipment in museums&lt;/em&gt;&lt;/a&gt; in Nature Communications 14 May 2024.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/people/francien-bossema/&quot;&gt;Francien Bossema&lt;/a&gt; (CWI/Rijksmuseum), &lt;a href=&quot;mailto:bossema@cwi.nl&quot;&gt;bossema@cwi.nl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/people/joost-batenburg/&quot;&gt;Prof. dr. Joost Batenburg&lt;/a&gt; (LIACS), &lt;a href=&quot;mailto:k.j.batenburg@liacs.leidenuniv.nl&quot;&gt;k.j.batenburg@liacs.leidenuniv.nl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getty.edu/author/corona-madeline/&quot;&gt;Madeline Corona&lt;/a&gt; (Getty Museum), &lt;a href=&quot;mailto:MCorona@getty.edu&quot;&gt;MCorona@getty.edu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/collaboration/labs/flex-ray-lab/&quot;&gt;FleX-ray CT lab at CWI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cwi.nl/en/groups/computational-imaging/&quot;&gt;Computational Imaging group at CWI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-do-it-yourself-computed-tomography-s-7f9418ba.CA__ftPK.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Is scientific software the new land grab?</title><link>https://blog.esciencecenter.nl/posts/2024-11-27---is-scientific-software-the-new-land-grab</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-11-27---is-scientific-software-the-new-land-grab</guid><description>&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;Scientific software platforms are not always as open as they look at first sight. Avoid getting locked in with this advice!&lt;/p&gt;
&lt;p&gt;“Do you know what CodeOcean is? Should I do this?” As a Research Software Engineer you often advise on all sorts of stuff, but I hadn’t heard this one before. In this case from a professor I work with, who’d sent a paper to Nature (as you do) and was asked by the editor to put the corresponding code in “CodeOcean”. Do I have an opinion on this?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-d0106fc2.-gtIOeaw_1S2f01.webp&quot; srcset=&quot;&quot;&gt;
You mean this could be my office? Photo by &lt;a href=&quot;https://unsplash.com/@oulashin?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Sean Oulashin&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;I’d never heard of CodeOcean. Data lakes, yes, and Wind River Systems, but CodeOcean? Never heard of. Fortunately, a web search found it quickly. I started reading.&lt;/p&gt;
&lt;p&gt;CodeOcean is a cloud-based workflow execution and data storage platform. You can make an account, and then upload your scientific data and scripts into the system. Because the script is in containers in the cloud, the script’s environment never changes, so it will always run and your research will be easily reproducible by other researchers, who will be able to comfortably find it when they next log in. You and others can then compose &lt;em&gt;workflows&lt;/em&gt;, step-by-step procedures for processing data, using your own software and that of others.&lt;/p&gt;
&lt;p&gt;Sounds great, right?&lt;/p&gt;
&lt;p&gt;Well, not to me actually, for reasons practical but mostly political. Let’s have a look at what’s really going on here.&lt;/p&gt;
&lt;h2 id=&quot;reproducing-and-reusing&quot;&gt;Reproducing and reusing&lt;/h2&gt;
&lt;p&gt;First, workflows. Workflows have been around for a long time. The idea of a workflow is that you can use a graphical editor to click together a series of steps that the computer is to perform, so that you can do custom processing without having to learn programming.&lt;/p&gt;
&lt;p&gt;This sounds nice in theory, but has its limitations. Steps can only be combined by feeding output from one step into the next. This is done through files, which is slow, and it’s limited in that you cannot send data back and forth between different programs.&lt;/p&gt;
&lt;p&gt;Graphical, drag-and-drop approaches, while easy to understand at first, quickly become overly complex in real-world scenarios. Because of this, scripting, where you describe what you want in text, is more popular and increasingly widely taught at universities. So a workflow system is not necessarily what people actually need, even if it looks good on screen.&lt;/p&gt;
&lt;p&gt;Furthermore, the story above cuts some corners. Reproducibility is not the same as reusability, and a script is not the same as a reusable software package. Putting your script in the system and getting it into a container and running is probably doable in most cases, and will create reproducibility, at least for a while depending on how complicated the thing is you’re trying to do.&lt;/p&gt;
&lt;p&gt;Science is more than just reproducing results though. We want to build on them, and we don’t want to have to re-implement everything that has already been researched. Instead, we’d like to reuse the work of our predecessors, so that we can get started right away. So we need &lt;em&gt;reusability&lt;/em&gt; as well as reproducibility.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We need reusability as well as reproducibility&lt;/p&gt;
&lt;p&gt;For reusability to work, a lot more work is needed. Researchers will have to convert their script, which is designed to run just once, on specific input data, with its author at hand to handle any issues as they arise, into a reusable workflow step that can run many times, handle a range of inputs, and solve any issues by itself or at least give an error that is understandable by someone who doesn’t know the software. This is a lot of work, and it takes a lot more skill and experience than creating a script.&lt;/p&gt;
&lt;p&gt;Setting up a workflow system in the cloud is one thing (especially if you pull a ready-made Open Source one off the Internet, as CodeOcean has to their credit done), but it needs to be populated with reusable software to be a useful workflow development platform, and that is difficult and time-consuming.&lt;/p&gt;
&lt;p&gt;So, will a system like this actually be useful? We have some existing workflow systems in science that are well used in particular communities, like &lt;a href=&quot;https://en.wikipedia.org/wiki/KNIME&quot;&gt;KNIME&lt;/a&gt;, so it’ll likely be of some use, but I don’t see this being the great solution to reusing scientific software. I do see something else, however: lock-in.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-420cacda.BYhmxsm-_ZLWveT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@reskp?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Jametlene Reskp&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-next-landgrab&quot;&gt;The next landgrab&lt;/h2&gt;
&lt;p&gt;CodeOcean claim that their platform is open. You can put your software and data on there, and everyone else can download it. And since the workflow engine they use, Apache Airflow, is Open Source, you may even be able to use the downloaded bits to put together a workflow locally.&lt;/p&gt;
&lt;p&gt;Doing that in practice is going to be quite a bit of work, and unlike with other repositories you need an account just to download anything. So there’s a network effect here: if most of the data and software you want is on this platform, then adding the rest is easier than getting the data and software out and running somewhere else.&lt;/p&gt;
&lt;p&gt;The login requirement also raises a barrier: I can easily grab data from a public server from a script, but with CodeOcean I have to go to my browser and do it by hand. Unless of course, I put my script into their platform.&lt;/p&gt;
&lt;p&gt;For a workflow platform like this to be truly open, it would have to be able to use data sets and compute steps from other platforms in its workflows, and allow other platforms (or local scripts) to use data and steps available on it. That would leave users free to choose any platform (or their own laptop) to put their data and software on, as well as to compose workflows on, because it ensures that we all can work together regardless of which product we choose to use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The downside of a federated system is that it’s more difficult to make money off of it.&lt;/p&gt;
&lt;p&gt;The downside of a federated system is that it’s more difficult to make money off of it. Without a network effect, multiple providers could compete, and users would be free to switch. Such a free market would reduce prices, and that would be good for us eternally cash-strapped scientists, but investors in these companies would get less profit.&lt;/p&gt;
&lt;p&gt;So, if I ran a company like CodeOcean and wanted to make good money, I’d do something else. I’d require people to sign up to use the service, I would make it so that you could only combine data and software from different sources if all the data and all the software is in my system, and then I would make deals with some high-ranking journals to get them to push scientists to put their data and software on my platform.&lt;/p&gt;
&lt;p&gt;Other scientists are likely to want to use those high-profile data sets and software modules, and to do so, I’d make them sign up first. I would then design my user interface to push people towards using the data and software on my site, rather than downloading them and using them locally.&lt;/p&gt;
&lt;p&gt;They’d add their software and data to my platform, this being easier than getting things to run on their own computers, which encourages others to join as well, and the whole thing will snowball.&lt;/p&gt;
&lt;p&gt;Then, having obtained many users, I would have a look at the email addresses with which they signed up. I’d contact the universities they work for, and explain politely that many of their employees are using my service. I’d tell them that free accounts are going to go away, and that the university will have to pay an annual fee.&lt;/p&gt;
&lt;p&gt;If they refuse, I’d block their scientists from my platform. The scientists would then protest their university administration because, without their data and software, they cannot work. The university would then pay me, I’d re-enable access, and subsequently retire to a tropical beach to sip cocktails and add more features to my scientific software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;861&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-53a82e4a.BuANbNvh_ZDhgk3.webp&quot; srcset=&quot;&quot;&gt;
I’ll need to order a cup holder for my laptop… Photo by &lt;a href=&quot;https://unsplash.com/@whitney_wright?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Whitney Wright&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;déja-vu&quot;&gt;Déja vu&lt;/h2&gt;
&lt;p&gt;Am I a brilliant business strategist? Of course not. This business model, in which society pays people with public money to produce scientific output, which is then appropriated by a commercial platform and sold back to the public, is what Open Access has fought hard against.&lt;/p&gt;
&lt;p&gt;It’s taken a long time to get to a point where we are now mostly publishing Open Access (even in Nature, if you’re rich), and much of our publicly funded work is still locked away behind paywalls, but overall I’d say it’s been a success. That doesn’t deter people from trying to pull us back into the same trap however, this time for data and software. Instead of fighting our way out, maybe this time we should avoid falling into it in the first place.&lt;/p&gt;
&lt;p&gt;The good news is, we can! Instead of putting your data set on CodeOcean or a similar locked-in platform, put it on &lt;a href=&quot;https://zenodo.org/&quot;&gt;Zenodo&lt;/a&gt; or &lt;a href=&quot;https://figshare.com/&quot;&gt;Figshare&lt;/a&gt;. These platforms allow anyone to download your data without an account, enabling them to use it anywhere. Scripts can go there too, and like data, they’ll get a DOI so that you can refer to them from your Open Access paper.&lt;/p&gt;
&lt;p&gt;No one installs reusable software from Zenodo, so if you make a reusable program then it’s best to publish it to the standard repository for the programming language you’re using. Python should go on PyPI and into conda-forge, the latter is also good for packages in C, C++, and Fortran, and Julia, Rust, R, and Java all have their standard places too.&lt;/p&gt;
&lt;p&gt;These repositories are open, allowing anyone to install and use your software anywhere without getting locked into something. For development, you can use GitLab (your own or one in the cloud) or GitHub, which also allows anyone to clone your repository without signing up or putting their own software in there.&lt;/p&gt;
&lt;p&gt;Of course running these platforms isn’t free. Zenodo is paid for by CERN, the particle physics lab in Switzerland. Figshare is run by a company. The conda package manager is mostly developed by Anaconda Inc. (another company), conda-forge runs on spare cloud resources donated by Microsoft, GitHub is owned by Microsoft and GitLab is run by the company with the same name.&lt;/p&gt;
&lt;p&gt;The difference is that conda is open source and so are conda-forge’s scripts and bots, and that git is an independent open source program, so that I can trivially clone a git repository off of GitHub and push it onto GitLab or vice versa.&lt;/p&gt;
&lt;p&gt;Issues and pull requests are harder to move, and there is somewhat of a network effect on these latter platforms for developers, who need to have an account for security reasons, but you don’t get locked in just to run anything, and it’s still easy to combine software and data from different sources.&lt;/p&gt;
&lt;p&gt;Sometimes it’s useful to put something in the cloud. Scientific software is often poorly engineered and difficult to install, and it can be nice to share an entire pre-installed environment sometimes, for demonstration purposes for example.&lt;/p&gt;
&lt;p&gt;If that’s what you want, go talk to your academic computing center! SURF for example here in The Netherlands have the &lt;a href=&quot;https://www.surf.nl/en/services/surf-research-cloud&quot;&gt;SURF Research Cloud&lt;/a&gt;, an environment in which you can create virtual machine images with your software, which other people can then run and use on SURF infrastructure.&lt;/p&gt;
&lt;p&gt;This does require an account (a standard SURFconext one that you use for their other services too), but at least it’s an account with a not-for-profit whose task it is to provide these resources to scientists. In short, SURF are working for you, not for a return on investment.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-a2a5337a.BLFLgvCk_qumPd.webp&quot; srcset=&quot;&quot;&gt;
Example of a researcher using the SURF Research Cloud. Photo by &lt;a href=&quot;https://unsplash.com/@timmossholder?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tim Mossholder&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-short&quot;&gt;In short&lt;/h2&gt;
&lt;p&gt;If someone invites you to put your scientific software onto their platform then you should have a good look first to see what this platform is for. Is this publicly funded infrastructure set up to make science more open and to support open collaboration? Then go right ahead. Is it commercial? Then it could still be okay, if it’s open enough. But beware of companies trying to appropriate your publicly funded work. We don’t need to fall into that trap again.&lt;/p&gt;</description><pubDate>Wed, 27 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;Scientific software platforms are not always as open as they look at first sight. Avoid getting locked in with this advice!&lt;/p&gt;
&lt;p&gt;“Do you know what CodeOcean is? Should I do this?” As a Research Software Engineer you often advise on all sorts of stuff, but I hadn’t heard this one before. In this case from a professor I work with, who’d sent a paper to Nature (as you do) and was asked by the editor to put the corresponding code in “CodeOcean”. Do I have an opinion on this?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-d0106fc2.-gtIOeaw_1S2f01.webp&quot; srcset=&quot;&quot;&gt;
You mean this could be my office? Photo by &lt;a href=&quot;https://unsplash.com/@oulashin?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Sean Oulashin&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;I’d never heard of CodeOcean. Data lakes, yes, and Wind River Systems, but CodeOcean? Never heard of. Fortunately, a web search found it quickly. I started reading.&lt;/p&gt;
&lt;p&gt;CodeOcean is a cloud-based workflow execution and data storage platform. You can make an account, and then upload your scientific data and scripts into the system. Because the script is in containers in the cloud, the script’s environment never changes, so it will always run and your research will be easily reproducible by other researchers, who will be able to comfortably find it when they next log in. You and others can then compose &lt;em&gt;workflows&lt;/em&gt;, step-by-step procedures for processing data, using your own software and that of others.&lt;/p&gt;
&lt;p&gt;Sounds great, right?&lt;/p&gt;
&lt;p&gt;Well, not to me actually, for reasons practical but mostly political. Let’s have a look at what’s really going on here.&lt;/p&gt;
&lt;h2 id=&quot;reproducing-and-reusing&quot;&gt;Reproducing and reusing&lt;/h2&gt;
&lt;p&gt;First, workflows. Workflows have been around for a long time. The idea of a workflow is that you can use a graphical editor to click together a series of steps that the computer is to perform, so that you can do custom processing without having to learn programming.&lt;/p&gt;
&lt;p&gt;This sounds nice in theory, but has its limitations. Steps can only be combined by feeding output from one step into the next. This is done through files, which is slow, and it’s limited in that you cannot send data back and forth between different programs.&lt;/p&gt;
&lt;p&gt;Graphical, drag-and-drop approaches, while easy to understand at first, quickly become overly complex in real-world scenarios. Because of this, scripting, where you describe what you want in text, is more popular and increasingly widely taught at universities. So a workflow system is not necessarily what people actually need, even if it looks good on screen.&lt;/p&gt;
&lt;p&gt;Furthermore, the story above cuts some corners. Reproducibility is not the same as reusability, and a script is not the same as a reusable software package. Putting your script in the system and getting it into a container and running is probably doable in most cases, and will create reproducibility, at least for a while depending on how complicated the thing is you’re trying to do.&lt;/p&gt;
&lt;p&gt;Science is more than just reproducing results though. We want to build on them, and we don’t want to have to re-implement everything that has already been researched. Instead, we’d like to reuse the work of our predecessors, so that we can get started right away. So we need &lt;em&gt;reusability&lt;/em&gt; as well as reproducibility.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We need reusability as well as reproducibility&lt;/p&gt;
&lt;p&gt;For reusability to work, a lot more work is needed. Researchers will have to convert their script, which is designed to run just once, on specific input data, with its author at hand to handle any issues as they arise, into a reusable workflow step that can run many times, handle a range of inputs, and solve any issues by itself or at least give an error that is understandable by someone who doesn’t know the software. This is a lot of work, and it takes a lot more skill and experience than creating a script.&lt;/p&gt;
&lt;p&gt;Setting up a workflow system in the cloud is one thing (especially if you pull a ready-made Open Source one off the Internet, as CodeOcean has to their credit done), but it needs to be populated with reusable software to be a useful workflow development platform, and that is difficult and time-consuming.&lt;/p&gt;
&lt;p&gt;So, will a system like this actually be useful? We have some existing workflow systems in science that are well used in particular communities, like &lt;a href=&quot;https://en.wikipedia.org/wiki/KNIME&quot;&gt;KNIME&lt;/a&gt;, so it’ll likely be of some use, but I don’t see this being the great solution to reusing scientific software. I do see something else, however: lock-in.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-420cacda.BYhmxsm-_ZLWveT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@reskp?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Jametlene Reskp&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-next-landgrab&quot;&gt;The next landgrab&lt;/h2&gt;
&lt;p&gt;CodeOcean claim that their platform is open. You can put your software and data on there, and everyone else can download it. And since the workflow engine they use, Apache Airflow, is Open Source, you may even be able to use the downloaded bits to put together a workflow locally.&lt;/p&gt;
&lt;p&gt;Doing that in practice is going to be quite a bit of work, and unlike with other repositories you need an account just to download anything. So there’s a network effect here: if most of the data and software you want is on this platform, then adding the rest is easier than getting the data and software out and running somewhere else.&lt;/p&gt;
&lt;p&gt;The login requirement also raises a barrier: I can easily grab data from a public server from a script, but with CodeOcean I have to go to my browser and do it by hand. Unless of course, I put my script into their platform.&lt;/p&gt;
&lt;p&gt;For a workflow platform like this to be truly open, it would have to be able to use data sets and compute steps from other platforms in its workflows, and allow other platforms (or local scripts) to use data and steps available on it. That would leave users free to choose any platform (or their own laptop) to put their data and software on, as well as to compose workflows on, because it ensures that we all can work together regardless of which product we choose to use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The downside of a federated system is that it’s more difficult to make money off of it.&lt;/p&gt;
&lt;p&gt;The downside of a federated system is that it’s more difficult to make money off of it. Without a network effect, multiple providers could compete, and users would be free to switch. Such a free market would reduce prices, and that would be good for us eternally cash-strapped scientists, but investors in these companies would get less profit.&lt;/p&gt;
&lt;p&gt;So, if I ran a company like CodeOcean and wanted to make good money, I’d do something else. I’d require people to sign up to use the service, I would make it so that you could only combine data and software from different sources if all the data and all the software is in my system, and then I would make deals with some high-ranking journals to get them to push scientists to put their data and software on my platform.&lt;/p&gt;
&lt;p&gt;Other scientists are likely to want to use those high-profile data sets and software modules, and to do so, I’d make them sign up first. I would then design my user interface to push people towards using the data and software on my site, rather than downloading them and using them locally.&lt;/p&gt;
&lt;p&gt;They’d add their software and data to my platform, this being easier than getting things to run on their own computers, which encourages others to join as well, and the whole thing will snowball.&lt;/p&gt;
&lt;p&gt;Then, having obtained many users, I would have a look at the email addresses with which they signed up. I’d contact the universities they work for, and explain politely that many of their employees are using my service. I’d tell them that free accounts are going to go away, and that the university will have to pay an annual fee.&lt;/p&gt;
&lt;p&gt;If they refuse, I’d block their scientists from my platform. The scientists would then protest their university administration because, without their data and software, they cannot work. The university would then pay me, I’d re-enable access, and subsequently retire to a tropical beach to sip cocktails and add more features to my scientific software.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;861&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-53a82e4a.BuANbNvh_ZDhgk3.webp&quot; srcset=&quot;&quot;&gt;
I’ll need to order a cup holder for my laptop… Photo by &lt;a href=&quot;https://unsplash.com/@whitney_wright?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Whitney Wright&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;déja-vu&quot;&gt;Déja vu&lt;/h2&gt;
&lt;p&gt;Am I a brilliant business strategist? Of course not. This business model, in which society pays people with public money to produce scientific output, which is then appropriated by a commercial platform and sold back to the public, is what Open Access has fought hard against.&lt;/p&gt;
&lt;p&gt;It’s taken a long time to get to a point where we are now mostly publishing Open Access (even in Nature, if you’re rich), and much of our publicly funded work is still locked away behind paywalls, but overall I’d say it’s been a success. That doesn’t deter people from trying to pull us back into the same trap however, this time for data and software. Instead of fighting our way out, maybe this time we should avoid falling into it in the first place.&lt;/p&gt;
&lt;p&gt;The good news is, we can! Instead of putting your data set on CodeOcean or a similar locked-in platform, put it on &lt;a href=&quot;https://zenodo.org/&quot;&gt;Zenodo&lt;/a&gt; or &lt;a href=&quot;https://figshare.com/&quot;&gt;Figshare&lt;/a&gt;. These platforms allow anyone to download your data without an account, enabling them to use it anywhere. Scripts can go there too, and like data, they’ll get a DOI so that you can refer to them from your Open Access paper.&lt;/p&gt;
&lt;p&gt;No one installs reusable software from Zenodo, so if you make a reusable program then it’s best to publish it to the standard repository for the programming language you’re using. Python should go on PyPI and into conda-forge, the latter is also good for packages in C, C++, and Fortran, and Julia, Rust, R, and Java all have their standard places too.&lt;/p&gt;
&lt;p&gt;These repositories are open, allowing anyone to install and use your software anywhere without getting locked into something. For development, you can use GitLab (your own or one in the cloud) or GitHub, which also allows anyone to clone your repository without signing up or putting their own software in there.&lt;/p&gt;
&lt;p&gt;Of course running these platforms isn’t free. Zenodo is paid for by CERN, the particle physics lab in Switzerland. Figshare is run by a company. The conda package manager is mostly developed by Anaconda Inc. (another company), conda-forge runs on spare cloud resources donated by Microsoft, GitHub is owned by Microsoft and GitLab is run by the company with the same name.&lt;/p&gt;
&lt;p&gt;The difference is that conda is open source and so are conda-forge’s scripts and bots, and that git is an independent open source program, so that I can trivially clone a git repository off of GitHub and push it onto GitLab or vice versa.&lt;/p&gt;
&lt;p&gt;Issues and pull requests are harder to move, and there is somewhat of a network effect on these latter platforms for developers, who need to have an account for security reasons, but you don’t get locked in just to run anything, and it’s still easy to combine software and data from different sources.&lt;/p&gt;
&lt;p&gt;Sometimes it’s useful to put something in the cloud. Scientific software is often poorly engineered and difficult to install, and it can be nice to share an entire pre-installed environment sometimes, for demonstration purposes for example.&lt;/p&gt;
&lt;p&gt;If that’s what you want, go talk to your academic computing center! SURF for example here in The Netherlands have the &lt;a href=&quot;https://www.surf.nl/en/services/surf-research-cloud&quot;&gt;SURF Research Cloud&lt;/a&gt;, an environment in which you can create virtual machine images with your software, which other people can then run and use on SURF infrastructure.&lt;/p&gt;
&lt;p&gt;This does require an account (a standard SURFconext one that you use for their other services too), but at least it’s an account with a not-for-profit whose task it is to provide these resources to scientists. In short, SURF are working for you, not for a return on investment.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Is scientific software the new land grab?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-a2a5337a.BLFLgvCk_qumPd.webp&quot; srcset=&quot;&quot;&gt;
Example of a researcher using the SURF Research Cloud. Photo by &lt;a href=&quot;https://unsplash.com/@timmossholder?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Tim Mossholder&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-short&quot;&gt;In short&lt;/h2&gt;
&lt;p&gt;If someone invites you to put your scientific software onto their platform then you should have a good look first to see what this platform is for. Is this publicly funded infrastructure set up to make science more open and to support open collaboration? Then go right ahead. Is it commercial? Then it could still be okay, if it’s open enough. But beware of companies trying to appropriate your publicly funded work. We don’t need to fall into that trap again.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/is-scientific-software-the-new-land-grab-d0106fc2.-gtIOeaw.jpg" medium="image"/><author>Lourens Veen</author></item><item><title>From Pandemic Response to Package Development</title><link>https://blog.esciencecenter.nl/posts/2024-11-26---from-pandemic-response-to-package-development</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-11-26---from-pandemic-response-to-package-development</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/fenne-riemslagh/&quot;&gt;Fenne Riemslagh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We had the pleasure of sitting down with &lt;a href=&quot;http://www.linkedin.com/in/kirsten-bulsink&quot;&gt;Kirsten Bulsink&lt;/a&gt;, a data scientist at the Dutch National Institute for Public Health and the Environment (&lt;a href=&quot;http://www.rivm.nl&quot;&gt;RIVM&lt;/a&gt;). Our discussion covered her journey from pandemic response to R-package development and how the Netherlands eScience Center played a part in creating a crucial part of tooling at RIVM. Her story demonstrates the importance of collaborative work in research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-32f8ae64.B6ocEb2n_Zt1Q8v.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@chesnutt?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Eran Menashri&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Q: Can you tell us about your background and current role at RIVM?**&lt;/p&gt;
&lt;p&gt;A: I’ve been working at RIVM for a little over three years now. My background is in psychology, with a master’s in neuroscience. During my Research Master’s, I discovered my passion for data analysis and finding answers through data. This led me to pursue a minor in data science.&lt;/p&gt;
&lt;p&gt;I started working at RIVM during the COVID-19 pandemic. Initially, it was a chaotic time, with researchers working overtime to analyze and report data quickly. When I joined, there was already a semi-automatic data pipeline in place, but we still had to tackle complex challenges, like calculating vaccination rates with data from a selected group (because of opt-out).&lt;/p&gt;
&lt;p&gt;As our team grew to about 9 to 10 people, we started organizing workshops to reflect on our processes. We asked ourselves what worked well and what we’d do differently if we could start over. This reflection led to the development of new tools and approaches.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“…we started organizing workshops to reflect on our processes. We asked ourselves what worked well and what we’d do differently if we could start over. This reflection led to the development of new tools and approaches.”&lt;/p&gt;
&lt;p&gt;Before the pandemic, processes and methods differed for different infectious diseases. As a result, researchers at RIVM had to perform many actions manually, and these processes could differ per infectious disease. The pandemic necessitated more knowledge sharing and collaboration. We started standardizing and automating data transformation and reporting for infectious diseases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: We understand that you and your colleague participated in the R-packaging workshop organized by the eScience Center. Can you tell us about that experience and the R-package your team developed?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, that’s correct. One of my colleagues actually took the &lt;a href=&quot;https://carpentries-incubator.github.io/lesson-R-packaging/&quot;&gt;R-packaging workshop&lt;/a&gt; offered by the eScience Center before I did. Later, I also had the opportunity to take the same course.&lt;/p&gt;
&lt;p&gt;The package, which now serves as a core tool for epidemiological pipelines at RIVM, provides functionality for loading, cleaning, and reporting data, with various checks in place. It also includes functions to create graphs in RIVM colors and style.&lt;/p&gt;
&lt;p&gt;For example, during the COVID-19 pandemic, we used analysis methods to process data on positive cases, calculate the number of cases over time, and generate reports. Now, we use the package for monitoring and reporting on various infectious diseases like &lt;a href=&quot;https://www.rivm.nl/soa/cijfers-en-rapportages-soa&quot;&gt;sexually transmitted infections&lt;/a&gt; and &lt;a href=&quot;https://www.rivm.nl/luchtweginfecties/actuele-cijfers&quot;&gt;respiratory infections&lt;/a&gt;, not just COVID-19.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-64e59eb1.DcKWcbN2_Z18Wl75.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@f12r?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Fahim Muntashir&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;**&lt;/p&gt;
&lt;p&gt;How did the R-packaging workshop help professionalize your package?**&lt;/p&gt;
&lt;p&gt;After joining the workshop at the Netherlands eScience Center, I organized a session for my team to share what I had learned. While my colleagues had already done a great job, the workshop helped us improve consistency in managing dependencies. We also enhanced our documentation. The package improvements made it easier for others to use the package. Installation became smoother, and users no longer had to figure out why they needed to install extra packages.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“The package improvements made it easier for others to use the package. Installation became smoother, and users no longer had to figure out why they needed to install extra packages.”&lt;/p&gt;
&lt;p&gt;Later on, I also took the &lt;a href=&quot;https://carpentries-incubator.github.io/python-intermediate-development/&quot;&gt;Python software development course&lt;/a&gt; offered by the eScience Center, which was really eye-opening. I learned about tools like linters, virtual environments, testing, coverage, and CI/CD pipelines. This knowledge made us realize we needed to implement these practices in our R-package as well.&lt;/p&gt;
&lt;p&gt;After gaining all this knowledge from the eScience Center courses, we felt ready to take our package to the next level. We decided to organize hackathons to focus on implementing best practices and improving our package structure.&lt;/p&gt;
&lt;p&gt;Our first main goal was to internally demonstrate that we had a high-quality product, especially since many analyses of infectious disease data rely on this package. Our second goal was to share our methodology with external parties like the GGD (Municipal Health Services), even if we couldn’t share the actual data.&lt;/p&gt;
&lt;p&gt;We reached out to the eScience Center training team for support, and they connected us with &lt;a href=&quot;https://www.esciencecenter.nl/team/pablo-rodriguez-sanchez/&quot;&gt;Pablo Rodríguez Sánchez&lt;/a&gt; (one of the eScience Center’s Research Software Engineers (RSEs) and main author of the R-packaging course, ed.) to consult during our hackathon. This collaboration was very valuable in guiding our efforts and providing expert insights.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-f8e29e49.CecW0r8P_USIcj.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kommumikation?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mika Baumeister&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;strong&gt;Q: What were the outcomes of the hackathons?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We had two hackathons. In the first one, we focused on testing and documentation. We increased our test coverage and improved our package documentation, including creating a vignette with examples.&lt;/p&gt;
&lt;p&gt;The second hackathon was about splitting our large package into smaller, more manageable ones. We also worked on establishing a workflow for potentially publishing the package on GitHub while keeping our main development on RIVM’s internal GitLab.&lt;/p&gt;
&lt;p&gt;Pablo provided a fresh perspective and helped us confirm that we were on the right track. His expertise was particularly valuable in the second hackathon when we were making decisions about package structure and workflow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“Pablo Rodríguez-Sánchez, Research Software Engineer (RSE) at the Netherlands eScience Center, provided a fresh perspective and helped us confirm that we were on the right track. His expertise was particularly valuable in the second hackathon when we were making decisions about package structure and workflow.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: How has this experience changed your team’s way of working?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the past year, we’ve started to work much more like a software development team. We now use a Kanban board for project management and have implemented CI/CD pipelines, which have made our development process much smoother. The package split has made everything more manageable, and it’s easier to see where we need certain tests or improvements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: What’s next for your package and team?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We’re planning to release some of our packages in GitHub in the next couple of months, which will allow external users to download and use them. We’re also focusing on internal knowledge sharing and running workshops about our tooling.&lt;/p&gt;
&lt;p&gt;We value having the eScience Center as a sparring partner for tackling these technical challenges.&lt;/p&gt;
&lt;p&gt;In my current role I now have a nice combination of technical skills and advisory tasks. We advise and make other people at RIVM enthusiastic about our tools. Our recent experience in developing this R package has been invaluable.&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center would like to thank Kirsten for her time for the interview . We look forward to continuing our collaboration. If you want to learn more about collaborating with the eScience Center or are interested in our training programme, please visit &lt;a href=&quot;https://www.esciencecenter.nl/digital-skills/&quot;&gt;Training &amp;#x26; Workshops — eScience Center&lt;/a&gt;. If you are interested in receiving consulting like Kirsten did, you may be interested in our &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;Fellowship Programme&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 26 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/fenne-riemslagh/&quot;&gt;Fenne Riemslagh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We had the pleasure of sitting down with &lt;a href=&quot;http://www.linkedin.com/in/kirsten-bulsink&quot;&gt;Kirsten Bulsink&lt;/a&gt;, a data scientist at the Dutch National Institute for Public Health and the Environment (&lt;a href=&quot;http://www.rivm.nl&quot;&gt;RIVM&lt;/a&gt;). Our discussion covered her journey from pandemic response to R-package development and how the Netherlands eScience Center played a part in creating a crucial part of tooling at RIVM. Her story demonstrates the importance of collaborative work in research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-32f8ae64.B6ocEb2n_Zt1Q8v.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@chesnutt?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Eran Menashri&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Q: Can you tell us about your background and current role at RIVM?**&lt;/p&gt;
&lt;p&gt;A: I’ve been working at RIVM for a little over three years now. My background is in psychology, with a master’s in neuroscience. During my Research Master’s, I discovered my passion for data analysis and finding answers through data. This led me to pursue a minor in data science.&lt;/p&gt;
&lt;p&gt;I started working at RIVM during the COVID-19 pandemic. Initially, it was a chaotic time, with researchers working overtime to analyze and report data quickly. When I joined, there was already a semi-automatic data pipeline in place, but we still had to tackle complex challenges, like calculating vaccination rates with data from a selected group (because of opt-out).&lt;/p&gt;
&lt;p&gt;As our team grew to about 9 to 10 people, we started organizing workshops to reflect on our processes. We asked ourselves what worked well and what we’d do differently if we could start over. This reflection led to the development of new tools and approaches.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“…we started organizing workshops to reflect on our processes. We asked ourselves what worked well and what we’d do differently if we could start over. This reflection led to the development of new tools and approaches.”&lt;/p&gt;
&lt;p&gt;Before the pandemic, processes and methods differed for different infectious diseases. As a result, researchers at RIVM had to perform many actions manually, and these processes could differ per infectious disease. The pandemic necessitated more knowledge sharing and collaboration. We started standardizing and automating data transformation and reporting for infectious diseases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: We understand that you and your colleague participated in the R-packaging workshop organized by the eScience Center. Can you tell us about that experience and the R-package your team developed?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, that’s correct. One of my colleagues actually took the &lt;a href=&quot;https://carpentries-incubator.github.io/lesson-R-packaging/&quot;&gt;R-packaging workshop&lt;/a&gt; offered by the eScience Center before I did. Later, I also had the opportunity to take the same course.&lt;/p&gt;
&lt;p&gt;The package, which now serves as a core tool for epidemiological pipelines at RIVM, provides functionality for loading, cleaning, and reporting data, with various checks in place. It also includes functions to create graphs in RIVM colors and style.&lt;/p&gt;
&lt;p&gt;For example, during the COVID-19 pandemic, we used analysis methods to process data on positive cases, calculate the number of cases over time, and generate reports. Now, we use the package for monitoring and reporting on various infectious diseases like &lt;a href=&quot;https://www.rivm.nl/soa/cijfers-en-rapportages-soa&quot;&gt;sexually transmitted infections&lt;/a&gt; and &lt;a href=&quot;https://www.rivm.nl/luchtweginfecties/actuele-cijfers&quot;&gt;respiratory infections&lt;/a&gt;, not just COVID-19.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-64e59eb1.DcKWcbN2_Z18Wl75.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@f12r?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Fahim Muntashir&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;**&lt;/p&gt;
&lt;p&gt;How did the R-packaging workshop help professionalize your package?**&lt;/p&gt;
&lt;p&gt;After joining the workshop at the Netherlands eScience Center, I organized a session for my team to share what I had learned. While my colleagues had already done a great job, the workshop helped us improve consistency in managing dependencies. We also enhanced our documentation. The package improvements made it easier for others to use the package. Installation became smoother, and users no longer had to figure out why they needed to install extra packages.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“The package improvements made it easier for others to use the package. Installation became smoother, and users no longer had to figure out why they needed to install extra packages.”&lt;/p&gt;
&lt;p&gt;Later on, I also took the &lt;a href=&quot;https://carpentries-incubator.github.io/python-intermediate-development/&quot;&gt;Python software development course&lt;/a&gt; offered by the eScience Center, which was really eye-opening. I learned about tools like linters, virtual environments, testing, coverage, and CI/CD pipelines. This knowledge made us realize we needed to implement these practices in our R-package as well.&lt;/p&gt;
&lt;p&gt;After gaining all this knowledge from the eScience Center courses, we felt ready to take our package to the next level. We decided to organize hackathons to focus on implementing best practices and improving our package structure.&lt;/p&gt;
&lt;p&gt;Our first main goal was to internally demonstrate that we had a high-quality product, especially since many analyses of infectious disease data rely on this package. Our second goal was to share our methodology with external parties like the GGD (Municipal Health Services), even if we couldn’t share the actual data.&lt;/p&gt;
&lt;p&gt;We reached out to the eScience Center training team for support, and they connected us with &lt;a href=&quot;https://www.esciencecenter.nl/team/pablo-rodriguez-sanchez/&quot;&gt;Pablo Rodríguez Sánchez&lt;/a&gt; (one of the eScience Center’s Research Software Engineers (RSEs) and main author of the R-packaging course, ed.) to consult during our hackathon. This collaboration was very valuable in guiding our efforts and providing expert insights.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Pandemic Response to Package Development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-f8e29e49.CecW0r8P_USIcj.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kommumikation?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mika Baumeister&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;strong&gt;Q: What were the outcomes of the hackathons?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We had two hackathons. In the first one, we focused on testing and documentation. We increased our test coverage and improved our package documentation, including creating a vignette with examples.&lt;/p&gt;
&lt;p&gt;The second hackathon was about splitting our large package into smaller, more manageable ones. We also worked on establishing a workflow for potentially publishing the package on GitHub while keeping our main development on RIVM’s internal GitLab.&lt;/p&gt;
&lt;p&gt;Pablo provided a fresh perspective and helped us confirm that we were on the right track. His expertise was particularly valuable in the second hackathon when we were making decisions about package structure and workflow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“Pablo Rodríguez-Sánchez, Research Software Engineer (RSE) at the Netherlands eScience Center, provided a fresh perspective and helped us confirm that we were on the right track. His expertise was particularly valuable in the second hackathon when we were making decisions about package structure and workflow.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: How has this experience changed your team’s way of working?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the past year, we’ve started to work much more like a software development team. We now use a Kanban board for project management and have implemented CI/CD pipelines, which have made our development process much smoother. The package split has made everything more manageable, and it’s easier to see where we need certain tests or improvements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: What’s next for your package and team?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We’re planning to release some of our packages in GitHub in the next couple of months, which will allow external users to download and use them. We’re also focusing on internal knowledge sharing and running workshops about our tooling.&lt;/p&gt;
&lt;p&gt;We value having the eScience Center as a sparring partner for tackling these technical challenges.&lt;/p&gt;
&lt;p&gt;In my current role I now have a nice combination of technical skills and advisory tasks. We advise and make other people at RIVM enthusiastic about our tools. Our recent experience in developing this R package has been invaluable.&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center would like to thank Kirsten for her time for the interview . We look forward to continuing our collaboration. If you want to learn more about collaborating with the eScience Center or are interested in our training programme, please visit &lt;a href=&quot;https://www.esciencecenter.nl/digital-skills/&quot;&gt;Training &amp;#x26; Workshops — eScience Center&lt;/a&gt;. If you are interested in receiving consulting like Kirsten did, you may be interested in our &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;Fellowship Programme&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/from-pandemic-response-to-package-develo-32f8ae64.B6ocEb2n.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Why should you care about reproducible code — and how to get started?</title><link>https://blog.esciencecenter.nl/posts/2024-11-14---why-should-you-care-about-reproducible-code-and-how-to-get-s</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-11-14---why-should-you-care-about-reproducible-code-and-how-to-get-s</guid><description>&lt;h2 id=&quot;on-23-april-2024-the-first-national-research-software-day-took-place-in-hilversum-the-netherlands-during-the-unconference-part-of-the-program-eduard-klapwijk-ran-the-session-about-the-importance-of-reproducible-code&quot;&gt;On 23 April 2024, the first ‘&lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt;’ took place in Hilversum, the Netherlands. During the unconference part of the program, &lt;a href=&quot;https://www.universiteitleiden.nl/medewerkers/eduard-klapwijk#tab-1&quot;&gt;Eduard Klapwijk&lt;/a&gt; ran the session about the importance of reproducible code.&lt;/h2&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why should you care about reproducible code — and how to get started?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;495&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-should-you-care-about-reproducible-c-984b86bd.CiHwM2go_2vr8Xa.webp&quot; srcset=&quot;&quot;&gt;
Credit: &lt;a href=&quot;https://the-turing-way.netlify.app/_images/reproducibility.jpg&quot;&gt;The Turing Way&lt;/a&gt;&lt;em&gt;Authors: Diana I. Bocancea¹, Daniela Gawehns², Julian Lopez Gordillo³, Sam Langton¹, Katinka Rus¹, Sally Hogenboom⁴, Iris Spruit⁵, Eduard Klapwijk⁶&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Despite the increased awareness regarding reproducibility in recent years, most research results are not &lt;a href=&quot;https://book.the-turing-way.org/reproducible-research/overview/overview-definitions&quot;&gt;computationally reproducible&lt;/a&gt;: they cannot be independently reproduced. The main reason for this is that in most cases, data and code are not shared publicly. But even when a researcher openly shares their data and code with the public, reviewers or research colleagues, their findings can rarely be reproduced in their entirety. Perhaps the code cannot be executed, only parts of the results are generated, or perhaps the results produced are totally different from the published study. Reproducibility can even be a challenge internally. As any programmer will know, just because your code runs perfectly today, it does not mean it will run perfectly in five years’ time (or even five days’ time!).&lt;/p&gt;
&lt;p&gt;But why does writing reproducible code even matter, and how might you as a researcher get started on this journey toward reproducible research?&lt;/p&gt;
&lt;h2 id=&quot;benefits-of-working-reproducibly&quot;&gt;&lt;em&gt;Benefits of working reproducibly&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;One reason is that it will make your life as a researcher easier! Many of the components that make a piece of research reproducible — well-documented, clearly written code, containerised environments, properly organized data — are also things that save a lot of time. These activities ensure that when you return to code six months later, the scripts still run, and you don’t have to spend three days debugging them. It also means that your code can be shared and reused by your colleagues, saving them time, and giving you credit (e.g., authorship) in the process. There are other reasons too, including reputational benefits and advantages during peer review. You can read more about ‘selfish’ reasons to make your research reproducible &lt;a href=&quot;https://genomebiology.biomedcentral.com/articles/10.1186/s13059-015-0850-7%22%20%EF%B7%9FHYPERLINK%20%22https://doi.org/10.1186/s13059-015-0850-7&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What about the scientific community? We are currently in a situation where a large proportion of research is not reproducible. This situation threatens the integrity of scientific research, weakens our evidence base, and ultimately might lessen public trust in science. The main method for scrutinising and sharing scientific results — peer-reviewed journals — are slowly adapting to this realisation. Increasingly, researchers are encouraged, if not expected, to provide their data, code and other materials used alongside the publication itself. In time, we could see reproducibility move from being an optional bonus to becoming a mandatory part of the research (and publication) process. Adapting to this change early will bring you all the benefits noted above (e.g., timesaving, code reuse) but will also prepare you for the future.&lt;/p&gt;
&lt;h2 id=&quot;reproducible-tools-as-a-contribution-to-science&quot;&gt;&lt;em&gt;Reproducible tools as a contribution to science&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;On that note, the changing perspective on the importance of reproducibility is bringing new career paths with it. For example, beyond the fundamental tools that enable reproducible research (such as git for version control), other higher-level tools are appearing to address certain challenges particular to some scientific domains. Usually, they are aimed at solving well-known problems for researchers from a certain field, problems not well-known outside of one niche. They might revolve around workflow management and experiment design or standardisation of certain procedures within the community. In many cases, the developers behind those software tools and resources are… the researchers themselves. They might have struggled with these issues in their own research and decided to take up the task of developing the tools that they wished they had (for example, extensive Python-based processing pipelines such as &lt;a href=&quot;https://doi.org/10.1038/s41592-018-0235-4&quot;&gt;fmriprep&lt;/a&gt; in the neuroimaging field, and thousands of R packages ranging from complex statistical modelling packages such as &lt;a href=&quot;https://doi.org/10.18637/jss.v080.i01&quot;&gt;brms&lt;/a&gt; for Bayesian regression to packages to help you formatting manuscripts such as &lt;a href=&quot;https://cran.r-project.org/web/packages/papaja/index.html&quot;&gt;papaja&lt;/a&gt;). In doing so, they shifted their focus from their original subject domain to the mission of making research within that domain reproducible. This typically takes the form of developing the software libraries that make that possible and integrating them with the standard software used within the domain.&lt;/p&gt;
&lt;p&gt;The whole scientific community can benefit from such tools! Newer research can be built on top of them, without the need to solve common reproducibility issues from scratch. These software developments can be just as valuable a contribution to the research domain as other research findings, and as such, they should be recognised accordingly. And just like it is possible to publish your research findings, it should be possible to publish your code contributions when they are significant enough. A good example of this idea put into practice is the &lt;a href=&quot;https://joss.theoj.org/&quot;&gt;Journal of Open Source Sofware&lt;/a&gt; (JOSS), where the submitted code takes the main stage in the review process (as opposed to be required as “supplementary material”). Initiatives like JOSS showcase developments around reproducible research as a meaningful contribution to science and a viable development path, both of which are powerful incentives for researchers to get interested in the topic.&lt;/p&gt;
&lt;p&gt;In time, with all these smaller and bigger changes, scientific research can become more trustworthy, more reliable, and in turn, more impactful.&lt;/p&gt;
&lt;h2 id=&quot;how-to-get-started&quot;&gt;How to get started*&lt;/h2&gt;
&lt;p&gt;The inevitable question that follows is then: how to get started with reproducibility? One answer is training. Luckily, there are a lot of initiatives for training that will help you to get started, both nationally and internationally. For example, a lot of institutions organize Software and Data &lt;a href=&quot;https://carpentries.org/&quot;&gt;Carpentries&lt;/a&gt; that offer foundational coding and data science skills.&lt;/p&gt;
&lt;p&gt;One way senior academics can make a difference — as group leaders, supervisors, and grant reviewers — is to give (junior) colleagues the time and incentives to value and practice reproducibility. For instance, supervisors could have all PhD students replicate and extend an existing analysis as part of their initial research. The process of reproducing an existing work will familiarize the student with the common challenges that come with doing good science. The work of reproducing someone else’s work might entail finding and understanding a certain dataset (sometimes difficult to even get access to), as well as the software (e.g. scripts or packages) that was used to produce the results. Running the previous analysis, often on a different computer and at a later time (when software dependencies have likely changed) would check the computational reproducibility of the previous work, and in doing so, be a valuable learning experience for the student.&lt;/p&gt;
&lt;p&gt;Group leaders benefit from reproducible workflows as it prevents (PhD) students from re-writing the same piece of software again and again. While learning the ropes is important for any junior scholar, it is not very efficient if every new generation of students re-writes code for basic operations or frequently used analysis methods.&lt;/p&gt;
&lt;p&gt;In addition to the benefits of an academic career, researchers themselves also increase their employability outside of academia by learning digital skills (such as version control or programming reusable pieces of code) that are valued in many different (industry) jobs.&lt;/p&gt;
&lt;p&gt;In modern science, computational methods are the norm in almost every discipline. Yet attempts at reproducibility are almost always unsuccessful due to missing materials and/or lack of skills. Part of this problem can be mitigated by learning how to produce reproducible code: how to write documentation, perform version control, and manage packages. Doing so will benefit you as a researcher, but also your colleagues, and the wider scientific community, because your (coding) efforts will become reusable. Increasing the use of reproducible workflows is in the interest of many stakeholders in academia — increasing the reproducibility of research is key for a broader change in how we do science.&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amc.nl/web/home.htm&quot;&gt;Amsterdam UMC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.umcg.nl/&quot;&gt;University Medical Center Groningen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.naturalis.nl/en&quot;&gt;Naturalis Biodiversity Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ou.nl/en/home&quot;&gt;Open Universiteit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.universiteitleiden.nl/en&quot;&gt;Universiteit Leiden&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.eur.nl/en/essb&quot;&gt;Erasmus School of Social and Behavioural Sciences&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Thu, 14 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;on-23-april-2024-the-first-national-research-software-day-took-place-in-hilversum-the-netherlands-during-the-unconference-part-of-the-program-eduard-klapwijk-ran-the-session-about-the-importance-of-reproducible-code&quot;&gt;On 23 April 2024, the first ‘&lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt;’ took place in Hilversum, the Netherlands. During the unconference part of the program, &lt;a href=&quot;https://www.universiteitleiden.nl/medewerkers/eduard-klapwijk#tab-1&quot;&gt;Eduard Klapwijk&lt;/a&gt; ran the session about the importance of reproducible code.&lt;/h2&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why should you care about reproducible code — and how to get started?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;495&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-should-you-care-about-reproducible-c-984b86bd.CiHwM2go_2vr8Xa.webp&quot; srcset=&quot;&quot;&gt;
Credit: &lt;a href=&quot;https://the-turing-way.netlify.app/_images/reproducibility.jpg&quot;&gt;The Turing Way&lt;/a&gt;&lt;em&gt;Authors: Diana I. Bocancea¹, Daniela Gawehns², Julian Lopez Gordillo³, Sam Langton¹, Katinka Rus¹, Sally Hogenboom⁴, Iris Spruit⁵, Eduard Klapwijk⁶&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Despite the increased awareness regarding reproducibility in recent years, most research results are not &lt;a href=&quot;https://book.the-turing-way.org/reproducible-research/overview/overview-definitions&quot;&gt;computationally reproducible&lt;/a&gt;: they cannot be independently reproduced. The main reason for this is that in most cases, data and code are not shared publicly. But even when a researcher openly shares their data and code with the public, reviewers or research colleagues, their findings can rarely be reproduced in their entirety. Perhaps the code cannot be executed, only parts of the results are generated, or perhaps the results produced are totally different from the published study. Reproducibility can even be a challenge internally. As any programmer will know, just because your code runs perfectly today, it does not mean it will run perfectly in five years’ time (or even five days’ time!).&lt;/p&gt;
&lt;p&gt;But why does writing reproducible code even matter, and how might you as a researcher get started on this journey toward reproducible research?&lt;/p&gt;
&lt;h2 id=&quot;benefits-of-working-reproducibly&quot;&gt;&lt;em&gt;Benefits of working reproducibly&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;One reason is that it will make your life as a researcher easier! Many of the components that make a piece of research reproducible — well-documented, clearly written code, containerised environments, properly organized data — are also things that save a lot of time. These activities ensure that when you return to code six months later, the scripts still run, and you don’t have to spend three days debugging them. It also means that your code can be shared and reused by your colleagues, saving them time, and giving you credit (e.g., authorship) in the process. There are other reasons too, including reputational benefits and advantages during peer review. You can read more about ‘selfish’ reasons to make your research reproducible &lt;a href=&quot;https://genomebiology.biomedcentral.com/articles/10.1186/s13059-015-0850-7%22%20%EF%B7%9FHYPERLINK%20%22https://doi.org/10.1186/s13059-015-0850-7&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What about the scientific community? We are currently in a situation where a large proportion of research is not reproducible. This situation threatens the integrity of scientific research, weakens our evidence base, and ultimately might lessen public trust in science. The main method for scrutinising and sharing scientific results — peer-reviewed journals — are slowly adapting to this realisation. Increasingly, researchers are encouraged, if not expected, to provide their data, code and other materials used alongside the publication itself. In time, we could see reproducibility move from being an optional bonus to becoming a mandatory part of the research (and publication) process. Adapting to this change early will bring you all the benefits noted above (e.g., timesaving, code reuse) but will also prepare you for the future.&lt;/p&gt;
&lt;h2 id=&quot;reproducible-tools-as-a-contribution-to-science&quot;&gt;&lt;em&gt;Reproducible tools as a contribution to science&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;On that note, the changing perspective on the importance of reproducibility is bringing new career paths with it. For example, beyond the fundamental tools that enable reproducible research (such as git for version control), other higher-level tools are appearing to address certain challenges particular to some scientific domains. Usually, they are aimed at solving well-known problems for researchers from a certain field, problems not well-known outside of one niche. They might revolve around workflow management and experiment design or standardisation of certain procedures within the community. In many cases, the developers behind those software tools and resources are… the researchers themselves. They might have struggled with these issues in their own research and decided to take up the task of developing the tools that they wished they had (for example, extensive Python-based processing pipelines such as &lt;a href=&quot;https://doi.org/10.1038/s41592-018-0235-4&quot;&gt;fmriprep&lt;/a&gt; in the neuroimaging field, and thousands of R packages ranging from complex statistical modelling packages such as &lt;a href=&quot;https://doi.org/10.18637/jss.v080.i01&quot;&gt;brms&lt;/a&gt; for Bayesian regression to packages to help you formatting manuscripts such as &lt;a href=&quot;https://cran.r-project.org/web/packages/papaja/index.html&quot;&gt;papaja&lt;/a&gt;). In doing so, they shifted their focus from their original subject domain to the mission of making research within that domain reproducible. This typically takes the form of developing the software libraries that make that possible and integrating them with the standard software used within the domain.&lt;/p&gt;
&lt;p&gt;The whole scientific community can benefit from such tools! Newer research can be built on top of them, without the need to solve common reproducibility issues from scratch. These software developments can be just as valuable a contribution to the research domain as other research findings, and as such, they should be recognised accordingly. And just like it is possible to publish your research findings, it should be possible to publish your code contributions when they are significant enough. A good example of this idea put into practice is the &lt;a href=&quot;https://joss.theoj.org/&quot;&gt;Journal of Open Source Sofware&lt;/a&gt; (JOSS), where the submitted code takes the main stage in the review process (as opposed to be required as “supplementary material”). Initiatives like JOSS showcase developments around reproducible research as a meaningful contribution to science and a viable development path, both of which are powerful incentives for researchers to get interested in the topic.&lt;/p&gt;
&lt;p&gt;In time, with all these smaller and bigger changes, scientific research can become more trustworthy, more reliable, and in turn, more impactful.&lt;/p&gt;
&lt;h2 id=&quot;how-to-get-started&quot;&gt;How to get started*&lt;/h2&gt;
&lt;p&gt;The inevitable question that follows is then: how to get started with reproducibility? One answer is training. Luckily, there are a lot of initiatives for training that will help you to get started, both nationally and internationally. For example, a lot of institutions organize Software and Data &lt;a href=&quot;https://carpentries.org/&quot;&gt;Carpentries&lt;/a&gt; that offer foundational coding and data science skills.&lt;/p&gt;
&lt;p&gt;One way senior academics can make a difference — as group leaders, supervisors, and grant reviewers — is to give (junior) colleagues the time and incentives to value and practice reproducibility. For instance, supervisors could have all PhD students replicate and extend an existing analysis as part of their initial research. The process of reproducing an existing work will familiarize the student with the common challenges that come with doing good science. The work of reproducing someone else’s work might entail finding and understanding a certain dataset (sometimes difficult to even get access to), as well as the software (e.g. scripts or packages) that was used to produce the results. Running the previous analysis, often on a different computer and at a later time (when software dependencies have likely changed) would check the computational reproducibility of the previous work, and in doing so, be a valuable learning experience for the student.&lt;/p&gt;
&lt;p&gt;Group leaders benefit from reproducible workflows as it prevents (PhD) students from re-writing the same piece of software again and again. While learning the ropes is important for any junior scholar, it is not very efficient if every new generation of students re-writes code for basic operations or frequently used analysis methods.&lt;/p&gt;
&lt;p&gt;In addition to the benefits of an academic career, researchers themselves also increase their employability outside of academia by learning digital skills (such as version control or programming reusable pieces of code) that are valued in many different (industry) jobs.&lt;/p&gt;
&lt;p&gt;In modern science, computational methods are the norm in almost every discipline. Yet attempts at reproducibility are almost always unsuccessful due to missing materials and/or lack of skills. Part of this problem can be mitigated by learning how to produce reproducible code: how to write documentation, perform version control, and manage packages. Doing so will benefit you as a researcher, but also your colleagues, and the wider scientific community, because your (coding) efforts will become reusable. Increasing the use of reproducible workflows is in the interest of many stakeholders in academia — increasing the reproducibility of research is key for a broader change in how we do science.&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amc.nl/web/home.htm&quot;&gt;Amsterdam UMC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.umcg.nl/&quot;&gt;University Medical Center Groningen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.naturalis.nl/en&quot;&gt;Naturalis Biodiversity Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ou.nl/en/home&quot;&gt;Open Universiteit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.universiteitleiden.nl/en&quot;&gt;Universiteit Leiden&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.eur.nl/en/essb&quot;&gt;Erasmus School of Social and Behavioural Sciences&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/why-should-you-care-about-reproducible-c-984b86bd.CiHwM2go.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Variables, Records, Values and Objects</title><link>https://blog.esciencecenter.nl/posts/2024-11-07---variables-records-values-and-objects</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-11-07---variables-records-values-and-objects</guid><description>&lt;p&gt;14&lt;/p&gt;
&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration. (&lt;/em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;&lt;em&gt;TEC1&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;em&gt;&lt;a href=&quot;https://medium.com/escience-center/procedural-programming-f1d8cdef7540&quot;&gt;&lt;em&gt;TEC2&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;-3-variables-records-values-and-objects&quot;&gt;№ 3: Variables, Records, Values and Objects&lt;/h2&gt;
&lt;p&gt;Last time, we talked about the actions taken by scripts, and how they could be organised hierarchically using procedures. This makes it possible to split up a big problem into clearly delineated blocks with well-defined interfaces. These blocks can then be glued together into a hierarchical structure that gets complex things done in a well-organised way.&lt;/p&gt;
&lt;p&gt;However, actions are only one half of the programming equation. Procedures give us verbs, but we’re still missing nouns: data, or state. In Python, and many other languages, data is stored in &lt;em&gt;variables&lt;/em&gt;. Variables connect a name to a memory location holding a value. This connection is created by an &lt;em&gt;assignment&lt;/em&gt;. The statement &lt;code&gt;x = 1&lt;/code&gt; will create a new memory location, associate it with the name &lt;code&gt;x&lt;/code&gt;, and write the number &lt;code&gt;1&lt;/code&gt; in it. Other examples of Python values are the string &lt;code&gt;&quot;The Engineering Corner”&lt;/code&gt; and the boolean value &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Variables, Records, Values and Objects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/variables-records-values-and-objects-ec9ee01b.CmSLy2Cc_ZHJSTb.webp&quot; srcset=&quot;&quot;&gt;
Values spilling out of a variable? Could there be a memory leak? Photo by &lt;a href=&quot;https://unsplash.com/@napender?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Napendra Singh&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Variables can be used in different ways. Often, they store the data that we are processing; after we read it from an input file, halfway through a calculation, and before we write it out again. But we also have variables that are used to control the execution of the script: loop variables, flags that keep track of whether something has happened, and so on. Sometimes, data is used to make decisions as well (“if x is negative, do this, else do that”).&lt;/p&gt;
&lt;p&gt;At any point during its execution, a program has a &lt;em&gt;state&lt;/em&gt;, which is simply the collection of all existing variables, plus an indication of the next statement to execute. Together with any future inputs, this state will determine what the program is going to do. Which branch of an if-statement is taken, how many loops a for-statement executes, it all depends on the state.&lt;/p&gt;
&lt;p&gt;As your script gets bigger it will get more and more variables, until it becomes difficult to keep track of them all. As with the actions, the solution is to organise the variables hierarchically. There are two ways to do that actually, &lt;em&gt;scopes&lt;/em&gt; and &lt;em&gt;records&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scopes&quot;&gt;Scopes&lt;/h3&gt;
&lt;p&gt;Scopes come for free once you start making functions (procedures in &lt;a href=&quot;https://medium.com/escience-center/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2&lt;/a&gt;, we’re switching back to Python terminology here and call them functions). Variables created within a function are &lt;em&gt;local&lt;/em&gt; to that function, which means that they’re only visible to statements inside of the function. In other words, they are &lt;em&gt;in the function’s scope&lt;/em&gt;. Variables that aren’t created within a function are &lt;em&gt;global&lt;/em&gt; variables, and are &lt;em&gt;in the global scope&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, if you make functions, you’ll notice that most of your variables will end up being local variables. In fact, if you design these functions well and have them only communicate with other functions via parameters and return values, then the only global variables you’ll have are at the top level of your Python script. In Python, you &lt;em&gt;can&lt;/em&gt; actually read those global variables from inside a function, but something funny happens if you write to them:&lt;/p&gt;
&lt;p&gt;global_variable = 42&lt;/p&gt;
&lt;p&gt;def my_function() -&gt; None:
print(global_variable) # prints 42
global_variable = 43
print(global_variable) # prints 43&lt;/p&gt;
&lt;p&gt;my_function()&lt;/p&gt;
&lt;p&gt;print(global_variable) # prints 42The way this works is that if you try to use a variable, it is first looked up in the local scope you’re in. If it’s not found there, then the global scope is tried. So the first time &lt;code&gt;global_variable&lt;/code&gt; is read in &lt;code&gt;my_function&lt;/code&gt;, this is what happens. Assignment however is not affected, so on the next line a &lt;em&gt;new&lt;/em&gt; variable is made in the &lt;em&gt;local&lt;/em&gt; scope, which is called &lt;code&gt;global_variable&lt;/code&gt; and given the value 43.&lt;/p&gt;
&lt;p&gt;On the next line, this local variable is found first and its value is printed. Note that the global variable named &lt;code&gt;global_variable&lt;/code&gt; is now invisible from within &lt;code&gt;my_function&lt;/code&gt;, as it is masked or &lt;em&gt;shadowed&lt;/em&gt; by the local variable of the same name. The print statement at the end of the script isn’t in &lt;code&gt;my_function&lt;/code&gt;’s scope, so, it sees the global version of the variable, which still has the value 42.&lt;/p&gt;
&lt;p&gt;Scopes are very, very good to have when you’re making larger programs, because they decouple different parts of the state from each other. If your functions are of a reasonable length, then all the code that can possibly affect a local variable is on your screen at once, and easy to have a picture of in your head. This makes it much easier to reason about the code, something that is very important if you’re writing code that will run on someone else’s computer while you’re not around.&lt;/p&gt;
&lt;p&gt;You can in fact write to a global variable from inside of a function, but you’d have to have some very very good reasons to do so. It’s almost never good design, so I’m not going to tell you how to do it. Instead, let’s talk about records.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Variables, Records, Values and Objects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/variables-records-values-and-objects-56480c6a.GzOIlrrD_ZwEkjh.webp&quot; srcset=&quot;&quot;&gt;
A record record has a record company, catalog number, artist, and title. Photo by &lt;a href=&quot;https://unsplash.com/@rocinante_11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mick Haupt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;records&quot;&gt;Records&lt;/h3&gt;
&lt;p&gt;Sometimes, one variable just isn’t enough to contain all the information you want to store about a particular thing. For example, if you need to keep track of a person, you’ll want to store their name, but maybe also their date of birth, email address, and whatever other properties are of interest to your application. And speaking of dates, those consist of a day, month and year &lt;a href=&quot;#2459&quot;&gt;[0]&lt;/a&gt;. So it seems that some way of grouping multiple variables together would be a useful language feature.&lt;/p&gt;
&lt;p&gt;Fortunately, language designers have come to the same conclusion, and have added records* (Pascal) and &lt;em&gt;structs&lt;/em&gt; (C and C++) to languages. More recent languages like Python tend to have classes instead (more on those in a future instalment), but the closest equivalents in Python would be a &lt;em&gt;dataclass&lt;/em&gt; [1]:&lt;/p&gt;
&lt;p&gt;from dataclass import dataclass&lt;/p&gt;
&lt;p&gt;@dataclass
class Date:
day: int
month: int
year: int&lt;/p&gt;
&lt;p&gt;@dataclass
class Person:
name: str
date_of_birth: DateHere we have a statement that creates a class named &lt;code&gt;Date&lt;/code&gt;, containing &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;month&lt;/code&gt; and &lt;code&gt;year&lt;/code&gt; fields all of type &lt;code&gt;int&lt;/code&gt;. What does that mean? One way of looking at a class or a record is that it is a description of the structure of a certain type of complex values. So here we are saying that any value of type &lt;code&gt;Date&lt;/code&gt; must contain three subvalues with the given names, each of type &lt;code&gt;int&lt;/code&gt;. These subvalues can themselves be complex objects, as we see in class &lt;code&gt;Person&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And so here is a hierarchy again, but a different one than the hierarchy of functions. That one lets us describe complex actions as a combination of simpler actions, while this one lets us describe complex objects as combinations of simpler parts. Together, they make it possible to describe very complex programs in such a way that we can understand them one piece at a time.&lt;/p&gt;
&lt;p&gt;There’s one thing still missing though. A class is just a description of what a particular type of value looks like. In order to actually do something, we need some variables containing such values (they’re often called &lt;em&gt;objects&lt;/em&gt;). Fortunately, Python’s &lt;code&gt;@dataclass&lt;/code&gt; annotation automatically creates a function with the same name as the class, which takes as arguments the values contained in the class, and returns a value containing them [2]. Some code shows it more clearly:&lt;/p&gt;
&lt;p&gt;p = Person(
name=‘Albert Einstein’,
date_of_birth=Date(
day=14, month=3, year=1879))&lt;/p&gt;
&lt;p&gt;p2 = Person(
name=‘Emmy Noether’,
date_of_birth=Date(
day=23, month=3, year=1882))&lt;/p&gt;
&lt;p&gt;p3 = p2
print(p3.date_of_birth.month)Here we create some values of class &lt;code&gt;Person&lt;/code&gt; by calling the correspondingly named function, and assign them to variables. To create a &lt;code&gt;Date&lt;/code&gt;, we have to call that function instead, and pass appropriate arguments.&lt;/p&gt;
&lt;p&gt;Once we have these complex values, we can use them as a whole, like in the assignment &lt;code&gt;p3 = p2&lt;/code&gt;, or we can access some detail inside of them using the &lt;code&gt;.&lt;/code&gt; operator, as in the &lt;code&gt;print&lt;/code&gt; statement. And just like that, we’re talking about complex things like people and calendar dates!&lt;/p&gt;
&lt;p&gt;One more thing before we go. In &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1&lt;/a&gt;, we talked about type annotations, which you can use to specify which types function arguments must have, and what the type of the return value will be. Records and (data)classes are in fact types, and you can use them to annotate functions. So given the above, you can write a function&lt;/p&gt;
&lt;p&gt;def update_date_of_birth(p: Person, d: Date) -&gt; None:
p.date_of_birth = d&lt;/p&gt;
&lt;p&gt;update_date_of_birth(p2, Date(day=23, month=3, year=1982))and have mypy check that it’s being called correctly.&lt;/p&gt;
&lt;p&gt;If you go and play around a bit with this code, you may notice that there’s some really funny business going on when you assign using whole objects and also parts of them. In the next instalment, we’ll take a look behind the scenes to see what’s actually happening inside of the computer when we make variables and complex values, and clear all that up.&lt;/p&gt;
&lt;p&gt;← &lt;a href=&quot;https://blog.esciencecenter.nl/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2: Procedural programming &lt;/a&gt;— TEC 4: &amp;#x3C;Stay tuned!&gt; →&lt;/p&gt;
&lt;p&gt;[0] At least with the calendar system currently used in the western world. There have been many calendar systems over the course of history, it’s a fascinating subject actually. If you’re ever bored, look into it!&lt;/p&gt;
&lt;p&gt;[1] Or a NamedTuple or perhaps even a dict, but a data class is the most straightforward and provides for a good starting point when we talk about classes later.&lt;/p&gt;
&lt;p&gt;[2] It’s actually a bit more complicated than that, more in a future instalment on Object Oriented Programming.&lt;/p&gt;</description><pubDate>Thu, 07 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;14&lt;/p&gt;
&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration. (&lt;/em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;&lt;em&gt;TEC1&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;em&gt;&lt;a href=&quot;https://medium.com/escience-center/procedural-programming-f1d8cdef7540&quot;&gt;&lt;em&gt;TEC2&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;-3-variables-records-values-and-objects&quot;&gt;№ 3: Variables, Records, Values and Objects&lt;/h2&gt;
&lt;p&gt;Last time, we talked about the actions taken by scripts, and how they could be organised hierarchically using procedures. This makes it possible to split up a big problem into clearly delineated blocks with well-defined interfaces. These blocks can then be glued together into a hierarchical structure that gets complex things done in a well-organised way.&lt;/p&gt;
&lt;p&gt;However, actions are only one half of the programming equation. Procedures give us verbs, but we’re still missing nouns: data, or state. In Python, and many other languages, data is stored in &lt;em&gt;variables&lt;/em&gt;. Variables connect a name to a memory location holding a value. This connection is created by an &lt;em&gt;assignment&lt;/em&gt;. The statement &lt;code&gt;x = 1&lt;/code&gt; will create a new memory location, associate it with the name &lt;code&gt;x&lt;/code&gt;, and write the number &lt;code&gt;1&lt;/code&gt; in it. Other examples of Python values are the string &lt;code&gt;&quot;The Engineering Corner”&lt;/code&gt; and the boolean value &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Variables, Records, Values and Objects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/variables-records-values-and-objects-ec9ee01b.CmSLy2Cc_ZHJSTb.webp&quot; srcset=&quot;&quot;&gt;
Values spilling out of a variable? Could there be a memory leak? Photo by &lt;a href=&quot;https://unsplash.com/@napender?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Napendra Singh&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Variables can be used in different ways. Often, they store the data that we are processing; after we read it from an input file, halfway through a calculation, and before we write it out again. But we also have variables that are used to control the execution of the script: loop variables, flags that keep track of whether something has happened, and so on. Sometimes, data is used to make decisions as well (“if x is negative, do this, else do that”).&lt;/p&gt;
&lt;p&gt;At any point during its execution, a program has a &lt;em&gt;state&lt;/em&gt;, which is simply the collection of all existing variables, plus an indication of the next statement to execute. Together with any future inputs, this state will determine what the program is going to do. Which branch of an if-statement is taken, how many loops a for-statement executes, it all depends on the state.&lt;/p&gt;
&lt;p&gt;As your script gets bigger it will get more and more variables, until it becomes difficult to keep track of them all. As with the actions, the solution is to organise the variables hierarchically. There are two ways to do that actually, &lt;em&gt;scopes&lt;/em&gt; and &lt;em&gt;records&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scopes&quot;&gt;Scopes&lt;/h3&gt;
&lt;p&gt;Scopes come for free once you start making functions (procedures in &lt;a href=&quot;https://medium.com/escience-center/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2&lt;/a&gt;, we’re switching back to Python terminology here and call them functions). Variables created within a function are &lt;em&gt;local&lt;/em&gt; to that function, which means that they’re only visible to statements inside of the function. In other words, they are &lt;em&gt;in the function’s scope&lt;/em&gt;. Variables that aren’t created within a function are &lt;em&gt;global&lt;/em&gt; variables, and are &lt;em&gt;in the global scope&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, if you make functions, you’ll notice that most of your variables will end up being local variables. In fact, if you design these functions well and have them only communicate with other functions via parameters and return values, then the only global variables you’ll have are at the top level of your Python script. In Python, you &lt;em&gt;can&lt;/em&gt; actually read those global variables from inside a function, but something funny happens if you write to them:&lt;/p&gt;
&lt;p&gt;global_variable = 42&lt;/p&gt;
&lt;p&gt;def my_function() -&gt; None:
print(global_variable) # prints 42
global_variable = 43
print(global_variable) # prints 43&lt;/p&gt;
&lt;p&gt;my_function()&lt;/p&gt;
&lt;p&gt;print(global_variable) # prints 42The way this works is that if you try to use a variable, it is first looked up in the local scope you’re in. If it’s not found there, then the global scope is tried. So the first time &lt;code&gt;global_variable&lt;/code&gt; is read in &lt;code&gt;my_function&lt;/code&gt;, this is what happens. Assignment however is not affected, so on the next line a &lt;em&gt;new&lt;/em&gt; variable is made in the &lt;em&gt;local&lt;/em&gt; scope, which is called &lt;code&gt;global_variable&lt;/code&gt; and given the value 43.&lt;/p&gt;
&lt;p&gt;On the next line, this local variable is found first and its value is printed. Note that the global variable named &lt;code&gt;global_variable&lt;/code&gt; is now invisible from within &lt;code&gt;my_function&lt;/code&gt;, as it is masked or &lt;em&gt;shadowed&lt;/em&gt; by the local variable of the same name. The print statement at the end of the script isn’t in &lt;code&gt;my_function&lt;/code&gt;’s scope, so, it sees the global version of the variable, which still has the value 42.&lt;/p&gt;
&lt;p&gt;Scopes are very, very good to have when you’re making larger programs, because they decouple different parts of the state from each other. If your functions are of a reasonable length, then all the code that can possibly affect a local variable is on your screen at once, and easy to have a picture of in your head. This makes it much easier to reason about the code, something that is very important if you’re writing code that will run on someone else’s computer while you’re not around.&lt;/p&gt;
&lt;p&gt;You can in fact write to a global variable from inside of a function, but you’d have to have some very very good reasons to do so. It’s almost never good design, so I’m not going to tell you how to do it. Instead, let’s talk about records.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Variables, Records, Values and Objects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/variables-records-values-and-objects-56480c6a.GzOIlrrD_ZwEkjh.webp&quot; srcset=&quot;&quot;&gt;
A record record has a record company, catalog number, artist, and title. Photo by &lt;a href=&quot;https://unsplash.com/@rocinante_11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mick Haupt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;records&quot;&gt;Records&lt;/h3&gt;
&lt;p&gt;Sometimes, one variable just isn’t enough to contain all the information you want to store about a particular thing. For example, if you need to keep track of a person, you’ll want to store their name, but maybe also their date of birth, email address, and whatever other properties are of interest to your application. And speaking of dates, those consist of a day, month and year &lt;a href=&quot;#2459&quot;&gt;[0]&lt;/a&gt;. So it seems that some way of grouping multiple variables together would be a useful language feature.&lt;/p&gt;
&lt;p&gt;Fortunately, language designers have come to the same conclusion, and have added records* (Pascal) and &lt;em&gt;structs&lt;/em&gt; (C and C++) to languages. More recent languages like Python tend to have classes instead (more on those in a future instalment), but the closest equivalents in Python would be a &lt;em&gt;dataclass&lt;/em&gt; [1]:&lt;/p&gt;
&lt;p&gt;from dataclass import dataclass&lt;/p&gt;
&lt;p&gt;@dataclass
class Date:
day: int
month: int
year: int&lt;/p&gt;
&lt;p&gt;@dataclass
class Person:
name: str
date_of_birth: DateHere we have a statement that creates a class named &lt;code&gt;Date&lt;/code&gt;, containing &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;month&lt;/code&gt; and &lt;code&gt;year&lt;/code&gt; fields all of type &lt;code&gt;int&lt;/code&gt;. What does that mean? One way of looking at a class or a record is that it is a description of the structure of a certain type of complex values. So here we are saying that any value of type &lt;code&gt;Date&lt;/code&gt; must contain three subvalues with the given names, each of type &lt;code&gt;int&lt;/code&gt;. These subvalues can themselves be complex objects, as we see in class &lt;code&gt;Person&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And so here is a hierarchy again, but a different one than the hierarchy of functions. That one lets us describe complex actions as a combination of simpler actions, while this one lets us describe complex objects as combinations of simpler parts. Together, they make it possible to describe very complex programs in such a way that we can understand them one piece at a time.&lt;/p&gt;
&lt;p&gt;There’s one thing still missing though. A class is just a description of what a particular type of value looks like. In order to actually do something, we need some variables containing such values (they’re often called &lt;em&gt;objects&lt;/em&gt;). Fortunately, Python’s &lt;code&gt;@dataclass&lt;/code&gt; annotation automatically creates a function with the same name as the class, which takes as arguments the values contained in the class, and returns a value containing them [2]. Some code shows it more clearly:&lt;/p&gt;
&lt;p&gt;p = Person(
name=‘Albert Einstein’,
date_of_birth=Date(
day=14, month=3, year=1879))&lt;/p&gt;
&lt;p&gt;p2 = Person(
name=‘Emmy Noether’,
date_of_birth=Date(
day=23, month=3, year=1882))&lt;/p&gt;
&lt;p&gt;p3 = p2
print(p3.date_of_birth.month)Here we create some values of class &lt;code&gt;Person&lt;/code&gt; by calling the correspondingly named function, and assign them to variables. To create a &lt;code&gt;Date&lt;/code&gt;, we have to call that function instead, and pass appropriate arguments.&lt;/p&gt;
&lt;p&gt;Once we have these complex values, we can use them as a whole, like in the assignment &lt;code&gt;p3 = p2&lt;/code&gt;, or we can access some detail inside of them using the &lt;code&gt;.&lt;/code&gt; operator, as in the &lt;code&gt;print&lt;/code&gt; statement. And just like that, we’re talking about complex things like people and calendar dates!&lt;/p&gt;
&lt;p&gt;One more thing before we go. In &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1&lt;/a&gt;, we talked about type annotations, which you can use to specify which types function arguments must have, and what the type of the return value will be. Records and (data)classes are in fact types, and you can use them to annotate functions. So given the above, you can write a function&lt;/p&gt;
&lt;p&gt;def update_date_of_birth(p: Person, d: Date) -&gt; None:
p.date_of_birth = d&lt;/p&gt;
&lt;p&gt;update_date_of_birth(p2, Date(day=23, month=3, year=1982))and have mypy check that it’s being called correctly.&lt;/p&gt;
&lt;p&gt;If you go and play around a bit with this code, you may notice that there’s some really funny business going on when you assign using whole objects and also parts of them. In the next instalment, we’ll take a look behind the scenes to see what’s actually happening inside of the computer when we make variables and complex values, and clear all that up.&lt;/p&gt;
&lt;p&gt;← &lt;a href=&quot;https://blog.esciencecenter.nl/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2: Procedural programming &lt;/a&gt;— TEC 4: &amp;#x3C;Stay tuned!&gt; →&lt;/p&gt;
&lt;p&gt;[0] At least with the calendar system currently used in the western world. There have been many calendar systems over the course of history, it’s a fascinating subject actually. If you’re ever bored, look into it!&lt;/p&gt;
&lt;p&gt;[1] Or a NamedTuple or perhaps even a dict, but a data class is the most straightforward and provides for a good starting point when we talk about classes later.&lt;/p&gt;
&lt;p&gt;[2] It’s actually a bit more complicated than that, more in a future instalment on Object Oriented Programming.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/variables-records-values-and-objects-ec9ee01b.CmSLy2Cc.jpg" medium="image"/><author>Lourens Veen</author></item><item><title>Beyond research</title><link>https://blog.esciencecenter.nl/posts/2024-10-30---beyond-research</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-10-30---beyond-research</guid><description>&lt;h1 id=&quot;beyond-research&quot;&gt;&lt;strong&gt;Beyond research&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;‘Beyond research’ is a new mini-series we are starting on the eScience Center blog. We want to give you some insight into the interests, hobbies and accomplishments of our colleagues. Learn more about the writers behind our blogs and get to know them beyond the research. This first post features &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#41d4&quot;&gt;Walter Baccinelli&lt;/a&gt;, &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#0155&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#4a75&quot;&gt;Olga Lyashevska&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Walter Baccinelli: wrestling and words of wisdom**&lt;/p&gt;
&lt;p&gt;I started my path in martial arts a long time ago when I was six and had no pain in my joints. I would love, at this point, to tell an inspiring and moving story about how I found my way to the dojo and “the gentle way” (aka, Judo), but I have none. The truth is that my older sister was already practicing Judo and the gym was close by, so I joined in. It was very convenient. What is incredible is that I never left this amazing world. Judo has been my first love and a very important part of my life, but I’ve been exploring, with more or less commitment, other disciplines like Sambo, Muay Thay, Wrestling, Kung Fu, as well as traditional fighting like Shuai Jiao and Qazaq Kuresi.&lt;/p&gt;
&lt;p&gt;Since I began practicing martial arts, there have been many moments that I am proud of and that have impacted me. I started competing for fun as a kid, and more seriously as a teenager and into adulthood. I had the chance to take part in countless competitions at different levels, from very fun amateur to European and World championships and, very recently, the &lt;a href=&quot;https://worldnomadgames.kz/en&quot;&gt;World Nomad Games&lt;/a&gt; as part of the Italian national team. Regardless of the level of the competition, stepping on the mat always takes a lot of courage, and I’m proud of myself every time I decide to put on my Gi (Judo uniform) and challenge myself by fighting. Even before the fight itself, the path is hard and it takes commitment, self-sacrifice, passion and a bit of craziness. It requires constant training, always pushing yourself to your limit. It requires suffering through the fatigue and, sometimes, the injuries. It requires adjusting your whole lifestyle, fasting and resting instead of partying. It requires being ready to win, but, even more, being ready to lose despite all the work.&lt;/p&gt;
&lt;p&gt;This may sounds like an awful life. Why would any sane person consciously decide to do this? Well, it also comes with joy. Firstly, it gives you the awareness that you have what it takes to reach the goals that you set, and some self-awareness never hurts. Secondly, reaching those goals is extremely satisfying. Entering the arena wearing the colors of your nation, hearing the cheering of your teammates and winning an important medal. That’s priceless.&lt;/p&gt;
&lt;p&gt;It is clear that sport, for me, was not just a hobby or a complementary part of my life, but a totalizing activity and a way of living. Having had the privilege of experiencing the athlete’s life shaped my character and taught me a lot of lessons largely applicable to my private and work life. And no, I’m not speaking only about how to correctly punch the keyboard when a test fails with my code. Martial arts has taught me the immense value of respect. Respect for the people you train with, your teammates but even more for your opponent. I learned that an opponent is not an enemy. I learned that I cannot achieve my goals without the support of other people and that my support is fundamental for other people to reach their own goals. In Judo, you cannot train alone and you and your “Uke” (sparring partner) need each other to improve together. It’s all about collaboration and learning from other people. I learned that the higher my goals are, the harder the route to fulfill them. Failure and frustration (as well as accepting these emotions) are a part of the process, and commitment, hard work and patience (and sometimes also a bit of luck) are the tools with which I must be equipped.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-1f31515b.pyM2re2S_2drxV8.webp&quot; srcset=&quot;&quot;&gt;
Walter during the World Nomad Games&lt;a href=&quot;#0155&quot;&gt;&lt;strong&gt;Carlos Martinez-Ortiz: Kendo and committing to curiosity&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I started kendo a few years ago. One of my friends had started a few weeks before and it sounded like a fun thing to do, so I joined him. A few months later, my friend stopped, because he started doing something else, but I just liked it enough to stay. Initially, I really liked the external part of it: it is very dynamic, and explosive — lots of shouting and running around. You get to wear cool armour and feel like a samurai. But over time there were other aspects that I enjoyed more — the aspect of long-term improvement and leaving the rest of the world outside when I practice.&lt;/p&gt;
&lt;p&gt;I think kendo for me has shown me some aspects of my own character.&lt;/p&gt;
&lt;p&gt;A couple of years ago, when I was preparing for a kendo exam, one of my seniors gave me some feedback on things I should improve — not only in terms of technique but also in terms of my attitude. Around the same time, I had my yearly appraisal with my line manager, and his feedback was very similar. From my perspective, what I needed to learn in kendo was the same thing I needed to learn for my personal development.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-79ee2d04.89kj2-n0_Z1Yjz3k.webp&quot; srcset=&quot;&quot;&gt;
Olga Lyashevska: my Jiu-jitsu journey**&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is not about how good you get but about what you do for the community — *Carlson Gracie Jr.&lt;/p&gt;
&lt;p&gt;My jiu-jitsu journey began back in 2005 when I was at university. One day, I noticed a group of students running around in what looked like white pajamas, jumping, rolling, and clearly having fun. Intrigued, I decided to check it out since I had some free time that week.&lt;/p&gt;
&lt;p&gt;When I arrived at the gym, I figured I’d just sit back and watch a session, but to my surprise, I wasn’t allowed. “You’ve got to join in,” the teacher said. So, without much hesitation, I grabbed one of those white ‘pajamas,’ which I later learned was called a &lt;em&gt;gi&lt;/em&gt;, and picked out a random belt from a box in the corner.&lt;/p&gt;
&lt;p&gt;The class started, and we jumped right into running, tumbling, and falling all over the mats. I had no clue what I was doing. At some point, the teacher noticed the belt I had tied around my waist — it was one meant for higher-ranked students. He looked at me with a puzzled expression and asked, “What belt are you?” I hadn’t the slightest idea what to say because I hadn’t earned any belt yet, let alone the one I was wearing. It was awkward and funny, but at that moment something kickstarted in me.&lt;/p&gt;
&lt;p&gt;From that day forward, I never stopped training. Jiu -itsu became much more than just a hobby — it transformed how I approached challenges, relationships and ultimately, how I saw myself. What started as an accidental introduction became a lifelong passion that continues to shape who I am today.&lt;/p&gt;
&lt;p&gt;As time passed, my training intensified. I found myself training up to six days a week, balancing my time between judo and jiu-jitsu, and competing and refereeing in both disciplines. Along the way, I’ve had many moments I’m proud of — from winning the World and European Championships to refereeing big competitions with some of the best competitors in the world.&lt;/p&gt;
&lt;p&gt;But as much as those achievements mean to me, they pale in comparison to the joy of watching my students grow. There’s nothing quite like seeing the transformation in people. I’ve seen shy individuals blossom into confident athletes, not only excelling on the mats but also gaining a new sense of self. I’ve worked with women who’ve faced difficult challenges, and through jiu-jitsu, they’ve found strength, empowerment and a community that supports them.&lt;/p&gt;
&lt;p&gt;Recently, one such moment after a women-only jiu-jitsu class I teach in Amsterdam, as students left with smiles and a sense of accomplishment, my teacher hugged me and whispered, “you’re changing lives.”&lt;/p&gt;
&lt;p&gt;I will be competing again, and the medals and titles are great, but the real reward comes from knowing that, through jiu-jitsu, I’ve been able to help others discover their own power and confidence.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-23e5eec1.CnsubD7U_1FQ9Gy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;</description><pubDate>Wed, 30 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;beyond-research&quot;&gt;&lt;strong&gt;Beyond research&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;‘Beyond research’ is a new mini-series we are starting on the eScience Center blog. We want to give you some insight into the interests, hobbies and accomplishments of our colleagues. Learn more about the writers behind our blogs and get to know them beyond the research. This first post features &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#41d4&quot;&gt;Walter Baccinelli&lt;/a&gt;, &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#0155&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://blog.esciencecenter.nl/beyond-research-e220eb18f8b4#4a75&quot;&gt;Olga Lyashevska&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Walter Baccinelli: wrestling and words of wisdom**&lt;/p&gt;
&lt;p&gt;I started my path in martial arts a long time ago when I was six and had no pain in my joints. I would love, at this point, to tell an inspiring and moving story about how I found my way to the dojo and “the gentle way” (aka, Judo), but I have none. The truth is that my older sister was already practicing Judo and the gym was close by, so I joined in. It was very convenient. What is incredible is that I never left this amazing world. Judo has been my first love and a very important part of my life, but I’ve been exploring, with more or less commitment, other disciplines like Sambo, Muay Thay, Wrestling, Kung Fu, as well as traditional fighting like Shuai Jiao and Qazaq Kuresi.&lt;/p&gt;
&lt;p&gt;Since I began practicing martial arts, there have been many moments that I am proud of and that have impacted me. I started competing for fun as a kid, and more seriously as a teenager and into adulthood. I had the chance to take part in countless competitions at different levels, from very fun amateur to European and World championships and, very recently, the &lt;a href=&quot;https://worldnomadgames.kz/en&quot;&gt;World Nomad Games&lt;/a&gt; as part of the Italian national team. Regardless of the level of the competition, stepping on the mat always takes a lot of courage, and I’m proud of myself every time I decide to put on my Gi (Judo uniform) and challenge myself by fighting. Even before the fight itself, the path is hard and it takes commitment, self-sacrifice, passion and a bit of craziness. It requires constant training, always pushing yourself to your limit. It requires suffering through the fatigue and, sometimes, the injuries. It requires adjusting your whole lifestyle, fasting and resting instead of partying. It requires being ready to win, but, even more, being ready to lose despite all the work.&lt;/p&gt;
&lt;p&gt;This may sounds like an awful life. Why would any sane person consciously decide to do this? Well, it also comes with joy. Firstly, it gives you the awareness that you have what it takes to reach the goals that you set, and some self-awareness never hurts. Secondly, reaching those goals is extremely satisfying. Entering the arena wearing the colors of your nation, hearing the cheering of your teammates and winning an important medal. That’s priceless.&lt;/p&gt;
&lt;p&gt;It is clear that sport, for me, was not just a hobby or a complementary part of my life, but a totalizing activity and a way of living. Having had the privilege of experiencing the athlete’s life shaped my character and taught me a lot of lessons largely applicable to my private and work life. And no, I’m not speaking only about how to correctly punch the keyboard when a test fails with my code. Martial arts has taught me the immense value of respect. Respect for the people you train with, your teammates but even more for your opponent. I learned that an opponent is not an enemy. I learned that I cannot achieve my goals without the support of other people and that my support is fundamental for other people to reach their own goals. In Judo, you cannot train alone and you and your “Uke” (sparring partner) need each other to improve together. It’s all about collaboration and learning from other people. I learned that the higher my goals are, the harder the route to fulfill them. Failure and frustration (as well as accepting these emotions) are a part of the process, and commitment, hard work and patience (and sometimes also a bit of luck) are the tools with which I must be equipped.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;465&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-1f31515b.pyM2re2S_2drxV8.webp&quot; srcset=&quot;&quot;&gt;
Walter during the World Nomad Games&lt;a href=&quot;#0155&quot;&gt;&lt;strong&gt;Carlos Martinez-Ortiz: Kendo and committing to curiosity&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I started kendo a few years ago. One of my friends had started a few weeks before and it sounded like a fun thing to do, so I joined him. A few months later, my friend stopped, because he started doing something else, but I just liked it enough to stay. Initially, I really liked the external part of it: it is very dynamic, and explosive — lots of shouting and running around. You get to wear cool armour and feel like a samurai. But over time there were other aspects that I enjoyed more — the aspect of long-term improvement and leaving the rest of the world outside when I practice.&lt;/p&gt;
&lt;p&gt;I think kendo for me has shown me some aspects of my own character.&lt;/p&gt;
&lt;p&gt;A couple of years ago, when I was preparing for a kendo exam, one of my seniors gave me some feedback on things I should improve — not only in terms of technique but also in terms of my attitude. Around the same time, I had my yearly appraisal with my line manager, and his feedback was very similar. From my perspective, what I needed to learn in kendo was the same thing I needed to learn for my personal development.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-79ee2d04.89kj2-n0_Z1Yjz3k.webp&quot; srcset=&quot;&quot;&gt;
Olga Lyashevska: my Jiu-jitsu journey**&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is not about how good you get but about what you do for the community — *Carlson Gracie Jr.&lt;/p&gt;
&lt;p&gt;My jiu-jitsu journey began back in 2005 when I was at university. One day, I noticed a group of students running around in what looked like white pajamas, jumping, rolling, and clearly having fun. Intrigued, I decided to check it out since I had some free time that week.&lt;/p&gt;
&lt;p&gt;When I arrived at the gym, I figured I’d just sit back and watch a session, but to my surprise, I wasn’t allowed. “You’ve got to join in,” the teacher said. So, without much hesitation, I grabbed one of those white ‘pajamas,’ which I later learned was called a &lt;em&gt;gi&lt;/em&gt;, and picked out a random belt from a box in the corner.&lt;/p&gt;
&lt;p&gt;The class started, and we jumped right into running, tumbling, and falling all over the mats. I had no clue what I was doing. At some point, the teacher noticed the belt I had tied around my waist — it was one meant for higher-ranked students. He looked at me with a puzzled expression and asked, “What belt are you?” I hadn’t the slightest idea what to say because I hadn’t earned any belt yet, let alone the one I was wearing. It was awkward and funny, but at that moment something kickstarted in me.&lt;/p&gt;
&lt;p&gt;From that day forward, I never stopped training. Jiu -itsu became much more than just a hobby — it transformed how I approached challenges, relationships and ultimately, how I saw myself. What started as an accidental introduction became a lifelong passion that continues to shape who I am today.&lt;/p&gt;
&lt;p&gt;As time passed, my training intensified. I found myself training up to six days a week, balancing my time between judo and jiu-jitsu, and competing and refereeing in both disciplines. Along the way, I’ve had many moments I’m proud of — from winning the World and European Championships to refereeing big competitions with some of the best competitors in the world.&lt;/p&gt;
&lt;p&gt;But as much as those achievements mean to me, they pale in comparison to the joy of watching my students grow. There’s nothing quite like seeing the transformation in people. I’ve seen shy individuals blossom into confident athletes, not only excelling on the mats but also gaining a new sense of self. I’ve worked with women who’ve faced difficult challenges, and through jiu-jitsu, they’ve found strength, empowerment and a community that supports them.&lt;/p&gt;
&lt;p&gt;Recently, one such moment after a women-only jiu-jitsu class I teach in Amsterdam, as students left with smiles and a sense of accomplishment, my teacher hugged me and whispered, “you’re changing lives.”&lt;/p&gt;
&lt;p&gt;I will be competing again, and the medals and titles are great, but the real reward comes from knowing that, through jiu-jitsu, I’ve been able to help others discover their own power and confidence.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Beyond research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/beyond-research-23e5eec1.CnsubD7U_1FQ9Gy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/beyond-research-1f31515b.pyM2re2S.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>From Corridor Coincidences to Cellular Cartography: The grlc Story</title><link>https://blog.esciencecenter.nl/posts/2024-10-24---from-corridor-coincidences-to-cellular-cartography-the-grlc-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-10-24---from-corridor-coincidences-to-cellular-cartography-the-grlc-</guid><description>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;This is the story of &lt;a href=&quot;https://grlc.io/&quot;&gt;grlc&lt;/a&gt;, a tool that transforms complex linked data queries into user-friendly web interfaces. We interviewed grlc’s developers &lt;a href=&quot;https://github.com/albertmeronyo&quot;&gt;Albert Meroño-Peñuela&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt;, to explore grlc’s origins, development, and real-world impact. We’ll also hear from &lt;a href=&quot;https://github.com/bherr2&quot;&gt;Bruce Herr&lt;/a&gt;, a user from the &lt;a href=&quot;https://hubmapconsortium.org/&quot;&gt;HuBMAP&lt;/a&gt; software project who’s putting grlc to work in groundbreaking research. The story is a testament to the power of open-source collaboration and the unexpected journeys of software tools.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;515&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-cec5731c.3PE2AEFD_Z1FoTLM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steverichey?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Richey&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;part-1-in-conversation-with-grlc-developers&quot;&gt;Part 1: In Conversation with grlc Developers&lt;/h2&gt;
&lt;h3 id=&quot;q-lets-start-at-the-beginning-what-exactly-is-grlc-and-what-problem-does-it-solve-for-its-users&quot;&gt;Q: Let’s start at the beginning. What exactly is grlc, and what problem does it solve for its users?&lt;/h3&gt;
&lt;p&gt;Albert: grlc is a server that automates the publication of knowledge graph APIs. It takes SPARQL queries as input and generates a functional Open API specification without requiring any coding.&lt;/p&gt;
&lt;p&gt;Imagine you have a collection of linked data about music bands that you want to share with music enthusiasts who don’t know SPARQL. With grlc, you can write a SPARQL query to retrieve band information, put it on GitHub, and grlc will create an API that allows users to access this data using a simple URL. Users can even modify parameters in the URL to get information about different bands, effectively exploring your data without needing to understand the complexities of SPARQL.&lt;/p&gt;
&lt;p&gt;Here is a traditional SPARQL query for a linked dataset:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;598&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-2002d6ee.BSc4dvJ9_nDC9.webp&quot; srcset=&quot;&quot;&gt;
A traditional (complicated) SPARQL query without using grlcIf you are a researcher only interested in music genres, you may not have the time or energy to learn SPARQL. grlc makes it easy to do the same thing:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;581&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-5b2851f8.Bupe_3-B_1NF95P.webp&quot; srcset=&quot;&quot;&gt;
The grlc generated API for the same query displayed aboveThe output of this is a URL, through which you can view and download the data you are after:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;496&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-cc5687e2.BAA3ciX7_Z1cAtJu.webp&quot; srcset=&quot;&quot;&gt;
The URL that grlc generated through which you can access the data. You can view this data in your browser, but you can also use your favourite programming language to fetch and analyse data from different genres&lt;/p&gt;
&lt;h3 id=&quot;q-thats-quite-useful-how-did-the-idea-for-grlc-come-about&quot;&gt;Q: That’s quite useful. How did the idea for grlc come about?&lt;/h3&gt;
&lt;p&gt;Albert: The story of grlc begins in 2016. The original contributors were developers who frequently found themselves creating Open API specifications for SPARQL endpoints. Like many programmers, they were looking for ways to automate this repetitive task.&lt;/p&gt;
&lt;p&gt;While some tools existed at the time, they all had limitations — either requiring SPARQL queries to be buried in a database or failing to comply with the emerging Open API specification (then known as Swagger). Faced with these constraints, they decided to build a better solution themselves. This solution ended up becoming grlc.&lt;/p&gt;
&lt;h3 id=&quot;q-how-did-the-escience-center-play-a-role-in-the-development-of-grlc&quot;&gt;Q: How did the eScience Center play a role in the development of grlc?&lt;/h3&gt;
&lt;p&gt;Carlos: I was an eScience Center RSE at the time (now Community Manager, ed.), working on a digital humanities project, building a linked data exploration tool. The other team members on that project had diverse expertise, so they needed a way to separate concerns — front-end developers shouldn’t need to know about data storage, and data specialists shouldn’t have to worry about front-end presentation.&lt;/p&gt;
&lt;p&gt;That’s when I discovered grlc. Albert, the original grlc developer was coincidentally working just down the hall, but we had never met. I started contributing to improve the codebase, bridging the gap between our two teams.&lt;/p&gt;
&lt;p&gt;After that project concluded, another colleague at the eScience Center began &lt;a href=&quot;https://research-software-directory.org/projects/candygene&quot;&gt;candYgene&lt;/a&gt;: a life sciences project using linked data. I suggested using grlc, and as they reported issues and suggested improvements, we kept enhancing the tool. It’s been a rewarding cycle of continuous improvement driven by real-world use cases.&lt;/p&gt;
&lt;h3 id=&quot;q-its-fascinating-to-see-how-tools-evolve-in-practice-how-is-grlc-being-used-now-and-how-do-you-track-its-adoption&quot;&gt;Q: It’s fascinating to see how tools evolve in practice. How is grlc being used now, and how do you track its adoption?&lt;/h3&gt;
&lt;p&gt;Carlos: One of the exciting aspects of open-source development is seeing your creation take on a life of its own. We often discover new use cases when users report issues or reach out for support.&lt;/p&gt;
&lt;p&gt;A particularly interesting example is &lt;a href=&quot;https://hubmapconsortium.org&quot;&gt;HuBMAP&lt;/a&gt; (the Human Biomolecular Atlas Program) using grlc in their groundbreaking work. It’s rewarding to see our tool contributing to such important scientific endeavors, especially ones we never anticipated when we first started development.&lt;/p&gt;
&lt;h2 id=&quot;part-2-grlc-in-action--a-conversation-with-a-hubmap-user&quot;&gt;Part 2: grlc in Action — A Conversation with a HuBMAP User&lt;/h2&gt;
&lt;h3 id=&quot;q-can-you-tell-us-a-bit-about-what-hubmap-is-and-what-youre-working-on&quot;&gt;Q: Can you tell us a bit about what HuBMAP is and what you’re working on?&lt;/h3&gt;
&lt;p&gt;Bruce: &lt;a href=&quot;https://hubmapconsortium.org&quot;&gt;HuBMAP&lt;/a&gt;, or the Human Biomolecular Atlas Program, is an NIH-funded consortium with an ambitious goal: building a comprehensive map of the human body at the cellular level.&lt;/p&gt;
&lt;p&gt;I’m part of the &lt;a href=&quot;https://cns.iu.edu&quot;&gt;Indiana University&lt;/a&gt; Mapping Component, where we’re creating the &lt;a href=&quot;https://humanatlas.io/&quot;&gt;Human Reference Atlas&lt;/a&gt; (HRA). It’s a fascinating project that combines ontologies, expert-curated data (including 2D and 3D anatomical imagery), and experimental data from various providers. The end result is an interconnected map of the human body that’s opening new frontiers in biomedical research.&lt;/p&gt;
&lt;h3 id=&quot;q-that-sounds-like-complex-and-important-work-how-does-grlc-fit-into-this-picture&quot;&gt;Q: That sounds like complex and important work. How does grlc fit into this picture?&lt;/h3&gt;
&lt;p&gt;Bruce: grlc has become an important tool for us. The HRA is built as a &lt;a href=&quot;https://lod.humanatlas.io/&quot;&gt;set of RDF graphs&lt;/a&gt;, which allows us to represent complex relationships in our data. However, we often get requests for specific data from researchers who may not be familiar with SPARQL or RDF.&lt;/p&gt;
&lt;p&gt;This is where grlc comes in handy. We can write a SPARQL query to extract the requested data, and grlc transforms that into a user-friendly interface and API. It’s accessible to both programmers and non-programmers, which is crucial given the diverse backgrounds of our collaborators and data users.&lt;/p&gt;
&lt;h3 id=&quot;q-so-grlc-is-bridging-the-gap-between-your-complex-data-structure-and-the-end-users-who-need-that-data-what-specific-capabilities-has-grlc-unlocked-for-your-team&quot;&gt;Q: So grlc is bridging the gap between your complex data structure and the end-users who need that data. What specific capabilities has grlc unlocked for your team?&lt;/h3&gt;
&lt;p&gt;Bruce: The key advantage is that grlc allows us to maintain our data in a rich, expressive format (RDF) while still providing straightforward reports and interfaces for our end users. It’s lowered the barrier for getting derived data products out to folks who need them.&lt;/p&gt;
&lt;p&gt;Before grlc, there was often a tension between having a powerful, flexible data structure and providing easy access to that data. grlc helps resolve that tension. We can focus on creating comprehensive RDF graphs and writing powerful SPARQL queries and be confident that we can easily share the results with collaborators who might not have the same technical background.&lt;/p&gt;
&lt;h3 id=&quot;q-how-did-you-first-discover-grlc&quot;&gt;Q: How did you first discover grlc?&lt;/h3&gt;
&lt;p&gt;Bruce: It was actually through a collaboration. Around 2022, we were working with EBI (European Bioinformatics Institute), one of our partners. We noticed they were using this tool called grlc for their Ubergraph project. At the time, we had our own SPARQL server and were looking for better ways to share queries and data. After seeing how effectively EBI was using grlc, we decided to &lt;a href=&quot;https://github.com/hubmapconsortium/ccf-grlc/&quot;&gt;give it a try&lt;/a&gt;. Now we’re using it for sharing queries and data in our CCF (Common Coordinate Framework) project.&lt;/p&gt;
&lt;h3 id=&quot;q-looking-ahead-do-you-see-the-sustainability-of-tools-like-grlc-as-a-potential-consideration-for-large-scale-projects-like-hubmap&quot;&gt;Q: Looking ahead, do you see the &lt;a href=&quot;https://xkcd.com/2347/&quot;&gt;sustainability&lt;/a&gt; of tools like grlc as a potential consideration for large-scale projects like HuBMAP?&lt;/h3&gt;
&lt;p&gt;Bruce : It’s definitely something we think about. The continued development and maintenance of grlc is valuable to HuBMAP and the HRA project. While we could theoretically pivot to another technology if needed, grlc has become an important part of our workflow.&lt;/p&gt;
&lt;p&gt;It’s a good example of how open-source tools can become key components of scientific projects. We appreciate the work the grlc team has done and continues to do. Their efforts are helping to advance not just our project, but potentially many others in the scientific community.&lt;/p&gt;
&lt;p&gt;Interview by Lieke de Boer*&lt;/p&gt;</description><pubDate>Thu, 24 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;This is the story of &lt;a href=&quot;https://grlc.io/&quot;&gt;grlc&lt;/a&gt;, a tool that transforms complex linked data queries into user-friendly web interfaces. We interviewed grlc’s developers &lt;a href=&quot;https://github.com/albertmeronyo&quot;&gt;Albert Meroño-Peñuela&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt;, to explore grlc’s origins, development, and real-world impact. We’ll also hear from &lt;a href=&quot;https://github.com/bherr2&quot;&gt;Bruce Herr&lt;/a&gt;, a user from the &lt;a href=&quot;https://hubmapconsortium.org/&quot;&gt;HuBMAP&lt;/a&gt; software project who’s putting grlc to work in groundbreaking research. The story is a testament to the power of open-source collaboration and the unexpected journeys of software tools.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;515&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-cec5731c.3PE2AEFD_Z1FoTLM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steverichey?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Richey&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;part-1-in-conversation-with-grlc-developers&quot;&gt;Part 1: In Conversation with grlc Developers&lt;/h2&gt;
&lt;h3 id=&quot;q-lets-start-at-the-beginning-what-exactly-is-grlc-and-what-problem-does-it-solve-for-its-users&quot;&gt;Q: Let’s start at the beginning. What exactly is grlc, and what problem does it solve for its users?&lt;/h3&gt;
&lt;p&gt;Albert: grlc is a server that automates the publication of knowledge graph APIs. It takes SPARQL queries as input and generates a functional Open API specification without requiring any coding.&lt;/p&gt;
&lt;p&gt;Imagine you have a collection of linked data about music bands that you want to share with music enthusiasts who don’t know SPARQL. With grlc, you can write a SPARQL query to retrieve band information, put it on GitHub, and grlc will create an API that allows users to access this data using a simple URL. Users can even modify parameters in the URL to get information about different bands, effectively exploring your data without needing to understand the complexities of SPARQL.&lt;/p&gt;
&lt;p&gt;Here is a traditional SPARQL query for a linked dataset:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;598&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-2002d6ee.BSc4dvJ9_nDC9.webp&quot; srcset=&quot;&quot;&gt;
A traditional (complicated) SPARQL query without using grlcIf you are a researcher only interested in music genres, you may not have the time or energy to learn SPARQL. grlc makes it easy to do the same thing:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;581&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-5b2851f8.Bupe_3-B_1NF95P.webp&quot; srcset=&quot;&quot;&gt;
The grlc generated API for the same query displayed aboveThe output of this is a URL, through which you can view and download the data you are after:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;From Corridor Coincidences to Cellular Cartography: The grlc Story&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;496&quot; src=&quot;https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-cc5687e2.BAA3ciX7_Z1cAtJu.webp&quot; srcset=&quot;&quot;&gt;
The URL that grlc generated through which you can access the data. You can view this data in your browser, but you can also use your favourite programming language to fetch and analyse data from different genres&lt;/p&gt;
&lt;h3 id=&quot;q-thats-quite-useful-how-did-the-idea-for-grlc-come-about&quot;&gt;Q: That’s quite useful. How did the idea for grlc come about?&lt;/h3&gt;
&lt;p&gt;Albert: The story of grlc begins in 2016. The original contributors were developers who frequently found themselves creating Open API specifications for SPARQL endpoints. Like many programmers, they were looking for ways to automate this repetitive task.&lt;/p&gt;
&lt;p&gt;While some tools existed at the time, they all had limitations — either requiring SPARQL queries to be buried in a database or failing to comply with the emerging Open API specification (then known as Swagger). Faced with these constraints, they decided to build a better solution themselves. This solution ended up becoming grlc.&lt;/p&gt;
&lt;h3 id=&quot;q-how-did-the-escience-center-play-a-role-in-the-development-of-grlc&quot;&gt;Q: How did the eScience Center play a role in the development of grlc?&lt;/h3&gt;
&lt;p&gt;Carlos: I was an eScience Center RSE at the time (now Community Manager, ed.), working on a digital humanities project, building a linked data exploration tool. The other team members on that project had diverse expertise, so they needed a way to separate concerns — front-end developers shouldn’t need to know about data storage, and data specialists shouldn’t have to worry about front-end presentation.&lt;/p&gt;
&lt;p&gt;That’s when I discovered grlc. Albert, the original grlc developer was coincidentally working just down the hall, but we had never met. I started contributing to improve the codebase, bridging the gap between our two teams.&lt;/p&gt;
&lt;p&gt;After that project concluded, another colleague at the eScience Center began &lt;a href=&quot;https://research-software-directory.org/projects/candygene&quot;&gt;candYgene&lt;/a&gt;: a life sciences project using linked data. I suggested using grlc, and as they reported issues and suggested improvements, we kept enhancing the tool. It’s been a rewarding cycle of continuous improvement driven by real-world use cases.&lt;/p&gt;
&lt;h3 id=&quot;q-its-fascinating-to-see-how-tools-evolve-in-practice-how-is-grlc-being-used-now-and-how-do-you-track-its-adoption&quot;&gt;Q: It’s fascinating to see how tools evolve in practice. How is grlc being used now, and how do you track its adoption?&lt;/h3&gt;
&lt;p&gt;Carlos: One of the exciting aspects of open-source development is seeing your creation take on a life of its own. We often discover new use cases when users report issues or reach out for support.&lt;/p&gt;
&lt;p&gt;A particularly interesting example is &lt;a href=&quot;https://hubmapconsortium.org&quot;&gt;HuBMAP&lt;/a&gt; (the Human Biomolecular Atlas Program) using grlc in their groundbreaking work. It’s rewarding to see our tool contributing to such important scientific endeavors, especially ones we never anticipated when we first started development.&lt;/p&gt;
&lt;h2 id=&quot;part-2-grlc-in-action--a-conversation-with-a-hubmap-user&quot;&gt;Part 2: grlc in Action — A Conversation with a HuBMAP User&lt;/h2&gt;
&lt;h3 id=&quot;q-can-you-tell-us-a-bit-about-what-hubmap-is-and-what-youre-working-on&quot;&gt;Q: Can you tell us a bit about what HuBMAP is and what you’re working on?&lt;/h3&gt;
&lt;p&gt;Bruce: &lt;a href=&quot;https://hubmapconsortium.org&quot;&gt;HuBMAP&lt;/a&gt;, or the Human Biomolecular Atlas Program, is an NIH-funded consortium with an ambitious goal: building a comprehensive map of the human body at the cellular level.&lt;/p&gt;
&lt;p&gt;I’m part of the &lt;a href=&quot;https://cns.iu.edu&quot;&gt;Indiana University&lt;/a&gt; Mapping Component, where we’re creating the &lt;a href=&quot;https://humanatlas.io/&quot;&gt;Human Reference Atlas&lt;/a&gt; (HRA). It’s a fascinating project that combines ontologies, expert-curated data (including 2D and 3D anatomical imagery), and experimental data from various providers. The end result is an interconnected map of the human body that’s opening new frontiers in biomedical research.&lt;/p&gt;
&lt;h3 id=&quot;q-that-sounds-like-complex-and-important-work-how-does-grlc-fit-into-this-picture&quot;&gt;Q: That sounds like complex and important work. How does grlc fit into this picture?&lt;/h3&gt;
&lt;p&gt;Bruce: grlc has become an important tool for us. The HRA is built as a &lt;a href=&quot;https://lod.humanatlas.io/&quot;&gt;set of RDF graphs&lt;/a&gt;, which allows us to represent complex relationships in our data. However, we often get requests for specific data from researchers who may not be familiar with SPARQL or RDF.&lt;/p&gt;
&lt;p&gt;This is where grlc comes in handy. We can write a SPARQL query to extract the requested data, and grlc transforms that into a user-friendly interface and API. It’s accessible to both programmers and non-programmers, which is crucial given the diverse backgrounds of our collaborators and data users.&lt;/p&gt;
&lt;h3 id=&quot;q-so-grlc-is-bridging-the-gap-between-your-complex-data-structure-and-the-end-users-who-need-that-data-what-specific-capabilities-has-grlc-unlocked-for-your-team&quot;&gt;Q: So grlc is bridging the gap between your complex data structure and the end-users who need that data. What specific capabilities has grlc unlocked for your team?&lt;/h3&gt;
&lt;p&gt;Bruce: The key advantage is that grlc allows us to maintain our data in a rich, expressive format (RDF) while still providing straightforward reports and interfaces for our end users. It’s lowered the barrier for getting derived data products out to folks who need them.&lt;/p&gt;
&lt;p&gt;Before grlc, there was often a tension between having a powerful, flexible data structure and providing easy access to that data. grlc helps resolve that tension. We can focus on creating comprehensive RDF graphs and writing powerful SPARQL queries and be confident that we can easily share the results with collaborators who might not have the same technical background.&lt;/p&gt;
&lt;h3 id=&quot;q-how-did-you-first-discover-grlc&quot;&gt;Q: How did you first discover grlc?&lt;/h3&gt;
&lt;p&gt;Bruce: It was actually through a collaboration. Around 2022, we were working with EBI (European Bioinformatics Institute), one of our partners. We noticed they were using this tool called grlc for their Ubergraph project. At the time, we had our own SPARQL server and were looking for better ways to share queries and data. After seeing how effectively EBI was using grlc, we decided to &lt;a href=&quot;https://github.com/hubmapconsortium/ccf-grlc/&quot;&gt;give it a try&lt;/a&gt;. Now we’re using it for sharing queries and data in our CCF (Common Coordinate Framework) project.&lt;/p&gt;
&lt;h3 id=&quot;q-looking-ahead-do-you-see-the-sustainability-of-tools-like-grlc-as-a-potential-consideration-for-large-scale-projects-like-hubmap&quot;&gt;Q: Looking ahead, do you see the &lt;a href=&quot;https://xkcd.com/2347/&quot;&gt;sustainability&lt;/a&gt; of tools like grlc as a potential consideration for large-scale projects like HuBMAP?&lt;/h3&gt;
&lt;p&gt;Bruce : It’s definitely something we think about. The continued development and maintenance of grlc is valuable to HuBMAP and the HRA project. While we could theoretically pivot to another technology if needed, grlc has become an important part of our workflow.&lt;/p&gt;
&lt;p&gt;It’s a good example of how open-source tools can become key components of scientific projects. We appreciate the work the grlc team has done and continues to do. Their efforts are helping to advance not just our project, but potentially many others in the scientific community.&lt;/p&gt;
&lt;p&gt;Interview by Lieke de Boer*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/from-corridor-coincidences-to-cellular-c-cec5731c.3PE2AEFD.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>The magic of teaching about the anti-magic of generative AI</title><link>https://blog.esciencecenter.nl/posts/2024-10-03---the-magic-of-teaching-about-the-anti-magic-of-generative-ai</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-10-03---the-magic-of-teaching-about-the-anti-magic-of-generative-ai</guid><description>&lt;p&gt;On the use and abuse of generative artificial intelligence by students&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1750&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Kj-xgUZwT-yLWAbb-1b9e9f52.CaD9LNVx_1zkuYs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Owen Beard on Unsplash&lt;/p&gt;
&lt;p&gt;Recently, I taught the pilot workshop &lt;a href=&quot;https://www.esciencecenter.nl/event/pilot-medical-image-processing/&quot;&gt;Medical Image Processing in Python&lt;/a&gt;. The room was full of post-docs, research software engineers and even faculty, but mostly young PhD candidates or freshly minted PhDs. Although the Netherlands eScience Center offers many courses and workshops, most are established. Many are based on existing &lt;a href=&quot;https://carpentries.org/&quot;&gt;Carpentries&lt;/a&gt; materials that are taught globally. Recognizing a large gap in the existing curriculum in terms of computational medical image processing, the Netherlands eScience Center embraced the idea of starting some sort of workshop about it. Part of the gap, in my opinion, was a lack of a curriculum that addressed generative AI.&lt;/p&gt;
&lt;p&gt;A few brave engineers at the Center designed their own workshops. This year, I did just that, and the process was at once terrifying and energizing. On the weekend before the course, I literally had a nightmare that the students would revolt during the workshop. I dreamt about angry PhDs in computer science yelling at me and the other course developer, a biomedical engineer, literally standing up during my MRI lecture, eyes rolling and correcting me about how spin echo MRI sequences were made.&lt;/p&gt;
&lt;p&gt;By the end of the day, none of this had happened, yet I expected the students to be exhausted and perhaps annoyed. I had stuck a segment on generative AI onto the end of the day, and was dedicated to teaching it, but feared the student revolt of my nightmares might still be coming.&lt;/p&gt;
&lt;p&gt;The role of instructor or faculty can often seem like a bit of a sham in the world of computation-driven health sciences research, and particularly any kind of medical signal processing. On the one hand, the theory behind signal processing is something instructors need to teach to students. On the other hand, all of the theory now needs to be implemented in the digital world, and the ability to implement anything with code well does not seem to track with rank. I have been around this part of academia long enough to know that the pattern is that often students should be teaching the teachers about technology, even if on paper it is the other way around. Would the students be annoyed about the relatively high amount of time we assigned to learn basic code for things like registration and segmentation?&lt;/p&gt;
&lt;p&gt;Or would they just be exhausted? After all, since morning we had all written lots of code, accomplishing many non-trivial feats like &lt;a href=&quot;https://esciencecenter-digital-skills.github.io/medical-image-processing/simpleitk.html&quot;&gt;visualizing image registration in SITK&lt;/a&gt; and augmenting a dataset for machine learning. As I rounded the corner towards the end, showing what &lt;a href=&quot;https://pydicom.github.io/pydicom/stable/index.html#&quot;&gt;pydicom&lt;/a&gt; could do in terms of anonymizing DICOM metadata, I realized I had an urgent last message to impart. How would I ever make people continue to pay attention?&lt;/p&gt;
&lt;p&gt;I took a breath and wondered if the students would start walking out, ready to leave after making it through most of the day. None of them did. Instead, to my surprise, students began engaging more during my last lecture. I could see them thinking about what I was saying.&lt;/p&gt;
&lt;p&gt;Perhaps the topic of generative AI was not as ‘last year’ as I had imagined. I thought everyone had discussed generative AI to death at this point, and certainly, I wouldn’t point out anything younger people didn’t already know. I feared that I might seem like a grandma to them, still mystified and confused by the remote control. It turns out I was wrong about all of that.&lt;/p&gt;
&lt;p&gt;I began my generative AI lecture by showcasing some absolute failures from a well-known generative algorithm in terms of radiological image generation. I showed how even with specific, correctly spelled prompts, I could get back imaging that looked like a computer graphical rendering from 1986 of a circle when prompting about things like an MRI of polycystic kidneys.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;542&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SjLUqHDcUb0oqKPd4QRmyQ-34a1bbb0.F-0zC_qZ_YT8xe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated in response to prompt for a T2 MRI axial slice of polycystic kidney disease&lt;/p&gt;
&lt;p&gt;I then showed some of the coding fails I have seen other people create with ChatGPT. The code I showed was far from ready to run, but it was what I had seen. The code began with approximately the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;path_to_niftis &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Z&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;directory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectoy3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;path_to_meta_data &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; directory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectoy5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;variable_1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; some_never_specified_variable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def funct1&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  for variable_1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  sub_folder &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; some_other_never_specified_variable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sadly, the code did not improve from there. I then pointed out to the students that in both cases the problem here was that anyone had ever taken these outputs (the bad image and the bad code) seriously. Unfortunately, someone had, in the case of the code, and they approached me to review what they had prompted. With one glance, I asked, disingenuously “Did you actually run this?” knowing that at least half the lines would fail to run given that they included variables that were never assigned.&lt;/p&gt;
&lt;p&gt;Afterward, I immediately wrote down some notes for my upcoming lecture. I stumbled upon yet another perfect example of one of the counter-intuitive problems of generative AI that I see all the time. To use these algorithms properly, you need to have deep knowledge of what you expect them to generate. At least in the field of medical imaging research, you cannot leapfrog over learning how to code or spending time with radiologists and pathologists to understand what proper images look like. If you are expert enough at coding, generative models can save you time by helping you debug and write boring code quickly (or so I hear from my more skilled colleagues who use these things). Now there is even &lt;a href=&quot;http://dx.doi.org/10.2139/ssrn.4945566&quot;&gt;some science behind such claims&lt;/a&gt;, although the obvious conflicts of interest should have been stated explicitly in the linked article. But if you have not developed certain skills, generative AI will not necessarily save you time, as opposed to say getting people to share their data and code with you.&lt;/p&gt;
&lt;p&gt;Unfortunately, I suspect the sudden uptick in student attention and involvement was not a reflection of my teaching. Ask anyone who teaches graduate students these days, and you will likely hear some stories about ChatGPT or Copilot or some other generative algorithm. Students have embraced these tools as if they were a sort of digital magic even though &lt;a href=&quot;https://blog.esciencecenter.nl/language-modeling-the-first-100-years-357556816148&quot;&gt;there is nothing magical about these models&lt;/a&gt;. Speak the right spell over the bubbling pot, or server in this case, and the entire world will change into a place where you solve all problems in time to spend hours doing something other than studying and learning. The promise that seems to have been marketed is that not only will your code be written and your work done, but you will be transformed into a wizard who can warp the time-space continuum in such a way that you get free time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;602&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_sfx6zP0DpHT0OnE9XPlgmA-549d87d7.DtJhIfcM_xLfYO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated by Openart.ai after several prompts by the author&lt;/p&gt;
&lt;p&gt;There is a bit of truth to this idea. What I didn’t tell the students is that code is by far the easy case. Here even a mediocre engineer can deploy a bit of witchcraft and potentially transform AI-generated code into something usable. The witchcraft is manual and automated testing. Sometimes all you have to do to improve AI-generated code is to try to get it to run and to write some tests for it. Many of my colleagues are actually getting some useful results out of generative tools.&lt;/p&gt;
&lt;p&gt;With images, things get murkier. There is some published work showing that there are &lt;a href=&quot;https://www.nature.com/articles/s41467-021-27577-x&quot;&gt;synthetic images good enough so that even expert radiologists&lt;/a&gt; could not detect that they were not real. But radiologists are not computers, and typically not engineers either. Rumor has it that in some unpublished studies, while the radiologists were fooled, the software engineers were not. They had seen so much of their own work they could recognize it. I suspect that in terms of machine learning features, generative algorithms might be able to create subtly detectable differences, and therefore a machine learning algorithm could potentially encode some bizarre unintended biases based on these features. I gave the students a more obvious example of potentially doubling down on biases in mammography. What if you want to balance a dataset with more breast cancer samples but all the synthetic data you create shows low-density, relatively fatty, breasts? Then you can potentially increase the correlation between this low density and breast cancer in your dataset. This kind of problem would be fairly easy for human eyes to see, but what about more subtle ones?&lt;/p&gt;
&lt;p&gt;Alas, there are, as of yet, no magic-based solutions to some problems we face in medical imaging research. Maybe the younger generation, today’s students are still hoping for this, because some basic tasks in research now do have solutions that work at astounding speed. Computation on modern computers seems like magic, especially if you do not see GPUs, but hear about some mystical cloud where these things live. The mistake I have seen students make is to double down on generative AI. “I must not be prompting this correctly”, they say when things go wrong, based on the assumption that with the right spell, precisely the code and images they want will appear. But could they even recognize them as such if they did?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The mistake I have seen students make is to double down on generative AI. “I must not be prompting this correctly”, they say when things go wrong, based on the assumption that with the right spell, precisely the code and images they want will appear. But could they even recognize them as such if they did?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is some level of debate in education about the relative importance of teaching facts and information as opposed to teaching methods and skills for discovery. Some people even argued that learning information was already obsolete in the era of search engines and instant access to information. Potentially generative AI is a method of discovery that can amplify anyone’s capabilities. However, I would argue that some amount of foundational information is necessary to get the most from generative tools. What I hope anyone educating university students reading this will take away from learning about my experience is that addressing the issues of Generative AI head-on will make your students stop playing with ChatGPT, sit up, and listen. And maybe even rededicate themselves to including alternative, older forms of knowledge acquisition alongside embracing generative-based methods. Whatever the case, talking about this stuff seems to have almost supernatural effects.&lt;/p&gt;</description><pubDate>Thu, 03 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the use and abuse of generative artificial intelligence by students&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1750&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Kj-xgUZwT-yLWAbb-1b9e9f52.CaD9LNVx_1zkuYs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Owen Beard on Unsplash&lt;/p&gt;
&lt;p&gt;Recently, I taught the pilot workshop &lt;a href=&quot;https://www.esciencecenter.nl/event/pilot-medical-image-processing/&quot;&gt;Medical Image Processing in Python&lt;/a&gt;. The room was full of post-docs, research software engineers and even faculty, but mostly young PhD candidates or freshly minted PhDs. Although the Netherlands eScience Center offers many courses and workshops, most are established. Many are based on existing &lt;a href=&quot;https://carpentries.org/&quot;&gt;Carpentries&lt;/a&gt; materials that are taught globally. Recognizing a large gap in the existing curriculum in terms of computational medical image processing, the Netherlands eScience Center embraced the idea of starting some sort of workshop about it. Part of the gap, in my opinion, was a lack of a curriculum that addressed generative AI.&lt;/p&gt;
&lt;p&gt;A few brave engineers at the Center designed their own workshops. This year, I did just that, and the process was at once terrifying and energizing. On the weekend before the course, I literally had a nightmare that the students would revolt during the workshop. I dreamt about angry PhDs in computer science yelling at me and the other course developer, a biomedical engineer, literally standing up during my MRI lecture, eyes rolling and correcting me about how spin echo MRI sequences were made.&lt;/p&gt;
&lt;p&gt;By the end of the day, none of this had happened, yet I expected the students to be exhausted and perhaps annoyed. I had stuck a segment on generative AI onto the end of the day, and was dedicated to teaching it, but feared the student revolt of my nightmares might still be coming.&lt;/p&gt;
&lt;p&gt;The role of instructor or faculty can often seem like a bit of a sham in the world of computation-driven health sciences research, and particularly any kind of medical signal processing. On the one hand, the theory behind signal processing is something instructors need to teach to students. On the other hand, all of the theory now needs to be implemented in the digital world, and the ability to implement anything with code well does not seem to track with rank. I have been around this part of academia long enough to know that the pattern is that often students should be teaching the teachers about technology, even if on paper it is the other way around. Would the students be annoyed about the relatively high amount of time we assigned to learn basic code for things like registration and segmentation?&lt;/p&gt;
&lt;p&gt;Or would they just be exhausted? After all, since morning we had all written lots of code, accomplishing many non-trivial feats like &lt;a href=&quot;https://esciencecenter-digital-skills.github.io/medical-image-processing/simpleitk.html&quot;&gt;visualizing image registration in SITK&lt;/a&gt; and augmenting a dataset for machine learning. As I rounded the corner towards the end, showing what &lt;a href=&quot;https://pydicom.github.io/pydicom/stable/index.html#&quot;&gt;pydicom&lt;/a&gt; could do in terms of anonymizing DICOM metadata, I realized I had an urgent last message to impart. How would I ever make people continue to pay attention?&lt;/p&gt;
&lt;p&gt;I took a breath and wondered if the students would start walking out, ready to leave after making it through most of the day. None of them did. Instead, to my surprise, students began engaging more during my last lecture. I could see them thinking about what I was saying.&lt;/p&gt;
&lt;p&gt;Perhaps the topic of generative AI was not as ‘last year’ as I had imagined. I thought everyone had discussed generative AI to death at this point, and certainly, I wouldn’t point out anything younger people didn’t already know. I feared that I might seem like a grandma to them, still mystified and confused by the remote control. It turns out I was wrong about all of that.&lt;/p&gt;
&lt;p&gt;I began my generative AI lecture by showcasing some absolute failures from a well-known generative algorithm in terms of radiological image generation. I showed how even with specific, correctly spelled prompts, I could get back imaging that looked like a computer graphical rendering from 1986 of a circle when prompting about things like an MRI of polycystic kidneys.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;542&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SjLUqHDcUb0oqKPd4QRmyQ-34a1bbb0.F-0zC_qZ_YT8xe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated in response to prompt for a T2 MRI axial slice of polycystic kidney disease&lt;/p&gt;
&lt;p&gt;I then showed some of the coding fails I have seen other people create with ChatGPT. The code I showed was far from ready to run, but it was what I had seen. The code began with approximately the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;path_to_niftis &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Z&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;directory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectoy3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;path_to_meta_data &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; directory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectory4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;subdirectoy5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;variable_1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; some_never_specified_variable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def funct1&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  for variable_1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  sub_folder &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; some_other_never_specified_variable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sadly, the code did not improve from there. I then pointed out to the students that in both cases the problem here was that anyone had ever taken these outputs (the bad image and the bad code) seriously. Unfortunately, someone had, in the case of the code, and they approached me to review what they had prompted. With one glance, I asked, disingenuously “Did you actually run this?” knowing that at least half the lines would fail to run given that they included variables that were never assigned.&lt;/p&gt;
&lt;p&gt;Afterward, I immediately wrote down some notes for my upcoming lecture. I stumbled upon yet another perfect example of one of the counter-intuitive problems of generative AI that I see all the time. To use these algorithms properly, you need to have deep knowledge of what you expect them to generate. At least in the field of medical imaging research, you cannot leapfrog over learning how to code or spending time with radiologists and pathologists to understand what proper images look like. If you are expert enough at coding, generative models can save you time by helping you debug and write boring code quickly (or so I hear from my more skilled colleagues who use these things). Now there is even &lt;a href=&quot;http://dx.doi.org/10.2139/ssrn.4945566&quot;&gt;some science behind such claims&lt;/a&gt;, although the obvious conflicts of interest should have been stated explicitly in the linked article. But if you have not developed certain skills, generative AI will not necessarily save you time, as opposed to say getting people to share their data and code with you.&lt;/p&gt;
&lt;p&gt;Unfortunately, I suspect the sudden uptick in student attention and involvement was not a reflection of my teaching. Ask anyone who teaches graduate students these days, and you will likely hear some stories about ChatGPT or Copilot or some other generative algorithm. Students have embraced these tools as if they were a sort of digital magic even though &lt;a href=&quot;https://blog.esciencecenter.nl/language-modeling-the-first-100-years-357556816148&quot;&gt;there is nothing magical about these models&lt;/a&gt;. Speak the right spell over the bubbling pot, or server in this case, and the entire world will change into a place where you solve all problems in time to spend hours doing something other than studying and learning. The promise that seems to have been marketed is that not only will your code be written and your work done, but you will be transformed into a wizard who can warp the time-space continuum in such a way that you get free time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;602&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_sfx6zP0DpHT0OnE9XPlgmA-549d87d7.DtJhIfcM_xLfYO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated by Openart.ai after several prompts by the author&lt;/p&gt;
&lt;p&gt;There is a bit of truth to this idea. What I didn’t tell the students is that code is by far the easy case. Here even a mediocre engineer can deploy a bit of witchcraft and potentially transform AI-generated code into something usable. The witchcraft is manual and automated testing. Sometimes all you have to do to improve AI-generated code is to try to get it to run and to write some tests for it. Many of my colleagues are actually getting some useful results out of generative tools.&lt;/p&gt;
&lt;p&gt;With images, things get murkier. There is some published work showing that there are &lt;a href=&quot;https://www.nature.com/articles/s41467-021-27577-x&quot;&gt;synthetic images good enough so that even expert radiologists&lt;/a&gt; could not detect that they were not real. But radiologists are not computers, and typically not engineers either. Rumor has it that in some unpublished studies, while the radiologists were fooled, the software engineers were not. They had seen so much of their own work they could recognize it. I suspect that in terms of machine learning features, generative algorithms might be able to create subtly detectable differences, and therefore a machine learning algorithm could potentially encode some bizarre unintended biases based on these features. I gave the students a more obvious example of potentially doubling down on biases in mammography. What if you want to balance a dataset with more breast cancer samples but all the synthetic data you create shows low-density, relatively fatty, breasts? Then you can potentially increase the correlation between this low density and breast cancer in your dataset. This kind of problem would be fairly easy for human eyes to see, but what about more subtle ones?&lt;/p&gt;
&lt;p&gt;Alas, there are, as of yet, no magic-based solutions to some problems we face in medical imaging research. Maybe the younger generation, today’s students are still hoping for this, because some basic tasks in research now do have solutions that work at astounding speed. Computation on modern computers seems like magic, especially if you do not see GPUs, but hear about some mystical cloud where these things live. The mistake I have seen students make is to double down on generative AI. “I must not be prompting this correctly”, they say when things go wrong, based on the assumption that with the right spell, precisely the code and images they want will appear. But could they even recognize them as such if they did?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The mistake I have seen students make is to double down on generative AI. “I must not be prompting this correctly”, they say when things go wrong, based on the assumption that with the right spell, precisely the code and images they want will appear. But could they even recognize them as such if they did?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is some level of debate in education about the relative importance of teaching facts and information as opposed to teaching methods and skills for discovery. Some people even argued that learning information was already obsolete in the era of search engines and instant access to information. Potentially generative AI is a method of discovery that can amplify anyone’s capabilities. However, I would argue that some amount of foundational information is necessary to get the most from generative tools. What I hope anyone educating university students reading this will take away from learning about my experience is that addressing the issues of Generative AI head-on will make your students stop playing with ChatGPT, sit up, and listen. And maybe even rededicate themselves to including alternative, older forms of knowledge acquisition alongside embracing generative-based methods. Whatever the case, talking about this stuff seems to have almost supernatural effects.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_SjLUqHDcUb0oqKPd4QRmyQ-34a1bbb0.F-0zC_qZ.png" medium="image"/><author>Candace Moore</author></item><item><title>National Research Software Day: National Infrastructures for Sustainable Software</title><link>https://blog.esciencecenter.nl/posts/2024-09-19---national-research-software-day-national-infrastructures-for-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-09-19---national-research-software-day-national-infrastructures-for-</guid><description>&lt;p&gt;*Written by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/luisa-orozco/&quot;&gt;&lt;em&gt;Luisa Orozco&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://danielagawehns.github.io/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and *&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first &lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt; already took place more than five months ago in Hilversum, on 23 April 2024. Following an inspiring keynote by Rogier Kievit, several parallel sessions competed for the attention of participants. This blog covers the ‘National infrastructures for sustainable software’ session.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;National Research Software Day: National Infrastructures for Sustainable Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/national-research-software-day-national--8a937220.BjtgdaL6_hKCo.webp&quot; srcset=&quot;&quot;&gt;
This session was a follow-up from a &lt;a href=&quot;https://blog.esciencecenter.nl/open-science-festival-what-infrastructures-do-we-need-to-preserve-research-software-7c181404f310&quot;&gt;similar session&lt;/a&gt; that took place during the &lt;a href=&quot;https://opensciencefestival.nl/&quot;&gt;Dutch Open Science Festival&lt;/a&gt; in 2023. On this occasion, the format was the same: a series of panel pitches, followed by a group discussion. The panel shared their insights and experiences related to infrastructure used for creating and maintaining sustainable research software. The composition of the panel was different on this occasion, so the discussion took a different direction.&lt;/p&gt;
&lt;p&gt;Luisa Orozco, RSE at the Netherlands eScience Center, led the discussion.&lt;/p&gt;
&lt;p&gt;After the session, the panelists were also interviewed by Peter Schmidt for the &lt;a href=&quot;https://codeforthought.buzzsprout.com/1326658/15210839-en-a-national-day-for-research-software-the-escience-center&quot;&gt;Code for Thought Podcast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;National Research Software Day: National Infrastructures for Sustainable Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/national-research-software-day-national--912a8b8f.B554FYB3_Z1o2JrB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;panel-composition-and-introduction&quot;&gt;Panel composition and introduction&lt;/h2&gt;
&lt;h3 id=&quot;elaine-van-ommen-kloeke-arise&quot;&gt;Elaine van Ommen Kloeke, ARISE&lt;/h3&gt;
&lt;p&gt;At Naturalis we build a digital infrastructure for recognizing species biodiversity. Data is huge, vertebrates, plants, insects, fungi. It is a huge challenge to capture, store and move data.&lt;/p&gt;
&lt;h3 id=&quot;louise-bezuidenhout-cwts-leiden-university&quot;&gt;Louise Bezuidenhout, CWTS Leiden University&lt;/h3&gt;
&lt;p&gt;Senior researcher focusing on Open Science monitoring and the evolution of Open Science infrastructures. The CWTS publishes the annual Leiden University rankings using Open Data, based on the Leiden manifesto which advocates for open and transparent research assessments moving beyond the normal metrics.&lt;/p&gt;
&lt;h3 id=&quot;jason-maassen-research-software-directory&quot;&gt;Jason Maassen, Research Software Directory&lt;/h3&gt;
&lt;p&gt;Jason is a Technology Lead at the Netherlands eScience Center supporting and helping researchers develop software. The eScience Center leads the Research Software Directory (RSD), a platform developed to highlight the roles of RSEs in research through links between software and other kinds of research outputs such as datasets, publications, research activities, projects and people.&lt;/p&gt;
&lt;h3 id=&quot;roel-janssen-4turesearchdata&quot;&gt;Roel Janssen, 4TU.ResearchData&lt;/h3&gt;
&lt;p&gt;4TU.ResearchData stores, archives and publishes datasets for technical universities in the Netherlands. I have the opportunity to work together at the National level with, for example, the RSD, to implement APIs and standards to help the deployability of research data and software.&lt;/p&gt;
&lt;h2 id=&quot;discussion&quot;&gt;Discussion&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Which kind of software, or which kind of infrastructure do you need in your day-to-day work or your institutes?&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine:&lt;/em&gt; There’s nothing standard that we can use. Some parts we can reuse and are open-source, while others have to be built from scratch. I need data storage, computing, dimension systems, PID identification systems, authentication, authorization and I need it to be user-friendly and encourage collaboration.&lt;/p&gt;
&lt;p&gt;*Louise: *I need access to data and knowledge graphs that we can use for our meta-research.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;How does the RSD and 4TU cater to the needs that researchers have in terms of infrastructure? Which niche or which solution are you targeting?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason:&lt;/em&gt; With the RSD, we link software to other research outputs and activities, integrating information needed for institute assessment. Also, it is a useful tool for researchers to find software.&lt;/p&gt;
&lt;p&gt;*Roel: *At 4TU we offer data and software repositories, more data storage is a common request. We also offer computation environments such that a given code can be run alongside the data.&lt;/p&gt;
&lt;p&gt;We also strive for recognition of good software, so that a user can find and reuse the software. We also try to make data publications more attractive to researchers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;When using those infrastructures, what are the boundaries or limitations that you encounter? For example national vs international, or open/closed/paid.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;*Elaine: *My first criterion is ‘does it get the job done’? Ideally open and reusable.&lt;/p&gt;
&lt;p&gt;*Louise: *I work with computer scientists examining how accessible these infrastructures are to users globally. We have used VPNs to access resources and found significant variability not only in terms of access speed but also in geographical accessibility. This variability raises questions about the impact of resource location, funding models, and user requirements on accessibility. We need to critically evaluate the geopolitical landscape surrounding infrastructure choices, take the example of GitHub, which is inaccessible to users in countries currently under financial sanction by the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;From more of a provider side: What are your boundaries or limitations? How do you decide who is your public and how far can you get?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel, you mentioned new features that the users were requesting. How do you handle those requests?&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel:&lt;/em&gt; We do receive more feature requests than we can implement due to limited manpower. To manage this, we prioritize based on ease of implementation, sometimes responding quickly and other times taking longer due to extensive planning required. At community events like those within 4TU, we prioritize requests from partners, universities, and funders, addressing recurring ones promptly. Additionally, we anticipate future needs by observing trends in software usage, implementing APIs for upcoming demands even before they are explicitly requested. It’s a balancing act between fulfilling immediate requests and anticipating long-term needs to stay ahead of the curve.&lt;/p&gt;
&lt;h2 id=&quot;questions-from-the-public&quot;&gt;Questions from the public&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;GitHub plays a central role in software development and it is a potential point of failure: it is centralized in nature, American-owned and has the possibility of being closed down, similar to what happened with Google Code. This is a vulnerability not just for the Netherlands but globally. How can these risks be mitigated?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel:&lt;/em&gt; There was a similar issue in the past with SVN and SourceForge. Unlike then, modern version control systems like Git offer a distributed model, where each developer has a complete copy of the source code, making it easier to switch platforms if needed. SoftwareHeritage also stores a copy of everything stored on GitHub. However, transferring auxiliary components like Wikis and issues remains a challenge. Continuous integration tools like GitHub Actions, while powerful, can be proprietary and tied to specific platforms, raising concerns about dependence on a single provider.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: Now that the OpenScience movement is gaining momentum, the Open Science community should have a better dialogue with companies such as GitHub, and together find a suitable way of working. This type of change has already started, for example, with the publishing industries which have also been changing in this direction. The decision to create a national dataverse is also an outcome of these dialogues.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: You do see a lot of organizations looking for alternatives, for example, running local GitLab instances. But these alternatives also take time and cost money. When organizations realize how much time and effort it costs, they often back off and turn back to commercial providers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: It depends on what you are trying to achieve. I could run my own data management system, but then I would need 15 dedicated engineers, and I only have two. I want those two to focus on other things. It is a bit of a balance between being principled and being pragmatic. There needs to be a conversation between research-performing organizations and commercial companies. I have no problem using a commercial company, as long as I keep the option to move my data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is an issue with depending on commercial companies, because if, for example, they change their license, you may need to change things in your own software. The same applies if they change formats — I have a lot of data from 30 years ago in Microsoft formats that I am unable to read anymore. You are putting yourself at risk!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: It is the same story with a Discman, it is the natural evolution of products and services that occurs everywhere, all the time. We now no longer use Discman today, but rather we use Spotify. We still listen to music, but if you insist on sticking with a Discman and are not prepared to move to new tech, you can get stuck. It is not something that applies to commercial products only. It is a risk that exists and that you need to take into account and plan for sufficiently in advance. You need to be aware of what risks exist, and what alternatives are available.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Maybe it is preferable to keep options as generic as possible. So instead of having a button that says “link with GitHub” have a more generic “link with any git version control”. It is useful to show which options you provide and that there are alternatives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you think having a centralized way of operation is the solution?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: For many types of infrastructure, perhaps that would be a viable option. That would be the case for a national PID system. It is the type of infrastructure that everybody needs, but nobody wants to build it or pay for it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Maybe in terms of standards, if we have a well-defined standard and many options of implementation, then that would be the best.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is there a way to see at an institutional level how much data and software have been produced? For example, PURE registers all your publications, but for data and software, it is not done as much.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: For publications, publishers harvest and analyze this information. Technically, it is not that hard to do, but it is not consistently done for data and software. One thing we have done is look at OpenAlex and try to connect all of these resources and figure out if we can identify citations for software. What you see is that there are many citations for publications, some citations for datasets and very few citations for software.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: At CWTS we are looking into this, and we’ve been working with the Center for Digital Scholarship, but we do not have solutions yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At Digital Humanities Lab we are looking into how to make our software more visible. But if we offload all the metadata to the RSD, how many people will use it? You also need to engage in how to make users find it. For developers, the incentive to create software is knowing it will be used.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: We are currently working with different communities to create community-specific views, the goal is that communities themselves curate the content by ensuring keywords are relevant for the target users. We are also looking into integrating the RSD with search engine tools so that software can be found more easily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the bus-factor for the RSD/4TU.ResearchData? What challenges do you face in increasing it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: Currently, at the eScience Center the bus-factor is three. This is a great increase from one, which is what it was a few years ago. We are also collaborating with other organizations in Germany, which increases it. But finding someone to keep pushing the software remains a difficult challenge.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Our bus factor is two and a half or three, spread over multiple people over the team. We do not have enough money available to grow the team, but we do have multiple people who understand how everything works.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;What would you like participants of this session to remember as their take home message. Something you would still like to say?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: Keep talking! People hate meetings, but getting together is how people share ideas, especially across domains but also for setting standards.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: Keep talking, also to people who you never talked to before. The range of stakeholders in science is very broad: it is not limited to academia, not limited to the Netherlands.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: Recognition not only for those developing great research software but also for those engaging in promoting best practices, infrastructures and in setting standards.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: For me, if you have any ideas on how to improve repositories please get in touch!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you to all of our panellists for their participation. These are a lot of topics that are very interesting for us and it is great we could have this nice conversation!&lt;/strong&gt;&lt;/p&gt;</description><pubDate>Thu, 19 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;*Written by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/luisa-orozco/&quot;&gt;&lt;em&gt;Luisa Orozco&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://danielagawehns.github.io/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and *&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first &lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt; already took place more than five months ago in Hilversum, on 23 April 2024. Following an inspiring keynote by Rogier Kievit, several parallel sessions competed for the attention of participants. This blog covers the ‘National infrastructures for sustainable software’ session.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;National Research Software Day: National Infrastructures for Sustainable Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/national-research-software-day-national--8a937220.BjtgdaL6_hKCo.webp&quot; srcset=&quot;&quot;&gt;
This session was a follow-up from a &lt;a href=&quot;https://blog.esciencecenter.nl/open-science-festival-what-infrastructures-do-we-need-to-preserve-research-software-7c181404f310&quot;&gt;similar session&lt;/a&gt; that took place during the &lt;a href=&quot;https://opensciencefestival.nl/&quot;&gt;Dutch Open Science Festival&lt;/a&gt; in 2023. On this occasion, the format was the same: a series of panel pitches, followed by a group discussion. The panel shared their insights and experiences related to infrastructure used for creating and maintaining sustainable research software. The composition of the panel was different on this occasion, so the discussion took a different direction.&lt;/p&gt;
&lt;p&gt;Luisa Orozco, RSE at the Netherlands eScience Center, led the discussion.&lt;/p&gt;
&lt;p&gt;After the session, the panelists were also interviewed by Peter Schmidt for the &lt;a href=&quot;https://codeforthought.buzzsprout.com/1326658/15210839-en-a-national-day-for-research-software-the-escience-center&quot;&gt;Code for Thought Podcast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;National Research Software Day: National Infrastructures for Sustainable Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/national-research-software-day-national--912a8b8f.B554FYB3_Z1o2JrB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;panel-composition-and-introduction&quot;&gt;Panel composition and introduction&lt;/h2&gt;
&lt;h3 id=&quot;elaine-van-ommen-kloeke-arise&quot;&gt;Elaine van Ommen Kloeke, ARISE&lt;/h3&gt;
&lt;p&gt;At Naturalis we build a digital infrastructure for recognizing species biodiversity. Data is huge, vertebrates, plants, insects, fungi. It is a huge challenge to capture, store and move data.&lt;/p&gt;
&lt;h3 id=&quot;louise-bezuidenhout-cwts-leiden-university&quot;&gt;Louise Bezuidenhout, CWTS Leiden University&lt;/h3&gt;
&lt;p&gt;Senior researcher focusing on Open Science monitoring and the evolution of Open Science infrastructures. The CWTS publishes the annual Leiden University rankings using Open Data, based on the Leiden manifesto which advocates for open and transparent research assessments moving beyond the normal metrics.&lt;/p&gt;
&lt;h3 id=&quot;jason-maassen-research-software-directory&quot;&gt;Jason Maassen, Research Software Directory&lt;/h3&gt;
&lt;p&gt;Jason is a Technology Lead at the Netherlands eScience Center supporting and helping researchers develop software. The eScience Center leads the Research Software Directory (RSD), a platform developed to highlight the roles of RSEs in research through links between software and other kinds of research outputs such as datasets, publications, research activities, projects and people.&lt;/p&gt;
&lt;h3 id=&quot;roel-janssen-4turesearchdata&quot;&gt;Roel Janssen, 4TU.ResearchData&lt;/h3&gt;
&lt;p&gt;4TU.ResearchData stores, archives and publishes datasets for technical universities in the Netherlands. I have the opportunity to work together at the National level with, for example, the RSD, to implement APIs and standards to help the deployability of research data and software.&lt;/p&gt;
&lt;h2 id=&quot;discussion&quot;&gt;Discussion&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Which kind of software, or which kind of infrastructure do you need in your day-to-day work or your institutes?&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine:&lt;/em&gt; There’s nothing standard that we can use. Some parts we can reuse and are open-source, while others have to be built from scratch. I need data storage, computing, dimension systems, PID identification systems, authentication, authorization and I need it to be user-friendly and encourage collaboration.&lt;/p&gt;
&lt;p&gt;*Louise: *I need access to data and knowledge graphs that we can use for our meta-research.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;How does the RSD and 4TU cater to the needs that researchers have in terms of infrastructure? Which niche or which solution are you targeting?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason:&lt;/em&gt; With the RSD, we link software to other research outputs and activities, integrating information needed for institute assessment. Also, it is a useful tool for researchers to find software.&lt;/p&gt;
&lt;p&gt;*Roel: *At 4TU we offer data and software repositories, more data storage is a common request. We also offer computation environments such that a given code can be run alongside the data.&lt;/p&gt;
&lt;p&gt;We also strive for recognition of good software, so that a user can find and reuse the software. We also try to make data publications more attractive to researchers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;When using those infrastructures, what are the boundaries or limitations that you encounter? For example national vs international, or open/closed/paid.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;*Elaine: *My first criterion is ‘does it get the job done’? Ideally open and reusable.&lt;/p&gt;
&lt;p&gt;*Louise: *I work with computer scientists examining how accessible these infrastructures are to users globally. We have used VPNs to access resources and found significant variability not only in terms of access speed but also in geographical accessibility. This variability raises questions about the impact of resource location, funding models, and user requirements on accessibility. We need to critically evaluate the geopolitical landscape surrounding infrastructure choices, take the example of GitHub, which is inaccessible to users in countries currently under financial sanction by the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;From more of a provider side: What are your boundaries or limitations? How do you decide who is your public and how far can you get?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel, you mentioned new features that the users were requesting. How do you handle those requests?&lt;/em&gt;**&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel:&lt;/em&gt; We do receive more feature requests than we can implement due to limited manpower. To manage this, we prioritize based on ease of implementation, sometimes responding quickly and other times taking longer due to extensive planning required. At community events like those within 4TU, we prioritize requests from partners, universities, and funders, addressing recurring ones promptly. Additionally, we anticipate future needs by observing trends in software usage, implementing APIs for upcoming demands even before they are explicitly requested. It’s a balancing act between fulfilling immediate requests and anticipating long-term needs to stay ahead of the curve.&lt;/p&gt;
&lt;h2 id=&quot;questions-from-the-public&quot;&gt;Questions from the public&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;GitHub plays a central role in software development and it is a potential point of failure: it is centralized in nature, American-owned and has the possibility of being closed down, similar to what happened with Google Code. This is a vulnerability not just for the Netherlands but globally. How can these risks be mitigated?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel:&lt;/em&gt; There was a similar issue in the past with SVN and SourceForge. Unlike then, modern version control systems like Git offer a distributed model, where each developer has a complete copy of the source code, making it easier to switch platforms if needed. SoftwareHeritage also stores a copy of everything stored on GitHub. However, transferring auxiliary components like Wikis and issues remains a challenge. Continuous integration tools like GitHub Actions, while powerful, can be proprietary and tied to specific platforms, raising concerns about dependence on a single provider.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: Now that the OpenScience movement is gaining momentum, the Open Science community should have a better dialogue with companies such as GitHub, and together find a suitable way of working. This type of change has already started, for example, with the publishing industries which have also been changing in this direction. The decision to create a national dataverse is also an outcome of these dialogues.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: You do see a lot of organizations looking for alternatives, for example, running local GitLab instances. But these alternatives also take time and cost money. When organizations realize how much time and effort it costs, they often back off and turn back to commercial providers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: It depends on what you are trying to achieve. I could run my own data management system, but then I would need 15 dedicated engineers, and I only have two. I want those two to focus on other things. It is a bit of a balance between being principled and being pragmatic. There needs to be a conversation between research-performing organizations and commercial companies. I have no problem using a commercial company, as long as I keep the option to move my data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is an issue with depending on commercial companies, because if, for example, they change their license, you may need to change things in your own software. The same applies if they change formats — I have a lot of data from 30 years ago in Microsoft formats that I am unable to read anymore. You are putting yourself at risk!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: It is the same story with a Discman, it is the natural evolution of products and services that occurs everywhere, all the time. We now no longer use Discman today, but rather we use Spotify. We still listen to music, but if you insist on sticking with a Discman and are not prepared to move to new tech, you can get stuck. It is not something that applies to commercial products only. It is a risk that exists and that you need to take into account and plan for sufficiently in advance. You need to be aware of what risks exist, and what alternatives are available.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Maybe it is preferable to keep options as generic as possible. So instead of having a button that says “link with GitHub” have a more generic “link with any git version control”. It is useful to show which options you provide and that there are alternatives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you think having a centralized way of operation is the solution?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: For many types of infrastructure, perhaps that would be a viable option. That would be the case for a national PID system. It is the type of infrastructure that everybody needs, but nobody wants to build it or pay for it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Maybe in terms of standards, if we have a well-defined standard and many options of implementation, then that would be the best.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is there a way to see at an institutional level how much data and software have been produced? For example, PURE registers all your publications, but for data and software, it is not done as much.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: For publications, publishers harvest and analyze this information. Technically, it is not that hard to do, but it is not consistently done for data and software. One thing we have done is look at OpenAlex and try to connect all of these resources and figure out if we can identify citations for software. What you see is that there are many citations for publications, some citations for datasets and very few citations for software.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: At CWTS we are looking into this, and we’ve been working with the Center for Digital Scholarship, but we do not have solutions yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At Digital Humanities Lab we are looking into how to make our software more visible. But if we offload all the metadata to the RSD, how many people will use it? You also need to engage in how to make users find it. For developers, the incentive to create software is knowing it will be used.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: We are currently working with different communities to create community-specific views, the goal is that communities themselves curate the content by ensuring keywords are relevant for the target users. We are also looking into integrating the RSD with search engine tools so that software can be found more easily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the bus-factor for the RSD/4TU.ResearchData? What challenges do you face in increasing it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: Currently, at the eScience Center the bus-factor is three. This is a great increase from one, which is what it was a few years ago. We are also collaborating with other organizations in Germany, which increases it. But finding someone to keep pushing the software remains a difficult challenge.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: Our bus factor is two and a half or three, spread over multiple people over the team. We do not have enough money available to grow the team, but we do have multiple people who understand how everything works.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;What would you like participants of this session to remember as their take home message. Something you would still like to say?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Elaine&lt;/em&gt;: Keep talking! People hate meetings, but getting together is how people share ideas, especially across domains but also for setting standards.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Louise&lt;/em&gt;: Keep talking, also to people who you never talked to before. The range of stakeholders in science is very broad: it is not limited to academia, not limited to the Netherlands.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason&lt;/em&gt;: Recognition not only for those developing great research software but also for those engaging in promoting best practices, infrastructures and in setting standards.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Roel&lt;/em&gt;: For me, if you have any ideas on how to improve repositories please get in touch!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you to all of our panellists for their participation. These are a lot of topics that are very interesting for us and it is great we could have this nice conversation!&lt;/strong&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/national-research-software-day-national--8a937220.BjtgdaL6.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>(Un)wieldy workflows with WRF</title><link>https://blog.esciencecenter.nl/posts/2024-09-05---unwieldy-workflows-with-wrf</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-09-05---unwieldy-workflows-with-wrf</guid><description>&lt;h1 id=&quot;unwieldy-workflows-with-wrf&quot;&gt;&lt;strong&gt;(Un)wieldy workflows with WRF&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;streamlining-experiments-with-the-weather-research-and-forecasting-model&quot;&gt;&lt;strong&gt;Streamlining experiments with the Weather Research and Forecasting model&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.mmm.ucar.edu/models/wrf&quot;&gt;Weather Research and Forecasting model&lt;/a&gt;, WRF for short, is a beautiful piece of research software with a large community of active users. That’s something we love and advocate for at the eScience Center.&lt;/p&gt;
&lt;p&gt;Given its large user base, one might think this must be an exemplary model to work with. And perhaps it is, in comparison to other models in the scene. But as I’m working with WRF again after several years, I’m reminded of my struggles in keeping my workflows organized.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;386&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-b6e59d0c.B5Z5PUNe_Z1p8i5Q.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@hdbernd?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Bernd 📷 Dittrich&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To try and tackle this issue once and for all, we experimented with different solutions, including a simple shell script, as well as &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/&quot;&gt;Snakemake&lt;/a&gt;, a python-based workflow management tool often used in bioinformatics. Both approaches turn out to have their own merits and quirks.&lt;/p&gt;
&lt;p&gt;Overall, we did get a better grip on the antipatterns that prevented us from keeping a nice and orderly workflow. From this, we extracted some best practices for managing complex (WRF) modelling workflows. This blogpost documents our journey and the lessons learned, in the hope that it will be useful for other WRF users and those who struggle with managing their experiments.&lt;/p&gt;
&lt;h2 id=&quot;running-basic-wrf&quot;&gt;Running basic WRF**&lt;/h2&gt;
&lt;p&gt;Let’s start with an overview of the steps required to run a basic WRF (real data) experiment, as per the instructions in the &lt;a href=&quot;https://www2.mmm.ucar.edu/wrf/users/wrf_users_guide/build/html/wps.html&quot;&gt;user guide&lt;/a&gt;. First you must run the WRF preprocessing system (WPS), which itself consists of three programs: geogrid, ungrib, and metgrid. Then you run WRF itself, which also consists of two programs: real and wrf.&lt;/p&gt;
&lt;p&gt;cd WPS**&lt;/p&gt;
&lt;h1 id=&quot;run-geogrid-interpolate-spatial-datasets-to-the-model-grid&quot;&gt;Run geogrid (interpolate spatial datasets to the model grid)&lt;/h1&gt;
&lt;p&gt;./geogrid.exe&lt;/p&gt;
&lt;h1 id=&quot;run-ungrib-unpack-meteorological-input-data&quot;&gt;Run ungrib (unpack meteorological input data)&lt;/h1&gt;
&lt;p&gt;./link_grib.csh /your/meteo/data/dir
ln -s ungrib/Variable_Tables/Vtable.GFS Vtable
./ungrib.exe&lt;/p&gt;
&lt;h1 id=&quot;run-metgrid-interpolate-the-meteo-data-to-model-grid&quot;&gt;Run metgrid (interpolate the meteo data to model grid)&lt;/h1&gt;
&lt;p&gt;./metgrid.exe&lt;/p&gt;
&lt;p&gt;cd ../WRF/run&lt;/p&gt;
&lt;h1 id=&quot;run-real-extract-initial-and-boundary-fields-from-preprocessed-data&quot;&gt;Run real (extract initial and boundary fields from preprocessed data)&lt;/h1&gt;
&lt;p&gt;ln -sf ../../WPS/met_em* .
./real.exe&lt;/p&gt;
&lt;h1 id=&quot;run-wrf-the-actual-forecast&quot;&gt;Run WRF (the actual forecast)&lt;/h1&gt;
&lt;p&gt;./wrf.exeThis workflow is not great in several ways. WRF and WPS are run in different working directories; yet they “pretend” to be in the same directory by use of symbolic links (&lt;code&gt;ln&lt;/code&gt;). Also, exectuables are in the same directory as the input/output data. Now, imagine, for example, that we want to do multiple experiments with slightly different settings.&lt;/p&gt;
&lt;p&gt;One option would be to move the output to a separate directory between each run. We would need to meticulously bookkeep our files, especially since runs may fail at different stages causing us to re-run (part of) the workflow. Also, we would not be able run the experiments in parallel. Clearly, using WRF in this way is a labour-intensive, error-prone process.&lt;/p&gt;
&lt;p&gt;Alternatively, we could duplicate our &lt;code&gt;WPS&lt;/code&gt;and &lt;code&gt;WRF/run&lt;/code&gt;directories. That’s also not great: imagine we want to re-run our experiments with a re-compiled version of WRF. Then we would need to copy over the new executables to all experiment directories.&lt;/p&gt;
&lt;p&gt;Finally, there’s lots of files in these directories that are not needed for our experiments, which makes it hard to tell the wheat from the chaff.&lt;/p&gt;
&lt;h3 id=&quot;our-workflow-wishlist&quot;&gt;Our workflow wishlist**&lt;/h3&gt;
&lt;p&gt;Considering the points above, let’s think about how we would like it to be, and start a workflow wishlist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each/all experiment(s) can be re-run with a single command&lt;/li&gt;
&lt;li&gt;One directory per experiment, containing config + output&lt;/li&gt;
&lt;li&gt;Intermediate/output data well organized in subdirectories&lt;/li&gt;
&lt;li&gt;Config files (namelists) specify paths to all relevant input data; no links&lt;/li&gt;
&lt;li&gt;Executables should be in a system path or another dedicated location&lt;/li&gt;
&lt;li&gt;We should be able to (re-)run only part of a workflow&lt;/li&gt;
&lt;li&gt;Bonus: reuse intermediate files that are the same for all experiments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution-1-using-a-shell-script&quot;&gt;&lt;strong&gt;Solution #1: using a shell script&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Let’s see how far we can get with a simple shell script. In this example, we maintain multiple namelists and geogrid tables for each experiment. These are stored alongside the shell script and copied over to the experiment folder once the script is run. The full code is available &lt;a href=&quot;https://github.com/Urban-M4/wrf-runner&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;some-initialization-of-the-environment-module-loads-etc-&quot;&gt;Some initialization of the environment, module loads etc.**# …&lt;/h1&gt;
&lt;h1 id=&quot;set-path-to-executables&quot;&gt;Set path to executables&lt;/h1&gt;
&lt;p&gt;WPS_HOME=&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;HOME/wrf-model/WPS
WRF_HOME=&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;HOME/wrf-model/WRF&lt;/p&gt;
&lt;h1 id=&quot;define-experiment-name&quot;&gt;Define experiment name&lt;/h1&gt;
&lt;p&gt;EXP=USGS&lt;/p&gt;
&lt;h1 id=&quot;make-new-experiment-directory&quot;&gt;Make new experiment directory&lt;/h1&gt;
&lt;p&gt;export RUNDIR=wrf_experiments/&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{EXP}
mkdir -p &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR
mkdir &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;D&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RUNDIR/geogrid
mkdir &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;eo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/metgrid&lt;/p&gt;
&lt;h1 id=&quot;copy-experiment-dependent-files&quot;&gt;Copy experiment-dependent files&lt;/h1&gt;
&lt;p&gt;cp namelist.wps_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/namelist.wps
cp namelist.input_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/namelist.input
cp GEOGRID.TBL.ARW_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/GEOGRID.TBL&lt;/p&gt;
&lt;h1 id=&quot;copy-additional-input-files-from-wrfwps&quot;&gt;Copy additional input files from WRF/WPS&lt;/h1&gt;
&lt;p&gt;cd &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;D&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RUNDIR
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WPS_HOME/metgrid/METGRID.TBL.ARW METGRID.TBL
cp &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WPS_HOME/ungrid/Variable_Tables/Vtable.ECMWF VTable
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;iab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/CAMtr_volume_mixing_ratio.RCP8.5 CAMtr_volume_mixing_ratio
cp &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WRF_HOME/run/ozone* .
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;oz&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/RRTMG* .
cp $WRF_HOME/run/*.TBL .&lt;/p&gt;
&lt;h1 id=&quot;run-experiments&quot;&gt;Run experiments&lt;/h1&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WPS_HOME/link_grib.csh &quot;path/to/our/input/data/*&quot;
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0361em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0315em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ib&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WPS_HOME/ungrib.exe
&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;&amp;#x26;&amp;#x27; at position 47: …R&amp;#x22; geogrid.log &amp;#x26;̲amp;&amp;#x26;amp; echo …&quot; style=&quot;color:#cc0000&quot;&gt;WPS_HOME/geogrid.exe
grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1
&lt;/span&gt;WPS_HOME/metgrid.exe
grep “ERROR” metgrid.log &amp;#x26;&amp;#x26; echo “Aborting: ERROR in metgrid.log.” &amp;#x26;&amp;#x26; exit 1&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WRF_HOME/run/real.exe
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/wrf.exeEvidently, WRF and WPS &lt;em&gt;can&lt;/em&gt; be run from another directory, by calling them by their full path. Alternatively, we could have added the &lt;code&gt;WPS&lt;/code&gt; and &lt;code&gt;WRF/run&lt;/code&gt; directories to our &lt;code&gt;PATH&lt;/code&gt; variable. However, WRF and WPS expect certain files (tables etc.) in the working directory, so we need to copy those.&lt;/p&gt;
&lt;p&gt;Geogrid and metgrid tables are expected in subfolders, but we can use the namelist setting &lt;code&gt;opt_geogrid_table_path=&apos;.&apos;&lt;/code&gt; (default is &lt;code&gt;&apos;./geogrid&apos;&lt;/code&gt;) to overwrite that, and similar for metgrid. Geogrid will then look in that folder for a file called &lt;code&gt;GEOGRID.TBL&lt;/code&gt;. (Why not simply point to the geogrid table directly in the namelist?)&lt;/p&gt;
&lt;p&gt;We were able to declutter our working directory somewhat by using the namelist.wps options &lt;code&gt;opt_output_from_geogrid_path&lt;/code&gt; and similar for metgrid. Unfortunately, that option is not available for ungrib, the worst clutterer of all… We were able to point &lt;code&gt;real.exe&lt;/code&gt; to our metgrid subfolder through the namelist.input parameter &lt;code&gt;[auxinput1_inname](https://github.com/wrf-model/WRF/blob/0a11865f97680fdd6865b278ea29d910e5db3ed7/run/README.namelist#L89)&lt;/code&gt;, so we could skip that linking step as well.&lt;/p&gt;
&lt;p&gt;We wanted the workflow to fail when one of the steps fails. However, metgrid and geogrid &lt;a href=&quot;https://github.com/wrf-model/WPS/issues/252#issue-2315032244&quot;&gt;don’t fail with a proper exit code&lt;/a&gt;. As a simple patch, we added extra commands to look for errors in the log files and raise an exception when needed.&lt;/p&gt;
&lt;p&gt;Despite some peculiarities, this is a good start. We can already tick some of the items off our wishlist. However, the workflow quickly becomes more complex. For example, as we are adding more experiments, we would like to edit the namelists programmatically. And for some runs, we may want to run an intermediate step (e.g. wudapt-to-wrf). Before we know it, the shell script becomes messy, which defeats our purpose of maintaining a tidy and organized workflow.&lt;/p&gt;
&lt;p&gt;To summarize, the following namelist parameters should probably be much better advertised:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;opt_geogrid_table_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_metgrid_table_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_output_from_geogrid_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_output_from_metgrid_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[auxinput1_inname](https://github.com/wrf-model/WRF/blob/0a11865f97680fdd6865b278ea29d910e5db3ed7/run/README.namelist#L89)&lt;/code&gt; (namelist.input)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a similar option for ungrib, the WRF experience would already be much better.&lt;/p&gt;
&lt;h2 id=&quot;solution-2-using-snakemake&quot;&gt;Solution #2: using Snakemake**&lt;/h2&gt;
&lt;p&gt;Ideally, we want to be able to run only part of a workflow. For example, when &lt;code&gt;real.exe&lt;/code&gt; fails, we don’t want to re-run WPS. Similarly, we may want to run all pre-processing first, and then submit WRF as a batch job.&lt;/p&gt;
&lt;h3 id=&quot;brief-intro-to-snakemake&quot;&gt;Brief intro to Snakemake&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;177&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-ef7a50be.BXCuInXQ_Z1i0EU1.webp&quot; srcset=&quot;&quot;&gt;
Example Snakemake rules (source &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/project_info/faq.html#what-is-the-key-idea-of-snakemake-workflows&quot;&gt;https://snakemake.readthedocs.io/en/stable/project_info/faq.html#what-is-the-key-idea-of-snakemake-workflows&lt;/a&gt;)A snakemake workflow, aka ‘Snakefile’, consists of rules. Each rule has certain inputs and outputs, and the commands to produce that output, either in Python code (a &lt;code&gt;run&lt;/code&gt; block) or as shell commands (a &lt;code&gt;shell&lt;/code&gt; block). When you tell snakemake to produce a certain output file, it will check which rule must executed in order to obtain that file. It does so in a smart way: if the required for a rule input already exists, it will not re-run that rule, unless the input is newer than the output.&lt;/p&gt;
&lt;h3 id=&quot;our-desired-workflow&quot;&gt;Our desired workflow&lt;/h3&gt;
&lt;p&gt;Before we delve into details, let’s have a look at the workflow that we want to achieve. For demonstration purposes I will focus on WPS only. Snakemake provides a command (&lt;code&gt;snakemake --dag WPS | dot -Tpng &amp;#x26;gt; dag.png&lt;/code&gt;) to visualize the task graph for our workflow:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;237&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-1d504248.iij7pUP3_2tEvlr.webp&quot; srcset=&quot;&quot;&gt;
Task graph for our WPS workflow. Boxes (nodes) are rules, arrows indicate dependencies between rules. Dashed lines indicate that these rules have already been executed. Full-line rules still need to be (re)run.As you can see, we want to run four independent experiments. While they share all the same steps, they have a different value for the &lt;code&gt;experiment&lt;/code&gt; setting. This is achieved through the use of a wildcard*.&lt;/p&gt;
&lt;h3 id=&quot;providing-experiment-settings&quot;&gt;Providing experiment settings&lt;/h3&gt;
&lt;p&gt;The values for the wildcard are provided to snakemake via a configuration file. This is a relatively simple file which, in addition to our experiment-specific settings, contains some global settings like &lt;code&gt;wps_home&lt;/code&gt;. Our config file looks like this (only showing the first experiment):&lt;/p&gt;
&lt;p&gt;wps_home: ~/Urban-M4/WPS
wrf_home: ~/Urban-M4/WRF
data_home: /projects/0/prjs0914/wrf-data/default
working_directory: ./output&lt;/p&gt;
&lt;p&gt;experiments:
usgs:
geog_data_res: [‘usgs_30s’,‘usgs_30s’,‘usgs_30s’,‘usgs_30s’]
geog_data_path: ‘/projects/0/prjs0914/wrf-data/default/static/summerinthecity’
geogrid_table: GEOGRID.TBL.ARW_USGS
use_wudapt_lcz: false
num_land_cat: 24
modis_lcz:
…The config file is read at the very top of the Snakefile, like so:&lt;/p&gt;
&lt;p&gt;configfile: workflow.source_path(“config.yaml”)The first rule in our workflow, &lt;code&gt;UPDATE_NAMELIST_WPS&lt;/code&gt;, uses a python package &lt;code&gt;[f90nml](https://f90nml.readthedocs.io/en/latest/)&lt;/code&gt; to load a reference namelist.wps, modify the settings as specified in the experiment configuration, and store the updated namelist in the output folder for that experiment. It looks like this:&lt;/p&gt;
&lt;p&gt;rule UPDATE_NAMELIST_WPS:
input:
namelist_wps = workflow.source_path(“namelist.wps”)
output:
“{experiment}/namelist.wps”,
run:
# Get parameters from config
geog_data_res = config[‘experiments’][wildcards.experiment][‘geog_data_res’]
geog_data_path = config[‘experiments’][wildcards.experiment][‘geog_data_path’]&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Read source namelist.wps with f90nml, make some changes, and save in experiment dir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml = f90nml.read(input.namelist_wps)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_path&quot;] = geog_data_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_res&quot;] = geog_data_res&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml.write(f&quot;{wildcards.experiment}/namelist.wps&quot;)Notice that we are reading the reference namelist form the workflow source path. This is because it is stored alongside the snakefile. Normally, all paths in snakemake are relative to the working directory.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, this rule works for any value of the &lt;code&gt;experiment&lt;/code&gt; wildcard (as long as the settings are provided in the configuration file). To invoke the rule for each of our experiments, we use a target rule, like so:&lt;/p&gt;
&lt;p&gt;rule PRODUCE_ALL_NAMELISTS:
input: collect(“{experiment}/namelist.wps”, experiment=config[“experiments”].keys())The &lt;code&gt;collect&lt;/code&gt; function fills the values of &lt;code&gt;experiment&lt;/code&gt; with all keys found in &lt;code&gt;config[&quot;experiments&quot;]&lt;/code&gt;. When we invoke this target rule, e.g. by running &lt;code&gt;snakemake PRODUCE_ALL_NAMELISTS&lt;/code&gt;, Snakemake will look for a rule that can produc the following files (unless they already exist):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;usgs/namelist.wps&lt;/li&gt;
&lt;li&gt;modis_lcz/namelist.wps&lt;/li&gt;
&lt;li&gt;wur/namelist.wps&lt;/li&gt;
&lt;li&gt;wur_lcz/namelist.wps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It will find &lt;code&gt;UPDATE_NAMELIST_WPS&lt;/code&gt;and invoke this rule, inferring that the first segment corresponds to the value of the wildcard.&lt;/p&gt;
&lt;h3 id=&quot;specifying-the-other-steps&quot;&gt;Specifying the other steps&lt;/h3&gt;
&lt;p&gt;Getting Snakemake to use the different experiment settings was by far the most involved part of our journey. Next, we want to add rules for all the other steps. For example, out METGRID rule looks as follows:&lt;/p&gt;
&lt;p&gt;rule METGRID:
input:
“{experiment}/namelist.wps”,
“{experiment}/finished.ungrib”,
“{experiment}/finished.geogrid”,
output: “{experiment}/finished.metgrid”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p metgrid&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/metgrid/METGRID.TBL.ARW METGRID.TBL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/metgrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (metgrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; metgrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in metgrid.log. &quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.metgrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;Snakemake infers the dependecies between rules via their input and output filenames. Since WPS output filenames are not predictable without parsing the namelist, we opted for a workaround: at the end of each rule, we create an empty file called `finished.&amp;#x26;lt;rule&amp;#x26;gt;`. As such, we inform Snakemake that metgrid must be run after updating the namelist, and after geogrid and ungrib.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As opposed to the first rule, which executes Python code (a &lt;code&gt;run&lt;/code&gt; block), here we use shell commands. This is nice, because it is very similar to what you would do manually on the command line. As an intermediate option we can use &lt;code&gt;params&lt;/code&gt;. We use this in our &lt;code&gt;GEOGRID&lt;/code&gt; rule:&lt;/p&gt;
&lt;p&gt;rule GEOGRID:
input: “{experiment}/namelist.wps”,
output: “{experiment}/finished.geogrid”
params: geogrid_table = lambda wildcards: workflow.source_path(config[‘experiments’][wildcards.experiment][‘geogrid_table’]),
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p geogrid
cp {params.geogrid_table} GEOGRID.TBL&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/geogrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (geogrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;The use of params enables us to execute some Python code to assign a value to a variable, which can then be accessed in the shell block of the rule. Here, we get the `geogrid_table` from our experiment config. So we can combine the flexibility of Python with the transparancy of plain shell commands.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;final-workflow&quot;&gt;Final workflow&lt;/h3&gt;
&lt;p&gt;Putting everything together, our full workflow looks something like below. Notice that &lt;code&gt;WPS&lt;/code&gt; is the target rule in this case.&lt;/p&gt;
&lt;p&gt;import os
from pathlib import Path&lt;/p&gt;
&lt;p&gt;import f90nml&lt;/p&gt;
&lt;p&gt;configfile: workflow.source_path(“config.yaml”)
workdir: config[“working_directory”]
envvars: “NETCDF”&lt;/p&gt;
&lt;p&gt;rule UPDATE_NAMELIST_WPS:
input:
namelist_wps = workflow.source_path(“namelist.wps”)
output:
“{experiment}/namelist.wps”,
run:
# Get parameters from config
geog_data_res = config[‘experiments’][wildcards.experiment][‘geog_data_res’]
geog_data_path = config[‘experiments’][wildcards.experiment][‘geog_data_path’]&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Read source namelist.wps with f90nml, make some changes, and save in experiment dir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml = f90nml.read(input.namelist_wps)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_path&quot;] = geog_data_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_res&quot;] = geog_data_res&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml.write(f&quot;{wildcards.experiment}/namelist.wps&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule GEOGRID:
input: “{experiment}/namelist.wps”,
output: “{experiment}/finished.geogrid”
params: geogrid_table = lambda wildcards: workflow.source_path(config[‘experiments’][wildcards.experiment][‘geogrid_table’]),
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p geogrid
cp {params.geogrid_table} GEOGRID.TBL&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/geogrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (geogrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule UNGRIB:
input: “{experiment}/namelist.wps”
output: “{experiment}/finished.ungrib”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Remove old output if present (ungrib doesn&apos;t like to overwrite stuff)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    rm -f FILE*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Link vtable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/ungrib/Variable_Tables/Vtable.ECMWF Vtable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Link gribfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/link_grib.csh {config[data_home]}/real-time/july2019/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run ungrib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/ungrib.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (ungrib can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; ungrib.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in ungrib.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Report ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.ungrib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule METGRID:
input:
“{experiment}/namelist.wps”,
“{experiment}/finished.ungrib”,
“{experiment}/finished.geogrid”,
output: “{experiment}/finished.metgrid”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p metgrid&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/metgrid/METGRID.TBL.ARW METGRID.TBL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/metgrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (metgrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; metgrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in metgrid.log. &quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.metgrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule WPS:
input: collect(“{experiment}/finished.metgrid”, experiment=config[“experiments”].keys())We’re steadily accumulating lines of code, but overall, we’re quite happy with how interpretable this still looks. As we develop this further, it would be good to split it up into multiple files, and incorporate other best practices as outlined in the &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/snakefiles/best_practices.html&quot;&gt;Snakemake documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;struggles&quot;&gt;Struggles&lt;/h3&gt;
&lt;p&gt;While we’re quite happy with our progress so far, here are some things that we struggled with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flexibility of output directories: we want to organize our output as follows: &lt;code&gt;./results/{experiment}&lt;/code&gt;. By default, all paths are relative to the working directory. We set the working directory to &lt;code&gt;./results&lt;/code&gt;, so the first rule, &lt;code&gt;UPDATE_NAMELIST&lt;/code&gt;, will actually create the file &lt;code&gt;./results/{experiment}/namelist.wps&lt;/code&gt;. Unfortunately, snakemake cannot use wildcards for the working directory. Therefore, we need to &lt;code&gt;cd&lt;/code&gt; to the experiment directory in every rule.&lt;/li&gt;
&lt;li&gt;Complex input/output: the output of WPS programs depends on the settings in namelist.wps. Specifically, filenames like &lt;code&gt;met_em.d03.2019...&lt;/code&gt; encode information about the domain and (a lot of) dates. We could use something like &lt;code&gt;output: expand(&quot;met_em.{domain}.{datetime}.nc&quot;, domain=DOMAINS, datetime=DATETIMES)&lt;/code&gt;. For that to work, we’d need to set &lt;code&gt;DOMAINS&lt;/code&gt; and &lt;code&gt;DATETIMES&lt;/code&gt; in the configuration file, or infer them from the template namelist.wps. Not ideal, and quickly getting complex.&lt;/li&gt;
&lt;li&gt;Atomic inputs/outputs: a bit of a stretch goal, but when using a workflow manager like this, it would be nice if you could do, for example, &lt;code&gt;metgrid.exe --domain=1 --date=20190101&lt;/code&gt;. This way, when only one domain/timestamp needs to be re-processed, we don’t need to re-run the workflow for everything else as well. However, this means some of the logic that’s currently encoded in WPS programs, specifically parsing the domain and time control sections of the namelist and looping over them, is moved entirely to the workflow. Do we really want to go down that path?&lt;/li&gt;
&lt;li&gt;Shared input/output: now, we’re saving the output of each experiment in a dedicated directory. However, there is quite some duplication. Instead, we could store WPS output in a shared directory. But what happens if two namelists with different settings create the same file &lt;code&gt;geo_em.d01.nc&lt;/code&gt;? We would need to encode the WPS configuration in the path somehow, e.g. &lt;code&gt;geogrid/usgs**/geo_em.d01.nc&lt;/code&gt; and &lt;code&gt;ungrib/**ifs**/FILE:20190101&lt;/code&gt; combine to create &lt;code&gt;metgrid/**usgs/ifs**/met_em...&lt;/code&gt;. This is currently not possible since the ungrib directory is not configurable.&lt;/li&gt;
&lt;li&gt;SLURM: snakemake can submit workflows to a batch scheduler like slurm through a plugin. However, we found it to be very cumbersome. For example, we found the main Snakemake program was hanging often and did not seem to check for status; online help often referred to old versions; you can mark jobs for local execution when slurm is the default, but not vice versa as we would have preferred; the working directory was not respected; we had to carefully reinitialize the environment; et cetera. Eventually it seemed easier to wrap the entire Snakemake workflow in a batch script and submit that to slurm, but this is also suboptimal, especially since we cannot differentiate between resources for eacht task then.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;verdict&quot;&gt;Verdict&lt;/h3&gt;
&lt;p&gt;Some of these things can probably be solved by digging further into the inner workings of Snakemake. At the same time, we’re conscious of the complexity of our workflow. If it takes more time to build and maintain it than it would take to do the tedious manual bookkeeping, is it really worth the effort?&lt;/p&gt;
&lt;p&gt;Hopefully yes: reproducibility is important, and perhaps others can benefit as well. For now, however, we need to focus on the results for a bit. So let’s do a quick recap and call it a day.&lt;/p&gt;
&lt;p&gt;If you want to follow our progress, keep an eye on our repository &lt;a href=&quot;https://github.com/Urban-M4/snakemake-wrf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;We’ve experimented with different options for managing WRF workflows. With a few tweaks, we were able to tackle many of our initial painpoints. Once we got the hang of it, we quite liked the flexibility of Snakemake and its promise of reproducible experiment sets. However, while we aimed for something simple, we found that our solutions quickly grew complex as we tried to bend the tools to our will.&lt;/p&gt;
&lt;p&gt;There’s a few peculiarities about WRF that were very much in the way. For example, that we couldn’t specify the ungrib directory. In terms of compatibility with Snakemake, it would be nice if WRF was less dependent on the current working directory, and/or if Snakemake’s working directory would be able to adapt to wildcard values.&lt;/p&gt;
&lt;p&gt;Perhaps the main conclusion should be that organizing your (WRF) workflows is not as straightforward as it may seem. This is something that many people must struggle with. And while there’s plenty of resources on the WRF documentation and user forum, “how to manage your workflow” does not seem to get the attention it deserves.&lt;/p&gt;
&lt;p&gt;How do you manage your workflows? Please share your tips and tricks in the comments or in any other way that you see fit.&lt;/p&gt;</description><pubDate>Thu, 05 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;unwieldy-workflows-with-wrf&quot;&gt;&lt;strong&gt;(Un)wieldy workflows with WRF&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;streamlining-experiments-with-the-weather-research-and-forecasting-model&quot;&gt;&lt;strong&gt;Streamlining experiments with the Weather Research and Forecasting model&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.mmm.ucar.edu/models/wrf&quot;&gt;Weather Research and Forecasting model&lt;/a&gt;, WRF for short, is a beautiful piece of research software with a large community of active users. That’s something we love and advocate for at the eScience Center.&lt;/p&gt;
&lt;p&gt;Given its large user base, one might think this must be an exemplary model to work with. And perhaps it is, in comparison to other models in the scene. But as I’m working with WRF again after several years, I’m reminded of my struggles in keeping my workflows organized.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;386&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-b6e59d0c.B5Z5PUNe_Z1p8i5Q.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@hdbernd?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Bernd 📷 Dittrich&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To try and tackle this issue once and for all, we experimented with different solutions, including a simple shell script, as well as &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/&quot;&gt;Snakemake&lt;/a&gt;, a python-based workflow management tool often used in bioinformatics. Both approaches turn out to have their own merits and quirks.&lt;/p&gt;
&lt;p&gt;Overall, we did get a better grip on the antipatterns that prevented us from keeping a nice and orderly workflow. From this, we extracted some best practices for managing complex (WRF) modelling workflows. This blogpost documents our journey and the lessons learned, in the hope that it will be useful for other WRF users and those who struggle with managing their experiments.&lt;/p&gt;
&lt;h2 id=&quot;running-basic-wrf&quot;&gt;Running basic WRF**&lt;/h2&gt;
&lt;p&gt;Let’s start with an overview of the steps required to run a basic WRF (real data) experiment, as per the instructions in the &lt;a href=&quot;https://www2.mmm.ucar.edu/wrf/users/wrf_users_guide/build/html/wps.html&quot;&gt;user guide&lt;/a&gt;. First you must run the WRF preprocessing system (WPS), which itself consists of three programs: geogrid, ungrib, and metgrid. Then you run WRF itself, which also consists of two programs: real and wrf.&lt;/p&gt;
&lt;p&gt;cd WPS**&lt;/p&gt;
&lt;h1 id=&quot;run-geogrid-interpolate-spatial-datasets-to-the-model-grid&quot;&gt;Run geogrid (interpolate spatial datasets to the model grid)&lt;/h1&gt;
&lt;p&gt;./geogrid.exe&lt;/p&gt;
&lt;h1 id=&quot;run-ungrib-unpack-meteorological-input-data&quot;&gt;Run ungrib (unpack meteorological input data)&lt;/h1&gt;
&lt;p&gt;./link_grib.csh /your/meteo/data/dir
ln -s ungrib/Variable_Tables/Vtable.GFS Vtable
./ungrib.exe&lt;/p&gt;
&lt;h1 id=&quot;run-metgrid-interpolate-the-meteo-data-to-model-grid&quot;&gt;Run metgrid (interpolate the meteo data to model grid)&lt;/h1&gt;
&lt;p&gt;./metgrid.exe&lt;/p&gt;
&lt;p&gt;cd ../WRF/run&lt;/p&gt;
&lt;h1 id=&quot;run-real-extract-initial-and-boundary-fields-from-preprocessed-data&quot;&gt;Run real (extract initial and boundary fields from preprocessed data)&lt;/h1&gt;
&lt;p&gt;ln -sf ../../WPS/met_em* .
./real.exe&lt;/p&gt;
&lt;h1 id=&quot;run-wrf-the-actual-forecast&quot;&gt;Run WRF (the actual forecast)&lt;/h1&gt;
&lt;p&gt;./wrf.exeThis workflow is not great in several ways. WRF and WPS are run in different working directories; yet they “pretend” to be in the same directory by use of symbolic links (&lt;code&gt;ln&lt;/code&gt;). Also, exectuables are in the same directory as the input/output data. Now, imagine, for example, that we want to do multiple experiments with slightly different settings.&lt;/p&gt;
&lt;p&gt;One option would be to move the output to a separate directory between each run. We would need to meticulously bookkeep our files, especially since runs may fail at different stages causing us to re-run (part of) the workflow. Also, we would not be able run the experiments in parallel. Clearly, using WRF in this way is a labour-intensive, error-prone process.&lt;/p&gt;
&lt;p&gt;Alternatively, we could duplicate our &lt;code&gt;WPS&lt;/code&gt;and &lt;code&gt;WRF/run&lt;/code&gt;directories. That’s also not great: imagine we want to re-run our experiments with a re-compiled version of WRF. Then we would need to copy over the new executables to all experiment directories.&lt;/p&gt;
&lt;p&gt;Finally, there’s lots of files in these directories that are not needed for our experiments, which makes it hard to tell the wheat from the chaff.&lt;/p&gt;
&lt;h3 id=&quot;our-workflow-wishlist&quot;&gt;Our workflow wishlist**&lt;/h3&gt;
&lt;p&gt;Considering the points above, let’s think about how we would like it to be, and start a workflow wishlist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each/all experiment(s) can be re-run with a single command&lt;/li&gt;
&lt;li&gt;One directory per experiment, containing config + output&lt;/li&gt;
&lt;li&gt;Intermediate/output data well organized in subdirectories&lt;/li&gt;
&lt;li&gt;Config files (namelists) specify paths to all relevant input data; no links&lt;/li&gt;
&lt;li&gt;Executables should be in a system path or another dedicated location&lt;/li&gt;
&lt;li&gt;We should be able to (re-)run only part of a workflow&lt;/li&gt;
&lt;li&gt;Bonus: reuse intermediate files that are the same for all experiments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution-1-using-a-shell-script&quot;&gt;&lt;strong&gt;Solution #1: using a shell script&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Let’s see how far we can get with a simple shell script. In this example, we maintain multiple namelists and geogrid tables for each experiment. These are stored alongside the shell script and copied over to the experiment folder once the script is run. The full code is available &lt;a href=&quot;https://github.com/Urban-M4/wrf-runner&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;some-initialization-of-the-environment-module-loads-etc-&quot;&gt;Some initialization of the environment, module loads etc.**# …&lt;/h1&gt;
&lt;h1 id=&quot;set-path-to-executables&quot;&gt;Set path to executables&lt;/h1&gt;
&lt;p&gt;WPS_HOME=&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;HOME/wrf-model/WPS
WRF_HOME=&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;HOME/wrf-model/WRF&lt;/p&gt;
&lt;h1 id=&quot;define-experiment-name&quot;&gt;Define experiment name&lt;/h1&gt;
&lt;p&gt;EXP=USGS&lt;/p&gt;
&lt;h1 id=&quot;make-new-experiment-directory&quot;&gt;Make new experiment directory&lt;/h1&gt;
&lt;p&gt;export RUNDIR=wrf_experiments/&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{EXP}
mkdir -p &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR
mkdir &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;D&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RUNDIR/geogrid
mkdir &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;eo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;mk&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/metgrid&lt;/p&gt;
&lt;h1 id=&quot;copy-experiment-dependent-files&quot;&gt;Copy experiment-dependent files&lt;/h1&gt;
&lt;p&gt;cp namelist.wps_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/namelist.wps
cp namelist.input_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/namelist.input
cp GEOGRID.TBL.ARW_&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;EXP &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RUNDIR/GEOGRID.TBL&lt;/p&gt;
&lt;h1 id=&quot;copy-additional-input-files-from-wrfwps&quot;&gt;Copy additional input files from WRF/WPS&lt;/h1&gt;
&lt;p&gt;cd &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;D&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RUNDIR
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WPS_HOME/metgrid/METGRID.TBL.ARW METGRID.TBL
cp &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WPS_HOME/ungrid/Variable_Tables/Vtable.ECMWF VTable
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;iab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/CAMtr_volume_mixing_ratio.RCP8.5 CAMtr_volume_mixing_ratio
cp &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WRF_HOME/run/ozone* .
cp &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;oz&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/RRTMG* .
cp $WRF_HOME/run/*.TBL .&lt;/p&gt;
&lt;h1 id=&quot;run-experiments&quot;&gt;Run experiments&lt;/h1&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WPS_HOME/link_grib.csh &quot;path/to/our/input/data/*&quot;
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0361em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0315em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ib&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WPS_HOME/ungrib.exe
&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;&amp;#x26;&amp;#x27; at position 47: …R&amp;#x22; geogrid.log &amp;#x26;̲amp;&amp;#x26;amp; echo …&quot; style=&quot;color:#cc0000&quot;&gt;WPS_HOME/geogrid.exe
grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1
&lt;/span&gt;WPS_HOME/metgrid.exe
grep “ERROR” metgrid.log &amp;#x26;&amp;#x26; echo “Aborting: ERROR in metgrid.log.” &amp;#x26;&amp;#x26; exit 1&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;WRF_HOME/run/real.exe
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;WRF_HOME/run/wrf.exeEvidently, WRF and WPS &lt;em&gt;can&lt;/em&gt; be run from another directory, by calling them by their full path. Alternatively, we could have added the &lt;code&gt;WPS&lt;/code&gt; and &lt;code&gt;WRF/run&lt;/code&gt; directories to our &lt;code&gt;PATH&lt;/code&gt; variable. However, WRF and WPS expect certain files (tables etc.) in the working directory, so we need to copy those.&lt;/p&gt;
&lt;p&gt;Geogrid and metgrid tables are expected in subfolders, but we can use the namelist setting &lt;code&gt;opt_geogrid_table_path=&apos;.&apos;&lt;/code&gt; (default is &lt;code&gt;&apos;./geogrid&apos;&lt;/code&gt;) to overwrite that, and similar for metgrid. Geogrid will then look in that folder for a file called &lt;code&gt;GEOGRID.TBL&lt;/code&gt;. (Why not simply point to the geogrid table directly in the namelist?)&lt;/p&gt;
&lt;p&gt;We were able to declutter our working directory somewhat by using the namelist.wps options &lt;code&gt;opt_output_from_geogrid_path&lt;/code&gt; and similar for metgrid. Unfortunately, that option is not available for ungrib, the worst clutterer of all… We were able to point &lt;code&gt;real.exe&lt;/code&gt; to our metgrid subfolder through the namelist.input parameter &lt;code&gt;[auxinput1_inname](https://github.com/wrf-model/WRF/blob/0a11865f97680fdd6865b278ea29d910e5db3ed7/run/README.namelist#L89)&lt;/code&gt;, so we could skip that linking step as well.&lt;/p&gt;
&lt;p&gt;We wanted the workflow to fail when one of the steps fails. However, metgrid and geogrid &lt;a href=&quot;https://github.com/wrf-model/WPS/issues/252#issue-2315032244&quot;&gt;don’t fail with a proper exit code&lt;/a&gt;. As a simple patch, we added extra commands to look for errors in the log files and raise an exception when needed.&lt;/p&gt;
&lt;p&gt;Despite some peculiarities, this is a good start. We can already tick some of the items off our wishlist. However, the workflow quickly becomes more complex. For example, as we are adding more experiments, we would like to edit the namelists programmatically. And for some runs, we may want to run an intermediate step (e.g. wudapt-to-wrf). Before we know it, the shell script becomes messy, which defeats our purpose of maintaining a tidy and organized workflow.&lt;/p&gt;
&lt;p&gt;To summarize, the following namelist parameters should probably be much better advertised:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;opt_geogrid_table_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_metgrid_table_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_output_from_geogrid_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt_output_from_metgrid_path&lt;/code&gt; (namelist.wps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[auxinput1_inname](https://github.com/wrf-model/WRF/blob/0a11865f97680fdd6865b278ea29d910e5db3ed7/run/README.namelist#L89)&lt;/code&gt; (namelist.input)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a similar option for ungrib, the WRF experience would already be much better.&lt;/p&gt;
&lt;h2 id=&quot;solution-2-using-snakemake&quot;&gt;Solution #2: using Snakemake**&lt;/h2&gt;
&lt;p&gt;Ideally, we want to be able to run only part of a workflow. For example, when &lt;code&gt;real.exe&lt;/code&gt; fails, we don’t want to re-run WPS. Similarly, we may want to run all pre-processing first, and then submit WRF as a batch job.&lt;/p&gt;
&lt;h3 id=&quot;brief-intro-to-snakemake&quot;&gt;Brief intro to Snakemake&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;177&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-ef7a50be.BXCuInXQ_Z1i0EU1.webp&quot; srcset=&quot;&quot;&gt;
Example Snakemake rules (source &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/project_info/faq.html#what-is-the-key-idea-of-snakemake-workflows&quot;&gt;https://snakemake.readthedocs.io/en/stable/project_info/faq.html#what-is-the-key-idea-of-snakemake-workflows&lt;/a&gt;)A snakemake workflow, aka ‘Snakefile’, consists of rules. Each rule has certain inputs and outputs, and the commands to produce that output, either in Python code (a &lt;code&gt;run&lt;/code&gt; block) or as shell commands (a &lt;code&gt;shell&lt;/code&gt; block). When you tell snakemake to produce a certain output file, it will check which rule must executed in order to obtain that file. It does so in a smart way: if the required for a rule input already exists, it will not re-run that rule, unless the input is newer than the output.&lt;/p&gt;
&lt;h3 id=&quot;our-desired-workflow&quot;&gt;Our desired workflow&lt;/h3&gt;
&lt;p&gt;Before we delve into details, let’s have a look at the workflow that we want to achieve. For demonstration purposes I will focus on WPS only. Snakemake provides a command (&lt;code&gt;snakemake --dag WPS | dot -Tpng &amp;#x26;gt; dag.png&lt;/code&gt;) to visualize the task graph for our workflow:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;(Un)wieldy workflows with WRF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;237&quot; src=&quot;https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-1d504248.iij7pUP3_2tEvlr.webp&quot; srcset=&quot;&quot;&gt;
Task graph for our WPS workflow. Boxes (nodes) are rules, arrows indicate dependencies between rules. Dashed lines indicate that these rules have already been executed. Full-line rules still need to be (re)run.As you can see, we want to run four independent experiments. While they share all the same steps, they have a different value for the &lt;code&gt;experiment&lt;/code&gt; setting. This is achieved through the use of a wildcard*.&lt;/p&gt;
&lt;h3 id=&quot;providing-experiment-settings&quot;&gt;Providing experiment settings&lt;/h3&gt;
&lt;p&gt;The values for the wildcard are provided to snakemake via a configuration file. This is a relatively simple file which, in addition to our experiment-specific settings, contains some global settings like &lt;code&gt;wps_home&lt;/code&gt;. Our config file looks like this (only showing the first experiment):&lt;/p&gt;
&lt;p&gt;wps_home: ~/Urban-M4/WPS
wrf_home: ~/Urban-M4/WRF
data_home: /projects/0/prjs0914/wrf-data/default
working_directory: ./output&lt;/p&gt;
&lt;p&gt;experiments:
usgs:
geog_data_res: [‘usgs_30s’,‘usgs_30s’,‘usgs_30s’,‘usgs_30s’]
geog_data_path: ‘/projects/0/prjs0914/wrf-data/default/static/summerinthecity’
geogrid_table: GEOGRID.TBL.ARW_USGS
use_wudapt_lcz: false
num_land_cat: 24
modis_lcz:
…The config file is read at the very top of the Snakefile, like so:&lt;/p&gt;
&lt;p&gt;configfile: workflow.source_path(“config.yaml”)The first rule in our workflow, &lt;code&gt;UPDATE_NAMELIST_WPS&lt;/code&gt;, uses a python package &lt;code&gt;[f90nml](https://f90nml.readthedocs.io/en/latest/)&lt;/code&gt; to load a reference namelist.wps, modify the settings as specified in the experiment configuration, and store the updated namelist in the output folder for that experiment. It looks like this:&lt;/p&gt;
&lt;p&gt;rule UPDATE_NAMELIST_WPS:
input:
namelist_wps = workflow.source_path(“namelist.wps”)
output:
“{experiment}/namelist.wps”,
run:
# Get parameters from config
geog_data_res = config[‘experiments’][wildcards.experiment][‘geog_data_res’]
geog_data_path = config[‘experiments’][wildcards.experiment][‘geog_data_path’]&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Read source namelist.wps with f90nml, make some changes, and save in experiment dir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml = f90nml.read(input.namelist_wps)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_path&quot;] = geog_data_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_res&quot;] = geog_data_res&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml.write(f&quot;{wildcards.experiment}/namelist.wps&quot;)Notice that we are reading the reference namelist form the workflow source path. This is because it is stored alongside the snakefile. Normally, all paths in snakemake are relative to the working directory.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, this rule works for any value of the &lt;code&gt;experiment&lt;/code&gt; wildcard (as long as the settings are provided in the configuration file). To invoke the rule for each of our experiments, we use a target rule, like so:&lt;/p&gt;
&lt;p&gt;rule PRODUCE_ALL_NAMELISTS:
input: collect(“{experiment}/namelist.wps”, experiment=config[“experiments”].keys())The &lt;code&gt;collect&lt;/code&gt; function fills the values of &lt;code&gt;experiment&lt;/code&gt; with all keys found in &lt;code&gt;config[&quot;experiments&quot;]&lt;/code&gt;. When we invoke this target rule, e.g. by running &lt;code&gt;snakemake PRODUCE_ALL_NAMELISTS&lt;/code&gt;, Snakemake will look for a rule that can produc the following files (unless they already exist):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;usgs/namelist.wps&lt;/li&gt;
&lt;li&gt;modis_lcz/namelist.wps&lt;/li&gt;
&lt;li&gt;wur/namelist.wps&lt;/li&gt;
&lt;li&gt;wur_lcz/namelist.wps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It will find &lt;code&gt;UPDATE_NAMELIST_WPS&lt;/code&gt;and invoke this rule, inferring that the first segment corresponds to the value of the wildcard.&lt;/p&gt;
&lt;h3 id=&quot;specifying-the-other-steps&quot;&gt;Specifying the other steps&lt;/h3&gt;
&lt;p&gt;Getting Snakemake to use the different experiment settings was by far the most involved part of our journey. Next, we want to add rules for all the other steps. For example, out METGRID rule looks as follows:&lt;/p&gt;
&lt;p&gt;rule METGRID:
input:
“{experiment}/namelist.wps”,
“{experiment}/finished.ungrib”,
“{experiment}/finished.geogrid”,
output: “{experiment}/finished.metgrid”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p metgrid&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/metgrid/METGRID.TBL.ARW METGRID.TBL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/metgrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (metgrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; metgrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in metgrid.log. &quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.metgrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;Snakemake infers the dependecies between rules via their input and output filenames. Since WPS output filenames are not predictable without parsing the namelist, we opted for a workaround: at the end of each rule, we create an empty file called `finished.&amp;#x26;lt;rule&amp;#x26;gt;`. As such, we inform Snakemake that metgrid must be run after updating the namelist, and after geogrid and ungrib.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As opposed to the first rule, which executes Python code (a &lt;code&gt;run&lt;/code&gt; block), here we use shell commands. This is nice, because it is very similar to what you would do manually on the command line. As an intermediate option we can use &lt;code&gt;params&lt;/code&gt;. We use this in our &lt;code&gt;GEOGRID&lt;/code&gt; rule:&lt;/p&gt;
&lt;p&gt;rule GEOGRID:
input: “{experiment}/namelist.wps”,
output: “{experiment}/finished.geogrid”
params: geogrid_table = lambda wildcards: workflow.source_path(config[‘experiments’][wildcards.experiment][‘geogrid_table’]),
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p geogrid
cp {params.geogrid_table} GEOGRID.TBL&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/geogrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (geogrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;The use of params enables us to execute some Python code to assign a value to a variable, which can then be accessed in the shell block of the rule. Here, we get the `geogrid_table` from our experiment config. So we can combine the flexibility of Python with the transparancy of plain shell commands.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;final-workflow&quot;&gt;Final workflow&lt;/h3&gt;
&lt;p&gt;Putting everything together, our full workflow looks something like below. Notice that &lt;code&gt;WPS&lt;/code&gt; is the target rule in this case.&lt;/p&gt;
&lt;p&gt;import os
from pathlib import Path&lt;/p&gt;
&lt;p&gt;import f90nml&lt;/p&gt;
&lt;p&gt;configfile: workflow.source_path(“config.yaml”)
workdir: config[“working_directory”]
envvars: “NETCDF”&lt;/p&gt;
&lt;p&gt;rule UPDATE_NAMELIST_WPS:
input:
namelist_wps = workflow.source_path(“namelist.wps”)
output:
“{experiment}/namelist.wps”,
run:
# Get parameters from config
geog_data_res = config[‘experiments’][wildcards.experiment][‘geog_data_res’]
geog_data_path = config[‘experiments’][wildcards.experiment][‘geog_data_path’]&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Read source namelist.wps with f90nml, make some changes, and save in experiment dir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml = f90nml.read(input.namelist_wps)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_path&quot;] = geog_data_path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml[&quot;geogrid&quot;][&quot;geog_data_res&quot;] = geog_data_res&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nml.write(f&quot;{wildcards.experiment}/namelist.wps&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule GEOGRID:
input: “{experiment}/namelist.wps”,
output: “{experiment}/finished.geogrid”
params: geogrid_table = lambda wildcards: workflow.source_path(config[‘experiments’][wildcards.experiment][‘geogrid_table’]),
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p geogrid
cp {params.geogrid_table} GEOGRID.TBL&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/geogrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (geogrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; geogrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in geogrid.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.geogrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule UNGRIB:
input: “{experiment}/namelist.wps”
output: “{experiment}/finished.ungrib”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Remove old output if present (ungrib doesn&apos;t like to overwrite stuff)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    rm -f FILE*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Link vtable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/ungrib/Variable_Tables/Vtable.ECMWF Vtable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Link gribfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/link_grib.csh {config[data_home]}/real-time/july2019/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Run ungrib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/ungrib.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (ungrib can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; ungrib.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in ungrib.log.&quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Report ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.ungrib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule METGRID:
input:
“{experiment}/namelist.wps”,
“{experiment}/finished.ungrib”,
“{experiment}/finished.geogrid”,
output: “{experiment}/finished.metgrid”
shell:
&quot;&quot;&quot;
cd {wildcards.experiment}
mkdir -p metgrid&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cp {config[wps_home]}/metgrid/METGRID.TBL.ARW METGRID.TBL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {config[wps_home]}/metgrid.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # Scan logfile for errors and raise if necessary (metgrid can fail silently with 0 exit status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    grep &quot;ERROR&quot; metgrid.log &amp;#x26;amp;&amp;#x26;amp; echo &quot;Aborting: ERROR in metgrid.log. &quot; &amp;#x26;amp;&amp;#x26;amp; exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    touch finished.metgrid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule WPS:
input: collect(“{experiment}/finished.metgrid”, experiment=config[“experiments”].keys())We’re steadily accumulating lines of code, but overall, we’re quite happy with how interpretable this still looks. As we develop this further, it would be good to split it up into multiple files, and incorporate other best practices as outlined in the &lt;a href=&quot;https://snakemake.readthedocs.io/en/stable/snakefiles/best_practices.html&quot;&gt;Snakemake documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;struggles&quot;&gt;Struggles&lt;/h3&gt;
&lt;p&gt;While we’re quite happy with our progress so far, here are some things that we struggled with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flexibility of output directories: we want to organize our output as follows: &lt;code&gt;./results/{experiment}&lt;/code&gt;. By default, all paths are relative to the working directory. We set the working directory to &lt;code&gt;./results&lt;/code&gt;, so the first rule, &lt;code&gt;UPDATE_NAMELIST&lt;/code&gt;, will actually create the file &lt;code&gt;./results/{experiment}/namelist.wps&lt;/code&gt;. Unfortunately, snakemake cannot use wildcards for the working directory. Therefore, we need to &lt;code&gt;cd&lt;/code&gt; to the experiment directory in every rule.&lt;/li&gt;
&lt;li&gt;Complex input/output: the output of WPS programs depends on the settings in namelist.wps. Specifically, filenames like &lt;code&gt;met_em.d03.2019...&lt;/code&gt; encode information about the domain and (a lot of) dates. We could use something like &lt;code&gt;output: expand(&quot;met_em.{domain}.{datetime}.nc&quot;, domain=DOMAINS, datetime=DATETIMES)&lt;/code&gt;. For that to work, we’d need to set &lt;code&gt;DOMAINS&lt;/code&gt; and &lt;code&gt;DATETIMES&lt;/code&gt; in the configuration file, or infer them from the template namelist.wps. Not ideal, and quickly getting complex.&lt;/li&gt;
&lt;li&gt;Atomic inputs/outputs: a bit of a stretch goal, but when using a workflow manager like this, it would be nice if you could do, for example, &lt;code&gt;metgrid.exe --domain=1 --date=20190101&lt;/code&gt;. This way, when only one domain/timestamp needs to be re-processed, we don’t need to re-run the workflow for everything else as well. However, this means some of the logic that’s currently encoded in WPS programs, specifically parsing the domain and time control sections of the namelist and looping over them, is moved entirely to the workflow. Do we really want to go down that path?&lt;/li&gt;
&lt;li&gt;Shared input/output: now, we’re saving the output of each experiment in a dedicated directory. However, there is quite some duplication. Instead, we could store WPS output in a shared directory. But what happens if two namelists with different settings create the same file &lt;code&gt;geo_em.d01.nc&lt;/code&gt;? We would need to encode the WPS configuration in the path somehow, e.g. &lt;code&gt;geogrid/usgs**/geo_em.d01.nc&lt;/code&gt; and &lt;code&gt;ungrib/**ifs**/FILE:20190101&lt;/code&gt; combine to create &lt;code&gt;metgrid/**usgs/ifs**/met_em...&lt;/code&gt;. This is currently not possible since the ungrib directory is not configurable.&lt;/li&gt;
&lt;li&gt;SLURM: snakemake can submit workflows to a batch scheduler like slurm through a plugin. However, we found it to be very cumbersome. For example, we found the main Snakemake program was hanging often and did not seem to check for status; online help often referred to old versions; you can mark jobs for local execution when slurm is the default, but not vice versa as we would have preferred; the working directory was not respected; we had to carefully reinitialize the environment; et cetera. Eventually it seemed easier to wrap the entire Snakemake workflow in a batch script and submit that to slurm, but this is also suboptimal, especially since we cannot differentiate between resources for eacht task then.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;verdict&quot;&gt;Verdict&lt;/h3&gt;
&lt;p&gt;Some of these things can probably be solved by digging further into the inner workings of Snakemake. At the same time, we’re conscious of the complexity of our workflow. If it takes more time to build and maintain it than it would take to do the tedious manual bookkeeping, is it really worth the effort?&lt;/p&gt;
&lt;p&gt;Hopefully yes: reproducibility is important, and perhaps others can benefit as well. For now, however, we need to focus on the results for a bit. So let’s do a quick recap and call it a day.&lt;/p&gt;
&lt;p&gt;If you want to follow our progress, keep an eye on our repository &lt;a href=&quot;https://github.com/Urban-M4/snakemake-wrf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;We’ve experimented with different options for managing WRF workflows. With a few tweaks, we were able to tackle many of our initial painpoints. Once we got the hang of it, we quite liked the flexibility of Snakemake and its promise of reproducible experiment sets. However, while we aimed for something simple, we found that our solutions quickly grew complex as we tried to bend the tools to our will.&lt;/p&gt;
&lt;p&gt;There’s a few peculiarities about WRF that were very much in the way. For example, that we couldn’t specify the ungrib directory. In terms of compatibility with Snakemake, it would be nice if WRF was less dependent on the current working directory, and/or if Snakemake’s working directory would be able to adapt to wildcard values.&lt;/p&gt;
&lt;p&gt;Perhaps the main conclusion should be that organizing your (WRF) workflows is not as straightforward as it may seem. This is something that many people must struggle with. And while there’s plenty of resources on the WRF documentation and user forum, “how to manage your workflow” does not seem to get the attention it deserves.&lt;/p&gt;
&lt;p&gt;How do you manage your workflows? Please share your tips and tricks in the comments or in any other way that you see fit.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/unwieldy-workflows-with-wrf-b6e59d0c.B5Z5PUNe.jpg" medium="image"/><author>Peter Kalverla</author></item><item><title>Research software is critical to the future of AI-driven research</title><link>https://blog.esciencecenter.nl/posts/2024-08-22---research-software-is-critical-to-the-future-of-ai-driven-res</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-08-22---research-software-is-critical-to-the-future-of-ai-driven-res</guid><description>&lt;p&gt;&lt;em&gt;By Michelle Barker, Kim Hartley, Daniel S. Katz, Richard Littauer, Qian Zhang, Shurui Zhou, Jyoti Bhogal&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Cross-posted from ReSA and the Digital Research Alliance of Canada&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research software is critical to the future of AI-driven research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-is-critical-to-the-fut-cea947aa.CtbIw_yP_2h44w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo credit: &lt;a href=&quot;https://www.shutterstock.com/g/TheMezereon&quot;&gt;TheMezereon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This position paper provides a statement on the criticality of research software in artificial intelligence (AI)-driven research and makes recommendations for stakeholders on how to consider research software in their AI goals. This is needed to ensure that the focus on technological infrastructure to support AI acceleration includes research software and its personnel as a vital part of that infrastructure. This paper discusses both research software that supports generative AI, which is now being explored today as a tool to enable new research, as well as more traditional machine learning, which has demonstrated impact in research in most disciplines (particularly in the last decade).&lt;/p&gt;
&lt;p&gt;This paper begins by providing definitions for key terms and demonstrating the importance of research software in AI-driven research. The paper then explores the need for AI strategies to recognise research software as key building blocks of AI-driven research, and to include this element alongside a focus on computing systems, data, and models. The fact that AI is dependent on software (i.e., data preparation and model training are performed by software, models are implemented in software) is not always adequately considered. Alongside this high-level need for incorporation of research software in AI strategies, the challenges inherent in software dependencies also need consideration, as research software requires continual maintenance, updating, bug fixes, etc. Consequently, the broader challenges in enabling ongoing support for research software used for any type of research are equally relevant to AI-driven research and presented here.&lt;/p&gt;
&lt;p&gt;There is also a need to better support the people who develop and maintain the research software that enables AI-driven research. Because human skills, training, and career paths often feature in AI strategies, it is imperative that stakeholders facilitate practices that support and recognise research software personnel. While the research community is exploring how to leverage AI to improve how research software is developed and maintained, this is also affecting how research software practices should be taught. The paper also illustrates how some countries are operationalising AI strategies that could support the critical element of research software, and have the potential to do so by building on existing investments in research software.&lt;/p&gt;
&lt;p&gt;This paper was written in collaboration with the Research Software Alliance (ReSA) and the Digital Research Alliance of Canada, one of ReSA’s Founding Members. ReSA is a global organisation that unites decision-makers and influencers across the international research software community.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; is funded by the Government of Canada to serve Canadian researchers, including the infrastructure and activities required for research software. Other community leaders also provided inputs from institutional and open-source perspectives.&lt;/p&gt;
&lt;h2 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;This position paper provides a statement on the criticality of research software in artificial intelligence (AI)-driven research. This is needed to ensure that the focus on technological infrastructure to support AI acceleration includes research software — a vital part of that infrastructure. This paper begins by providing definitions for key terms, demonstrating the importance of research software in AI-driven research, and explaining why this paper was developed. The paper then explores the need for AI strategies to recognise research software as a key building block of AI-driven research, and to include this element alongside a focus on computing systems, data, and models. To do this, evidence on the issues in supporting research software, including open-source scientific software, is presented.&lt;/p&gt;
&lt;p&gt;The paper then explores how to better support the people who develop and maintain the research software in AI-driven research. AI strategies often consider people elements such as skills and career paths, which also reflect broader issues for personnel. The paper then illustrates how some countries are operationalising AI strategies that could support the critical element of research software, and have the potential to do so by building on existing investments in research software. Finally, the paper makes recommendations for stakeholders to consider research software in their AI strategies.&lt;/p&gt;
&lt;h2 id=&quot;2-what-is-research-software-and-why-is-it-critical-to-ai&quot;&gt;2. What is research software and why is it critical to AI?&lt;/h2&gt;
&lt;p&gt;Research software is defined in accordance with the FAIR for Research Software Principles (Barker et al. 2022) as “source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose. Software components (e.g., operating systems, libraries, dependencies, packages, scripts, etc.) that are used for research but were not created during or with a clear research intent should be considered software in research and not research software. This differentiation may vary between disciplines” (Gruenpeter et al. 2021).&lt;/p&gt;
&lt;p&gt;Research software supports AI, both 1) in more traditional machine learning (ML), where models are trained on data and then used to infer knowledge about new data, and 2) in generative AI, which can be defined as “deep-learning models that can generate high-quality text, images, and other content based on the data they were trained on” (Martineau 2021).&lt;/p&gt;
&lt;p&gt;Research software is already recognised as critical to research outcomes (Barker, Katz, and Gonzalez-Beltran 2020; Hocquet et al. 2024; Strasser et al. 2022). Research software can be a research output in itself, and its many functions range from being a component of research instruments, being the research instrument (where research software generates research data, validates research data, or tests hypotheses, such as models and simulations), analysing and presenting research data, and providing infrastructure or underlying tools (Nieuwpoort and Katz 2024). All machine learning (ML) and AI began as research software. In many cases, AI research software has transitioned outside of research and is widely used outside research today.&lt;/p&gt;
&lt;p&gt;Consequently, research software is essential in AI-based research, where newly developed methods are** research software. Some AI reports and strategies recognise this; for example, OECD’s &lt;a href=&quot;https://www.oecd-ilibrary.org/science-and-technology/artificial-intelligence-in-science_a8d820bd-en&quot;&gt;Artificial Intelligence in Science&lt;/a&gt; report (OECD 2023) highlights the need to better support research software as part of utilising AI to accelerate scientific productivity, in a number of ways, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increase access to software&lt;/li&gt;
&lt;li&gt;Share best practices and applications of research software&lt;/li&gt;
&lt;li&gt;Facilitate more regular funding and more secure positions&lt;/li&gt;
&lt;li&gt;Improve ways to measure research impact and productivity&lt;/li&gt;
&lt;li&gt;Consider academic training changes needed&lt;/li&gt;
&lt;li&gt;Utilise disciplinary consortiums to accelerate discovery and improve reproducibility through the sharing of software&lt;/li&gt;
&lt;li&gt;Understand how AI can speed up research software development&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The research community personnel who develop and maintain research software are just as important as the research software itself, if not more important, as the software will stop working without ongoing maintenance. This maintenance is needed 1) to respond to bugs so that the software continues to be correct, 2) to add new features so that the software continues to be useful as research progresses, 3) to adapt to change in underlying software and hardware or in related software ecosystems, such as changed libraries and computing systems, so that the software continues to work.&lt;/p&gt;
&lt;p&gt;The people who do this work can have many titles, including researchers, research software engineers (RSEs), data scientists, computer scientists, data engineers, bioinformaticians, students, community scientists, and many more (Hettrick et al. 2022; Barker and Buchhorn 2022). The inclusion of improved support for the staff who develop and maintain research software is also emphasised in the UK-focused&lt;a href=&quot;https://www.turing.ac.uk/sites/default/files/2022-09/ukri-requirements-report_final_edits.pdf&quot;&gt; Review of Digital Research Infrastructure Requirements for AI&lt;/a&gt; (Lazauskas et al. 2022). This report’s findings included emphasis that “any investment in any infrastructure for AI would need to be matched by investments in training and support”, with the second highest priority areas identified as funding for RSEs (Lazauskas et al. 2022). The UK’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.4986062&quot;&gt;ExCALIBUR RSE Knowledge Integration Landscape Review&lt;/a&gt; also highlights the need for RSEs to acquire new skills relevant to AI, and notes that “These skill sets also begin to deviate from what is demanded by industries, requiring novel AI software and capabilities’’ (Parsons et al. 2021).&lt;/p&gt;
&lt;p&gt;ReSA’s initial research on recognition of research software in the AI landscape was presented in March 2024 at its &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; meetings. This forum engages representatives from over 60 funding organisations in online meetings and hybrid venues (ReSA 2024a). Attendees of these March meetings were immediately able to utilise these early findings from the presentation to strengthen their own cases for investment in research software within AI-dominated programs, where the criticality of this building block is not yet understood by many in their organisations. It became clear that further research on best practices would support not only funders but a variety of stakeholders in the international research software community.&lt;/p&gt;
&lt;p&gt;The research in this position paper was undertaken as a partnership between &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;ReSA&lt;/a&gt; and the &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt;, one of ReSA’s &lt;a href=&quot;https://www.researchsoft.org/about-resa/&quot;&gt;Founding Members&lt;/a&gt;. One of ReSA’s key functions is to ensure that research software is considered in international discussions on how to advance research capabilities. ReSA is a global organisation that unites decision-makers and influencers across the international research software community. The Digital Research Alliance of Canada is a non-profit organisation funded by the Government of Canada. It advances Canada’s position as a leader in the knowledge economy on the international stage by integrating, championing and funding the infrastructure and activities required, with research software as one of the three main areas. Other community leaders were also brought in on this paper in order to present more balanced perspectives on the need for research software in AI, particularly from institutional and open source perspectives.&lt;/p&gt;
&lt;h2 id=&quot;3-consequences-if-research-software-is-not-supported&quot;&gt;3. Consequences if research software is not supported&lt;/h2&gt;
&lt;p&gt;There is a tendency for AI initiatives to minimise or exclude focus on research software. This minimisation creates challenges. To show this, evidence on the issues in supporting research software, including open-source scientific software, is also presented here.&lt;/p&gt;
&lt;p&gt;Many AI initiatives tend to focus on computing systems, data, and models, considering issues such as the availability of systems that can train models and use them for inference in reasonable time periods; FAIRness of underlying data as well as its suitability for training models, including regularity and labelling; understanding and reducing bias in data and models; and understanding privacy. The fact that AI models are implemented in software, and that software is required for training, is rarely considered. Basically, models are thought of as extensions of data, not of software as well. Consequently, many AI strategies focus on data and models but exclude the underlying software. An example of an AI strategy that does not necessarily adequately include a research software focus is the US National Institutes of Health (NIH) workshop,&lt;a href=&quot;https://www.scgcorp.com/ethicalframework2024/Agenda&quot;&gt; Towards an ethical framework for AI in biomedical and behavioural research&lt;/a&gt;, which focused on data and models, but not the research software inherent in using the data and models (ODSS 2024).&lt;/p&gt;
&lt;p&gt;This challenge is not limited to research software. Discussions of AI capacity often omit open-source software, instead focusing on areas such as talent, funding, data, semiconductors, and compute access (Engler 2021). Like research software, open-source software can advance science but also has significant effects in other areas such as the development of AI standards (Engler 2021). Further, research software is often either open-source itself or depends on open-source software. But considerations for software from AI initiatives, if any, do not normally include open source software maintenance as a priority, nor analysis of its dependency on other software (Nahar et al. Forthcoming). Where dependency analysis does happen, it is usually due to concerns about supply chain security or perceived attack vectors (a pathway or method used to access a network or computer to attempt to exploit system vulnerabilities).&lt;/p&gt;
&lt;p&gt;The nature of open source software as a complex stack and the concomitant extra step of funding those open source software dependencies of the research software necessary for AI is largely ignored. This could reflect a misunderstanding of how open-source dependencies introduce systemic vulnerabilities that need to be addressed and maintained on an ongoing basis or concerns regarding funding many independent projects down the dependency tree. When open-source software is used without planning for future community or dependency support, the result is a more brittle system in the long run — for research software, open-source software, and AI.&lt;/p&gt;
&lt;p&gt;There has been some recent work done on software bills of materials (SBOMs) in open source supply chains, where dependencies are charted out, in part so that their vulnerabilities can be understood (National Security Agency 2024; SCAWG 2022) (and it is relevant to note that research software is often used to map these dependencies). Mapping supply chains is increasingly important for understanding how to shore up digital infrastructure, where large economies depend upon open-source software that is poorly maintained and that may be internationally broken or hijacked or may break (as in the XZ Utils, Heartbleed, or the Log4j incidents (Goodin 2024; Buchanan 2021), or the more recent CrowdStrike failure which caused a global Windows outage (Robins-Early 2024)). However, SBOMs are merely an atlas for understanding dependencies — they are policy agnostic and their creation doesn’t mandate funding or supporting important open-source or research software.&lt;/p&gt;
&lt;p&gt;This paper suggests that infrastructural issues with using and supporting open source software are similar or identical to issues with using research software. Where AI is involved, the same questions of continued support for the research software being used to develop, train, and run the AI systems are raised. Any AI initiative that plans to use global infrastructure, to adapt to new fields and target areas, or that hopes to exist for the long haul must consider the research software that enables those goals.&lt;/p&gt;
&lt;h2 id=&quot;4-challenges-if-research-software-personnel-are-not-supported&quot;&gt;4. Challenges if research software personnel are not supported&lt;/h2&gt;
&lt;p&gt;There is also a need to better support the people who develop and maintain research software that is important to AI-driven research. This is recognised in relation to research software personnel in general, particularly in relation to the training, hiring, and funding of both professional research and technical staff able to reuse, develop, and maintain sustainable research software; appropriate reward and recognition measures that enable career progression for all people involved in the creation and maintenance of research software; and citation practices for research software that recognise substantial contributors to all aspects of the software (Van Tuyl 2023; US-RSE Association and IEEE Computer Society 2023; Barker and Katz 2022a; ReSA 2023). For example, &lt;a href=&quot;https://zenodo.org/records/10473186&quot;&gt;Software and skills for research computing in the UK&lt;/a&gt; recommendations include facilitating detailed analysis of how to professionalise RSE roles; and collaboration between government, funders, and employers to create national policies aimed at improving standards of employment (Barker et al. 2024).&lt;/p&gt;
&lt;p&gt;Whilst many of the issues for research software, in general, are the same for research software to support AI-driven research, one area of difference is in the specifics of skills and training. Human skills, training, and career paths often feature in AI strategies, and it is important that these focus on relevant research software practices. For example, the&lt;a href=&quot;https://www.turing.ac.uk/sites/default/files/2022-09/ukri-requirements-report_final_edits.pdf&quot;&gt; Review of Digital Research Infrastructure Requirements for AI&lt;/a&gt; specifically emphasises the lack of AI skills and training, and career paths for research personnel, including for RSEs. It highlights that these staff often lack formal training, and ongoing professional development is crucial in the fast-paced world of AI tools and techniques (Lazauskas et al. 2022). With many researchers now using GenAI for coding tasks (Nordling 2023, cited in Hosseini et al. 2024), software development skills need to change to reflect this (Caballar 2024; Dursi 2024).&lt;/p&gt;
&lt;h2 id=&quot;5-national-approaches&quot;&gt;5. National approaches&lt;/h2&gt;
&lt;p&gt;AI is now seen as a geopolitical asset, and as international organisations and a range of countries seek to show leadership for AI in science, some countries are operationalising AI strategies that could support the critical element of research software. However, more focus is needed. One example of discussing software within a national AI strategy is the US &lt;a href=&quot;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&quot;&gt;National Artificial Intelligence Research Resource&lt;/a&gt; (NAIRR). NAIRR aims to provide a shared national research infrastructure for responsible discovery and innovation in AI, to address the fact that many researchers lack the necessary access to the computing, data, software and educational resources needed. The NAIRR pilot’s four operational focus areas include one area dedicated to software, to “facilitate and investigate interoperable use of AI software, platforms, tools and services for NAIRR pilot resources” (NSF 2024). However, there are potential challenges with this approach as the focus is on interoperability of existing software, which assumes that sustainable software is already in place.&lt;/p&gt;
&lt;p&gt;Many countries also have existing investments in research software (Barker and Katz 2022b; ReSA 2024b) that national initiatives have the potential to build on. The UK’s &lt;a href=&quot;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&quot;&gt;AI Research Resource&lt;/a&gt; (AIRR) is another example of a national initiative, which focuses on increasing computational power to support AI-driven research (UKRI 2023), although its funding is now uncertain (Trueman 2024). Whilst AIRR does not seem to include a focus on research software, AIRR is a key component of UK Research and Innovation (UKRI)’s &lt;a href=&quot;https://www.ukri.org/what-we-do/creating-world-class-research-and-innovation-infrastructure/digital-research-infrastructure/&quot;&gt;Digital Research Infrastructure&lt;/a&gt; (DRI) which has featured a number of recent investments in research software, including funding of research technical professionals (RTPs), such as RSEs. For example, the Engineering and Physical Sciences Research Council (EPSRC) and UKRI DRI have invested £16 million to support community-driven projects providing training and development for RTPs (UKRI 2024a). UKRI’s &lt;a href=&quot;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&quot;&gt;Digital RTP Skills NetworkPlus&lt;/a&gt; aims to explore key challenges and interventions related to skills and careers that are faced by digital RTP communities across the UK research and innovation landscape (UKRI 2024b).&lt;/p&gt;
&lt;p&gt;Canada has been a leader in AI, as the first country in the world to put in place in 2017 a fully-funded AI strategy, the &lt;a href=&quot;https://ised-isde.canada.ca/site/ai-strategy/en&quot;&gt;Pan-Canadian AI Strategy&lt;/a&gt; (ISED 2022). The strategy included the establishment of a national program of research chairs to recruit and retain top researchers at Canadian universities, the establishment of three national AI institutes to be global centres of training and research excellence and the creation of a Pan-Canadian AI Compute Environment (PAICE) platform. The Digital Research Alliance of Canada’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.10214741&quot;&gt;National Research Software Strategy&lt;/a&gt; for 2025–2030 (Digital Research Alliance of Canada, National Research Software Strategy Working Group 2023) also reviewed (inter)national research software funding programs in support of AI, deep learning, and ML-facilitated research. Before the Alliance, CANARIE has been a national Research Software funder and service provider since 2007, whose successful research software initiatives had resulted in the development of sophisticated software tools, known as research platforms, that typically support end-to-end research workflow within a specific domain. New platforms re-used software components previously developed through CANARIE funding, and contributed additional components back to the research community, creating a powerful cycle of software development and reuse (CANARIE 2024). The Alliance is now using the &lt;a href=&quot;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&quot;&gt;Research Software Directory&lt;/a&gt; to continue promoting the visibility, impact, and reuse of the Canadian research software (Digital Research Alliance of Canada 2024).&lt;/p&gt;
&lt;h2 id=&quot;6-recommendations-for-research-software-to-support-ai&quot;&gt;6. Recommendations for research software to support AI&lt;/h2&gt;
&lt;p&gt;Research software needs to be included in AI strategies. Our recommendations for doing so are listed below, organised in three areas from the &lt;a href=&quot;https://doi.org/10.5281/zenodo.8325436&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt; (ReSA 2023):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research software practice:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI strategies and funding must recognise that research software is a key part of the (publicly funded) AI pipeline and that AI is dependent on software, and therefore should stimulate the development and maintenance of research software to ensure the success of the AI work.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Research software ecosystem:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because AI-driven research is dependent on the existing research software ecosystem, AI strategies should provide long-term support for its elements, including personnel, communities, and infrastructure, and should add new elements that focus on AI-specific parts as needed.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Research software personnel:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because the existing research software ecosystem that supports AI-driven research is dependent on research software personnel, AI strategies should facilitate appropriate reward and recognition measures that enable career progression for all people involved in the creation and maintenance of research software that supports AI-driven research.&lt;/p&gt;
&lt;p&gt;Other ways to help ensure that the focus on technological infrastructure to support AI acceleration includes research software and its personnel as a vital part of that infrastructure include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;Signing&lt;/a&gt; the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability (ADORE.software)&lt;/a&gt;, which represents a first step to formalise, on a global level, the basic principles and recommendations related to funding the sustainability of research software, including the people needed to achieve this goal.&lt;/li&gt;
&lt;li&gt;Supporting ReSA in its aim to ensure that research software is considered in international discussions on how to advance research capabilities. Become a ReSA &lt;a href=&quot;https://www.researchsoft.org/membership/&quot;&gt;Organisational Member&lt;/a&gt;, &lt;a href=&quot;https://www.researchsoft.org/tf-support/&quot;&gt;support a task force&lt;/a&gt;, or &lt;a href=&quot;https://www.researchsoft.org/donate/&quot;&gt;donate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For funders, joining the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, a global collaboration of funding organisations committed to supporting research software, and those who develop and maintain it, as fundamental and vital to research.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Barker, Michelle, Elena Breitmoser, Philippa Broadbent, Neil Chue Hong, Simon Hettrick, Ioanna Lampaki, Anthony Quinn, and Rebecca Taylor. 2024. ‘Software and Skills for Research Computing in the UK’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10473186&quot;&gt;https://doi.org/10.5281/ZENODO.10473186&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Markus Buchhorn. 2022. ‘Research Software Capability in Australia’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6335998&quot;&gt;https://doi.org/10.5281/ZENODO.6335998&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, Neil P. Chue Hong, Daniel S. Katz, Anna-Lena Lamprecht, Carlos Martinez-Ortiz, Fotis Psomopoulos, Jennifer Harrow, et al. 2022. ‘Introducing the FAIR Principles for Research Software’. Scientific Data* 9 (1): 622. &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;https://doi.org/10.1038/s41597-022-01710-x&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Daniel S Katz. 2022a. ‘Encouraging Entry, Retention, Diversity and Inclusion in Research Software Careers’. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.7117842&quot;&gt;https://doi.org/10.5281/ZENODO.7117842&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Daniel S. Katz. 2022b. ‘Overview of Research Software Funding Landscape’, February. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6102487&quot;&gt;https://doi.org/10.5281/ZENODO.6102487&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, Daniel S. Katz, and Alejandra Gonzalez-Beltran. 2020. ‘Evidence for the Importance of Research Software’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.3884311&quot;&gt;https://doi.org/10.5281/ZENODO.3884311&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Buchanan, Bill. 2021. ‘Log4j: The Worst Vulnerability In Nearly A Decade?’ &lt;em&gt;Medium&lt;/em&gt; (blog). 2021. &lt;a href=&quot;https://medium.com/asecuritysite-when-bob-met-alice/log4j-the-worst-vulnerability-in-nearly-a-decade-e0cc80cbb49a&quot;&gt;https://medium.com/asecuritysite-when-bob-met-alice/log4j-the-worst-vulnerability-in-nearly-a-decade-e0cc80cbb49a&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Caballar, Rina Diane. 2024. ‘AI Copilots Are Changing How Coding Is Taught — IEEE Spectrum’. 2 May 2024. &lt;a href=&quot;https://spectrum.ieee.org/ai-coding&quot;&gt;https://spectrum.ieee.org/ai-coding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CANARIE. 2024. ‘Funded Research Software Platforms’. 2024. &lt;a href=&quot;https://www.canarie.ca/software/platforms/&quot;&gt;https://www.canarie.ca/software/platforms/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Digital Research Alliance of Canada. 2024. ‘Research Software Directory’. 2024. &lt;a href=&quot;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&quot;&gt;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Digital Research Alliance of Canada, National Research Software Strategy Working Group. 2023. ‘National Research Software Strategy 2023’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10214741&quot;&gt;https://doi.org/10.5281/ZENODO.10214741&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dursi, Jonathan. 2024. ‘We Need To Talk About AI’. &lt;em&gt;Research Computing Teams&lt;/em&gt; 183 (June). &lt;a href=&quot;https://newsletter.researchcomputingteams.org/archive/rct-183-we-need-to-talk-about-ai-plus-upfront/&quot;&gt;https://newsletter.researchcomputingteams.org/archive/rct-183-we-need-to-talk-about-ai-plus-upfront/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Engler, Alex. 2021. ‘How Open-Source Software Shapes AI Policy’. Brookings. 10 August 2021. &lt;a href=&quot;https://www.brookings.edu/articles/how-open-source-software-shapes-ai-policy/&quot;&gt;https://www.brookings.edu/articles/how-open-source-software-shapes-ai-policy/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Goodin, Dan. 2024. ‘The XZ Backdoor: Everything You Need to Know’. Wired. 2 April 2024. &lt;a href=&quot;https://www.wired.com/story/xz-backdoor-everything-you-need-to-know/&quot;&gt;https://www.wired.com/story/xz-backdoor-everything-you-need-to-know/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gruenpeter, Morane, Daniel S. Katz, Anna-Lena Lamprecht, Tom Honeyman, Daniel Garijo, Alexander Struck, Anna Niehues, et al. 2021. ‘Defining Research Software: A Controversial Discussion’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.5504016&quot;&gt;https://doi.org/10.5281/ZENODO.5504016&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hettrick, Simon, Radovan Bast, Steve Crouch, Claire Bradley, Philippe, Botzki, Alex, Carver, Jeffrey, et al. 2022. ‘International RSE Survey 2022’. &lt;a href=&quot;https://softwaresaved.github.io/international-survey-2022/&quot;&gt;https://softwaresaved.github.io/international-survey-2022/&lt;/a&gt;. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6884882&quot;&gt;https://doi.org/10.5281/ZENODO.6884882&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hocquet, Alexandre, Frédéric Wieber, Gabriele Gramelsberger, Konrad Hinsen, Markus Diesmann, Fernando Pasquini Santos, Catharina Landström, et al. 2024. ‘Software in Science Is Ubiquitous yet Overlooked’. &lt;em&gt;Nature Computational Science&lt;/em&gt;, July. &lt;a href=&quot;https://doi.org/10.1038/s43588-024-00651-2&quot;&gt;https://doi.org/10.1038/s43588-024-00651-2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ISED. 2022. ‘Pan-Canadian Artificial Intelligence Strategy’. Home page; Innovation, Science and Economic Development Canada. 20 July 2022. &lt;a href=&quot;https://ised-isde.canada.ca/site/ai-strategy/en/pan-canadian-artificial-intelligence-strategy&quot;&gt;https://ised-isde.canada.ca/site/ai-strategy/en/pan-canadian-artificial-intelligence-strategy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lazauskas, Tomas, Jennifer Ding, Neil Brown, Reda Nausedaite, Felix Dijkstal, Aaron Vinnik, Bruno Raabe, et al. 2022. ‘Review of Digital Research Infrastructure Requirements for AI’. &lt;a href=&quot;https://doi.org/10.13140/RG.2.2.29376.00009&quot;&gt;https://doi.org/10.13140/RG.2.2.29376.00009&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Martineau, Kim. 2021. ‘What Is Generative AI?’ IBM Research. 9 February 2021. &lt;a href=&quot;https://research.ibm.com/blog/what-is-generative-AI&quot;&gt;https://research.ibm.com/blog/what-is-generative-AI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nahar, Nadia, Haoran Zhang, Grace Lewis, Shurui Zhou, and Christian Kästner. Forthcoming. ‘The Product Beyond the Model — An Empirical Study of Repositories of Open-Source ML Products’. In . &lt;a href=&quot;https://www.cs.cmu.edu/~ckaestne/publications.html&quot;&gt;https://www.cs.cmu.edu/~ckaestne/publications.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;National Security Agency. 2024. ‘Recommendations for Software Bill of Materials (SBOM) Management’. &lt;a href=&quot;https://media.defense.gov/2023/Dec/14/2003359097/-1/-1/0/CSI-SCRM-SBOM-MANAGEMENT.PDF&quot;&gt;https://media.defense.gov/2023/Dec/14/2003359097/-1/-1/0/CSI-SCRM-SBOM-MANAGEMENT.PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nordling, Linda. 2023. ‘How ChatGPT Is Transforming the Postdoc Experience’. &lt;em&gt;Nature&lt;/em&gt; 622 (7983): 655–57. &lt;a href=&quot;https://doi.org/10.1038/d41586-023-03235-8&quot;&gt;https://doi.org/10.1038/d41586-023-03235-8&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;NSF. 2024. ‘National Artificial Intelligence Research Resource Pilot’. 2024. &lt;a href=&quot;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&quot;&gt;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ODSS. 2024. ‘Toward an Ethical Framework for AI in Biomedical and Behavioral Research’. 2024. &lt;a href=&quot;https://www.scgcorp.com/ethicalframework2024/Agenda&quot;&gt;https://www.scgcorp.com/ethicalframework2024/Agenda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OECD. 2023. &lt;em&gt;Artificial Intelligence in Science: Challenges, Opportunities and the Future of Research&lt;/em&gt;. OECD. &lt;a href=&quot;https://doi.org/10.1787/a8d820bd-en&quot;&gt;https://doi.org/10.1787/a8d820bd-en&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Parsons, Mark, Alastair Basden, Richard Bower, Neil P. Chue Hong, Davide Constanzo, Shaun Witt, Luigi Del Debbio, et al. 2021. ‘ExCALIBUR Research Software Engineer Knowledge Integration Landscape Review’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.4986062&quot;&gt;https://doi.org/10.5281/ZENODO.4986062&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ReSA. 2023. ‘Amsterdam Declaration on Funding Research Software Sustainability’, August. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.8325436&quot;&gt;https://doi.org/10.5281/ZENODO.8325436&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024a. ‘Research Software Funders Forum’. 2024. &lt;a href=&quot;https://researchsoft.org/funders-forum/&quot;&gt;https://researchsoft.org/funders-forum/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024b. ‘Research Software Funding Opportunities’. 2024. &lt;a href=&quot;https://researchsoft.org/funding-opportunities/&quot;&gt;https://researchsoft.org/funding-opportunities/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Robins-Early, Nick. 2024. ‘What Is CrowdStrike, and How Did It Cause a Global Windows Outage?’ &lt;em&gt;The Guardian&lt;/em&gt;, 19 July 2024. &lt;a href=&quot;https://www.theguardian.com/technology/article/2024/jul/19/what-is-crowdstrike-microsoft-windows-outage&quot;&gt;https://www.theguardian.com/technology/article/2024/jul/19/what-is-crowdstrike-microsoft-windows-outage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;SCAWG. 2022. ‘Recommendations to Improve the Resilience of Canada’s Digital Supply Chain’. &lt;a href=&quot;https://ised-isde.canada.ca/site/spectrum-management-telecommunications/sites/default/files/attachments/2022/CFDIR-June2022-recommendations.pdf&quot;&gt;https://ised-isde.canada.ca/site/spectrum-management-telecommunications/sites/default/files/attachments/2022/CFDIR-June2022-recommendations.pdf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Strasser, Carly, Kate Hertweck, Josh Greenberg, Dario Taraborelli, and Elizabeth Vu. 2022. ’10 Simple Rules for Funding Scientific Open Source Software’, June. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6611500&quot;&gt;https://doi.org/10.5281/ZENODO.6611500&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Trueman, Charlotte. 2024. ‘UK Government Shelves £1.3bn of Tech and AI Projects; Scraps Plans for First Exascale Supercomputer in Edinburgh’. 2 August 2024. &lt;a href=&quot;https://www.datacenterdynamics.com/en/news/uk-government-shelves-13bn-of-tech-and-ai-projects-scraps-plans-for-first-exascale-supercomputer-in-edinburgh/&quot;&gt;https://www.datacenterdynamics.com/en/news/uk-government-shelves-13bn-of-tech-and-ai-projects-scraps-plans-for-first-exascale-supercomputer-in-edinburgh/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UKRI. 2023. ‘£300 Million to Launch First Phase of New AI Research Resource’. 1 November 2023. &lt;a href=&quot;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&quot;&gt;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024a. ‘New Funding to Support Research Technical Professionals’. 18 March 2024. &lt;a href=&quot;https://www.ukri.org/news/new-funding-to-support-research-technical-professionals/&quot;&gt;https://www.ukri.org/news/new-funding-to-support-research-technical-professionals/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024b. ‘UKRI Digital Research Technical Professional Skills NetworkPlus’. 22 April 2024. &lt;a href=&quot;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&quot;&gt;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;US-RSE Association and IEEE Computer Society. 2023. ‘Research Software Engineers: Creating a Career Path — and a Career’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10073232&quot;&gt;https://doi.org/10.5281/ZENODO.10073232&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Van Tuyl, Steve (Ed.). 2023. ‘Hiring, Managing, and Retaining Data Scientists and Research Software Engineers in Academia: A Career Guidebook from ADSA and US-RSE’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.8274378&quot;&gt;https://doi.org/10.5281/ZENODO.8274378&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 22 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By Michelle Barker, Kim Hartley, Daniel S. Katz, Richard Littauer, Qian Zhang, Shurui Zhou, Jyoti Bhogal&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Cross-posted from ReSA and the Digital Research Alliance of Canada&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Research software is critical to the future of AI-driven research&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/research-software-is-critical-to-the-fut-cea947aa.CtbIw_yP_2h44w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo credit: &lt;a href=&quot;https://www.shutterstock.com/g/TheMezereon&quot;&gt;TheMezereon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This position paper provides a statement on the criticality of research software in artificial intelligence (AI)-driven research and makes recommendations for stakeholders on how to consider research software in their AI goals. This is needed to ensure that the focus on technological infrastructure to support AI acceleration includes research software and its personnel as a vital part of that infrastructure. This paper discusses both research software that supports generative AI, which is now being explored today as a tool to enable new research, as well as more traditional machine learning, which has demonstrated impact in research in most disciplines (particularly in the last decade).&lt;/p&gt;
&lt;p&gt;This paper begins by providing definitions for key terms and demonstrating the importance of research software in AI-driven research. The paper then explores the need for AI strategies to recognise research software as key building blocks of AI-driven research, and to include this element alongside a focus on computing systems, data, and models. The fact that AI is dependent on software (i.e., data preparation and model training are performed by software, models are implemented in software) is not always adequately considered. Alongside this high-level need for incorporation of research software in AI strategies, the challenges inherent in software dependencies also need consideration, as research software requires continual maintenance, updating, bug fixes, etc. Consequently, the broader challenges in enabling ongoing support for research software used for any type of research are equally relevant to AI-driven research and presented here.&lt;/p&gt;
&lt;p&gt;There is also a need to better support the people who develop and maintain the research software that enables AI-driven research. Because human skills, training, and career paths often feature in AI strategies, it is imperative that stakeholders facilitate practices that support and recognise research software personnel. While the research community is exploring how to leverage AI to improve how research software is developed and maintained, this is also affecting how research software practices should be taught. The paper also illustrates how some countries are operationalising AI strategies that could support the critical element of research software, and have the potential to do so by building on existing investments in research software.&lt;/p&gt;
&lt;p&gt;This paper was written in collaboration with the Research Software Alliance (ReSA) and the Digital Research Alliance of Canada, one of ReSA’s Founding Members. ReSA is a global organisation that unites decision-makers and influencers across the international research software community.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; is funded by the Government of Canada to serve Canadian researchers, including the infrastructure and activities required for research software. Other community leaders also provided inputs from institutional and open-source perspectives.&lt;/p&gt;
&lt;h2 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;This position paper provides a statement on the criticality of research software in artificial intelligence (AI)-driven research. This is needed to ensure that the focus on technological infrastructure to support AI acceleration includes research software — a vital part of that infrastructure. This paper begins by providing definitions for key terms, demonstrating the importance of research software in AI-driven research, and explaining why this paper was developed. The paper then explores the need for AI strategies to recognise research software as a key building block of AI-driven research, and to include this element alongside a focus on computing systems, data, and models. To do this, evidence on the issues in supporting research software, including open-source scientific software, is presented.&lt;/p&gt;
&lt;p&gt;The paper then explores how to better support the people who develop and maintain the research software in AI-driven research. AI strategies often consider people elements such as skills and career paths, which also reflect broader issues for personnel. The paper then illustrates how some countries are operationalising AI strategies that could support the critical element of research software, and have the potential to do so by building on existing investments in research software. Finally, the paper makes recommendations for stakeholders to consider research software in their AI strategies.&lt;/p&gt;
&lt;h2 id=&quot;2-what-is-research-software-and-why-is-it-critical-to-ai&quot;&gt;2. What is research software and why is it critical to AI?&lt;/h2&gt;
&lt;p&gt;Research software is defined in accordance with the FAIR for Research Software Principles (Barker et al. 2022) as “source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose. Software components (e.g., operating systems, libraries, dependencies, packages, scripts, etc.) that are used for research but were not created during or with a clear research intent should be considered software in research and not research software. This differentiation may vary between disciplines” (Gruenpeter et al. 2021).&lt;/p&gt;
&lt;p&gt;Research software supports AI, both 1) in more traditional machine learning (ML), where models are trained on data and then used to infer knowledge about new data, and 2) in generative AI, which can be defined as “deep-learning models that can generate high-quality text, images, and other content based on the data they were trained on” (Martineau 2021).&lt;/p&gt;
&lt;p&gt;Research software is already recognised as critical to research outcomes (Barker, Katz, and Gonzalez-Beltran 2020; Hocquet et al. 2024; Strasser et al. 2022). Research software can be a research output in itself, and its many functions range from being a component of research instruments, being the research instrument (where research software generates research data, validates research data, or tests hypotheses, such as models and simulations), analysing and presenting research data, and providing infrastructure or underlying tools (Nieuwpoort and Katz 2024). All machine learning (ML) and AI began as research software. In many cases, AI research software has transitioned outside of research and is widely used outside research today.&lt;/p&gt;
&lt;p&gt;Consequently, research software is essential in AI-based research, where newly developed methods are** research software. Some AI reports and strategies recognise this; for example, OECD’s &lt;a href=&quot;https://www.oecd-ilibrary.org/science-and-technology/artificial-intelligence-in-science_a8d820bd-en&quot;&gt;Artificial Intelligence in Science&lt;/a&gt; report (OECD 2023) highlights the need to better support research software as part of utilising AI to accelerate scientific productivity, in a number of ways, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increase access to software&lt;/li&gt;
&lt;li&gt;Share best practices and applications of research software&lt;/li&gt;
&lt;li&gt;Facilitate more regular funding and more secure positions&lt;/li&gt;
&lt;li&gt;Improve ways to measure research impact and productivity&lt;/li&gt;
&lt;li&gt;Consider academic training changes needed&lt;/li&gt;
&lt;li&gt;Utilise disciplinary consortiums to accelerate discovery and improve reproducibility through the sharing of software&lt;/li&gt;
&lt;li&gt;Understand how AI can speed up research software development&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The research community personnel who develop and maintain research software are just as important as the research software itself, if not more important, as the software will stop working without ongoing maintenance. This maintenance is needed 1) to respond to bugs so that the software continues to be correct, 2) to add new features so that the software continues to be useful as research progresses, 3) to adapt to change in underlying software and hardware or in related software ecosystems, such as changed libraries and computing systems, so that the software continues to work.&lt;/p&gt;
&lt;p&gt;The people who do this work can have many titles, including researchers, research software engineers (RSEs), data scientists, computer scientists, data engineers, bioinformaticians, students, community scientists, and many more (Hettrick et al. 2022; Barker and Buchhorn 2022). The inclusion of improved support for the staff who develop and maintain research software is also emphasised in the UK-focused&lt;a href=&quot;https://www.turing.ac.uk/sites/default/files/2022-09/ukri-requirements-report_final_edits.pdf&quot;&gt; Review of Digital Research Infrastructure Requirements for AI&lt;/a&gt; (Lazauskas et al. 2022). This report’s findings included emphasis that “any investment in any infrastructure for AI would need to be matched by investments in training and support”, with the second highest priority areas identified as funding for RSEs (Lazauskas et al. 2022). The UK’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.4986062&quot;&gt;ExCALIBUR RSE Knowledge Integration Landscape Review&lt;/a&gt; also highlights the need for RSEs to acquire new skills relevant to AI, and notes that “These skill sets also begin to deviate from what is demanded by industries, requiring novel AI software and capabilities’’ (Parsons et al. 2021).&lt;/p&gt;
&lt;p&gt;ReSA’s initial research on recognition of research software in the AI landscape was presented in March 2024 at its &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; meetings. This forum engages representatives from over 60 funding organisations in online meetings and hybrid venues (ReSA 2024a). Attendees of these March meetings were immediately able to utilise these early findings from the presentation to strengthen their own cases for investment in research software within AI-dominated programs, where the criticality of this building block is not yet understood by many in their organisations. It became clear that further research on best practices would support not only funders but a variety of stakeholders in the international research software community.&lt;/p&gt;
&lt;p&gt;The research in this position paper was undertaken as a partnership between &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;ReSA&lt;/a&gt; and the &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt;, one of ReSA’s &lt;a href=&quot;https://www.researchsoft.org/about-resa/&quot;&gt;Founding Members&lt;/a&gt;. One of ReSA’s key functions is to ensure that research software is considered in international discussions on how to advance research capabilities. ReSA is a global organisation that unites decision-makers and influencers across the international research software community. The Digital Research Alliance of Canada is a non-profit organisation funded by the Government of Canada. It advances Canada’s position as a leader in the knowledge economy on the international stage by integrating, championing and funding the infrastructure and activities required, with research software as one of the three main areas. Other community leaders were also brought in on this paper in order to present more balanced perspectives on the need for research software in AI, particularly from institutional and open source perspectives.&lt;/p&gt;
&lt;h2 id=&quot;3-consequences-if-research-software-is-not-supported&quot;&gt;3. Consequences if research software is not supported&lt;/h2&gt;
&lt;p&gt;There is a tendency for AI initiatives to minimise or exclude focus on research software. This minimisation creates challenges. To show this, evidence on the issues in supporting research software, including open-source scientific software, is also presented here.&lt;/p&gt;
&lt;p&gt;Many AI initiatives tend to focus on computing systems, data, and models, considering issues such as the availability of systems that can train models and use them for inference in reasonable time periods; FAIRness of underlying data as well as its suitability for training models, including regularity and labelling; understanding and reducing bias in data and models; and understanding privacy. The fact that AI models are implemented in software, and that software is required for training, is rarely considered. Basically, models are thought of as extensions of data, not of software as well. Consequently, many AI strategies focus on data and models but exclude the underlying software. An example of an AI strategy that does not necessarily adequately include a research software focus is the US National Institutes of Health (NIH) workshop,&lt;a href=&quot;https://www.scgcorp.com/ethicalframework2024/Agenda&quot;&gt; Towards an ethical framework for AI in biomedical and behavioural research&lt;/a&gt;, which focused on data and models, but not the research software inherent in using the data and models (ODSS 2024).&lt;/p&gt;
&lt;p&gt;This challenge is not limited to research software. Discussions of AI capacity often omit open-source software, instead focusing on areas such as talent, funding, data, semiconductors, and compute access (Engler 2021). Like research software, open-source software can advance science but also has significant effects in other areas such as the development of AI standards (Engler 2021). Further, research software is often either open-source itself or depends on open-source software. But considerations for software from AI initiatives, if any, do not normally include open source software maintenance as a priority, nor analysis of its dependency on other software (Nahar et al. Forthcoming). Where dependency analysis does happen, it is usually due to concerns about supply chain security or perceived attack vectors (a pathway or method used to access a network or computer to attempt to exploit system vulnerabilities).&lt;/p&gt;
&lt;p&gt;The nature of open source software as a complex stack and the concomitant extra step of funding those open source software dependencies of the research software necessary for AI is largely ignored. This could reflect a misunderstanding of how open-source dependencies introduce systemic vulnerabilities that need to be addressed and maintained on an ongoing basis or concerns regarding funding many independent projects down the dependency tree. When open-source software is used without planning for future community or dependency support, the result is a more brittle system in the long run — for research software, open-source software, and AI.&lt;/p&gt;
&lt;p&gt;There has been some recent work done on software bills of materials (SBOMs) in open source supply chains, where dependencies are charted out, in part so that their vulnerabilities can be understood (National Security Agency 2024; SCAWG 2022) (and it is relevant to note that research software is often used to map these dependencies). Mapping supply chains is increasingly important for understanding how to shore up digital infrastructure, where large economies depend upon open-source software that is poorly maintained and that may be internationally broken or hijacked or may break (as in the XZ Utils, Heartbleed, or the Log4j incidents (Goodin 2024; Buchanan 2021), or the more recent CrowdStrike failure which caused a global Windows outage (Robins-Early 2024)). However, SBOMs are merely an atlas for understanding dependencies — they are policy agnostic and their creation doesn’t mandate funding or supporting important open-source or research software.&lt;/p&gt;
&lt;p&gt;This paper suggests that infrastructural issues with using and supporting open source software are similar or identical to issues with using research software. Where AI is involved, the same questions of continued support for the research software being used to develop, train, and run the AI systems are raised. Any AI initiative that plans to use global infrastructure, to adapt to new fields and target areas, or that hopes to exist for the long haul must consider the research software that enables those goals.&lt;/p&gt;
&lt;h2 id=&quot;4-challenges-if-research-software-personnel-are-not-supported&quot;&gt;4. Challenges if research software personnel are not supported&lt;/h2&gt;
&lt;p&gt;There is also a need to better support the people who develop and maintain research software that is important to AI-driven research. This is recognised in relation to research software personnel in general, particularly in relation to the training, hiring, and funding of both professional research and technical staff able to reuse, develop, and maintain sustainable research software; appropriate reward and recognition measures that enable career progression for all people involved in the creation and maintenance of research software; and citation practices for research software that recognise substantial contributors to all aspects of the software (Van Tuyl 2023; US-RSE Association and IEEE Computer Society 2023; Barker and Katz 2022a; ReSA 2023). For example, &lt;a href=&quot;https://zenodo.org/records/10473186&quot;&gt;Software and skills for research computing in the UK&lt;/a&gt; recommendations include facilitating detailed analysis of how to professionalise RSE roles; and collaboration between government, funders, and employers to create national policies aimed at improving standards of employment (Barker et al. 2024).&lt;/p&gt;
&lt;p&gt;Whilst many of the issues for research software, in general, are the same for research software to support AI-driven research, one area of difference is in the specifics of skills and training. Human skills, training, and career paths often feature in AI strategies, and it is important that these focus on relevant research software practices. For example, the&lt;a href=&quot;https://www.turing.ac.uk/sites/default/files/2022-09/ukri-requirements-report_final_edits.pdf&quot;&gt; Review of Digital Research Infrastructure Requirements for AI&lt;/a&gt; specifically emphasises the lack of AI skills and training, and career paths for research personnel, including for RSEs. It highlights that these staff often lack formal training, and ongoing professional development is crucial in the fast-paced world of AI tools and techniques (Lazauskas et al. 2022). With many researchers now using GenAI for coding tasks (Nordling 2023, cited in Hosseini et al. 2024), software development skills need to change to reflect this (Caballar 2024; Dursi 2024).&lt;/p&gt;
&lt;h2 id=&quot;5-national-approaches&quot;&gt;5. National approaches&lt;/h2&gt;
&lt;p&gt;AI is now seen as a geopolitical asset, and as international organisations and a range of countries seek to show leadership for AI in science, some countries are operationalising AI strategies that could support the critical element of research software. However, more focus is needed. One example of discussing software within a national AI strategy is the US &lt;a href=&quot;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&quot;&gt;National Artificial Intelligence Research Resource&lt;/a&gt; (NAIRR). NAIRR aims to provide a shared national research infrastructure for responsible discovery and innovation in AI, to address the fact that many researchers lack the necessary access to the computing, data, software and educational resources needed. The NAIRR pilot’s four operational focus areas include one area dedicated to software, to “facilitate and investigate interoperable use of AI software, platforms, tools and services for NAIRR pilot resources” (NSF 2024). However, there are potential challenges with this approach as the focus is on interoperability of existing software, which assumes that sustainable software is already in place.&lt;/p&gt;
&lt;p&gt;Many countries also have existing investments in research software (Barker and Katz 2022b; ReSA 2024b) that national initiatives have the potential to build on. The UK’s &lt;a href=&quot;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&quot;&gt;AI Research Resource&lt;/a&gt; (AIRR) is another example of a national initiative, which focuses on increasing computational power to support AI-driven research (UKRI 2023), although its funding is now uncertain (Trueman 2024). Whilst AIRR does not seem to include a focus on research software, AIRR is a key component of UK Research and Innovation (UKRI)’s &lt;a href=&quot;https://www.ukri.org/what-we-do/creating-world-class-research-and-innovation-infrastructure/digital-research-infrastructure/&quot;&gt;Digital Research Infrastructure&lt;/a&gt; (DRI) which has featured a number of recent investments in research software, including funding of research technical professionals (RTPs), such as RSEs. For example, the Engineering and Physical Sciences Research Council (EPSRC) and UKRI DRI have invested £16 million to support community-driven projects providing training and development for RTPs (UKRI 2024a). UKRI’s &lt;a href=&quot;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&quot;&gt;Digital RTP Skills NetworkPlus&lt;/a&gt; aims to explore key challenges and interventions related to skills and careers that are faced by digital RTP communities across the UK research and innovation landscape (UKRI 2024b).&lt;/p&gt;
&lt;p&gt;Canada has been a leader in AI, as the first country in the world to put in place in 2017 a fully-funded AI strategy, the &lt;a href=&quot;https://ised-isde.canada.ca/site/ai-strategy/en&quot;&gt;Pan-Canadian AI Strategy&lt;/a&gt; (ISED 2022). The strategy included the establishment of a national program of research chairs to recruit and retain top researchers at Canadian universities, the establishment of three national AI institutes to be global centres of training and research excellence and the creation of a Pan-Canadian AI Compute Environment (PAICE) platform. The Digital Research Alliance of Canada’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.10214741&quot;&gt;National Research Software Strategy&lt;/a&gt; for 2025–2030 (Digital Research Alliance of Canada, National Research Software Strategy Working Group 2023) also reviewed (inter)national research software funding programs in support of AI, deep learning, and ML-facilitated research. Before the Alliance, CANARIE has been a national Research Software funder and service provider since 2007, whose successful research software initiatives had resulted in the development of sophisticated software tools, known as research platforms, that typically support end-to-end research workflow within a specific domain. New platforms re-used software components previously developed through CANARIE funding, and contributed additional components back to the research community, creating a powerful cycle of software development and reuse (CANARIE 2024). The Alliance is now using the &lt;a href=&quot;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&quot;&gt;Research Software Directory&lt;/a&gt; to continue promoting the visibility, impact, and reuse of the Canadian research software (Digital Research Alliance of Canada 2024).&lt;/p&gt;
&lt;h2 id=&quot;6-recommendations-for-research-software-to-support-ai&quot;&gt;6. Recommendations for research software to support AI&lt;/h2&gt;
&lt;p&gt;Research software needs to be included in AI strategies. Our recommendations for doing so are listed below, organised in three areas from the &lt;a href=&quot;https://doi.org/10.5281/zenodo.8325436&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt; (ReSA 2023):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research software practice:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI strategies and funding must recognise that research software is a key part of the (publicly funded) AI pipeline and that AI is dependent on software, and therefore should stimulate the development and maintenance of research software to ensure the success of the AI work.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Research software ecosystem:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because AI-driven research is dependent on the existing research software ecosystem, AI strategies should provide long-term support for its elements, including personnel, communities, and infrastructure, and should add new elements that focus on AI-specific parts as needed.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Research software personnel:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because the existing research software ecosystem that supports AI-driven research is dependent on research software personnel, AI strategies should facilitate appropriate reward and recognition measures that enable career progression for all people involved in the creation and maintenance of research software that supports AI-driven research.&lt;/p&gt;
&lt;p&gt;Other ways to help ensure that the focus on technological infrastructure to support AI acceleration includes research software and its personnel as a vital part of that infrastructure include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;Signing&lt;/a&gt; the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability (ADORE.software)&lt;/a&gt;, which represents a first step to formalise, on a global level, the basic principles and recommendations related to funding the sustainability of research software, including the people needed to achieve this goal.&lt;/li&gt;
&lt;li&gt;Supporting ReSA in its aim to ensure that research software is considered in international discussions on how to advance research capabilities. Become a ReSA &lt;a href=&quot;https://www.researchsoft.org/membership/&quot;&gt;Organisational Member&lt;/a&gt;, &lt;a href=&quot;https://www.researchsoft.org/tf-support/&quot;&gt;support a task force&lt;/a&gt;, or &lt;a href=&quot;https://www.researchsoft.org/donate/&quot;&gt;donate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For funders, joining the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, a global collaboration of funding organisations committed to supporting research software, and those who develop and maintain it, as fundamental and vital to research.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Barker, Michelle, Elena Breitmoser, Philippa Broadbent, Neil Chue Hong, Simon Hettrick, Ioanna Lampaki, Anthony Quinn, and Rebecca Taylor. 2024. ‘Software and Skills for Research Computing in the UK’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10473186&quot;&gt;https://doi.org/10.5281/ZENODO.10473186&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Markus Buchhorn. 2022. ‘Research Software Capability in Australia’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6335998&quot;&gt;https://doi.org/10.5281/ZENODO.6335998&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, Neil P. Chue Hong, Daniel S. Katz, Anna-Lena Lamprecht, Carlos Martinez-Ortiz, Fotis Psomopoulos, Jennifer Harrow, et al. 2022. ‘Introducing the FAIR Principles for Research Software’. Scientific Data* 9 (1): 622. &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;https://doi.org/10.1038/s41597-022-01710-x&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Daniel S Katz. 2022a. ‘Encouraging Entry, Retention, Diversity and Inclusion in Research Software Careers’. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.7117842&quot;&gt;https://doi.org/10.5281/ZENODO.7117842&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, and Daniel S. Katz. 2022b. ‘Overview of Research Software Funding Landscape’, February. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6102487&quot;&gt;https://doi.org/10.5281/ZENODO.6102487&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Barker, Michelle, Daniel S. Katz, and Alejandra Gonzalez-Beltran. 2020. ‘Evidence for the Importance of Research Software’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.3884311&quot;&gt;https://doi.org/10.5281/ZENODO.3884311&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Buchanan, Bill. 2021. ‘Log4j: The Worst Vulnerability In Nearly A Decade?’ &lt;em&gt;Medium&lt;/em&gt; (blog). 2021. &lt;a href=&quot;https://medium.com/asecuritysite-when-bob-met-alice/log4j-the-worst-vulnerability-in-nearly-a-decade-e0cc80cbb49a&quot;&gt;https://medium.com/asecuritysite-when-bob-met-alice/log4j-the-worst-vulnerability-in-nearly-a-decade-e0cc80cbb49a&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Caballar, Rina Diane. 2024. ‘AI Copilots Are Changing How Coding Is Taught — IEEE Spectrum’. 2 May 2024. &lt;a href=&quot;https://spectrum.ieee.org/ai-coding&quot;&gt;https://spectrum.ieee.org/ai-coding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CANARIE. 2024. ‘Funded Research Software Platforms’. 2024. &lt;a href=&quot;https://www.canarie.ca/software/platforms/&quot;&gt;https://www.canarie.ca/software/platforms/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Digital Research Alliance of Canada. 2024. ‘Research Software Directory’. 2024. &lt;a href=&quot;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&quot;&gt;https://research-software-directory.org/organisations/digital-research-alliance-of-canada?tab=software&amp;#x26;order=is_featured&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Digital Research Alliance of Canada, National Research Software Strategy Working Group. 2023. ‘National Research Software Strategy 2023’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10214741&quot;&gt;https://doi.org/10.5281/ZENODO.10214741&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dursi, Jonathan. 2024. ‘We Need To Talk About AI’. &lt;em&gt;Research Computing Teams&lt;/em&gt; 183 (June). &lt;a href=&quot;https://newsletter.researchcomputingteams.org/archive/rct-183-we-need-to-talk-about-ai-plus-upfront/&quot;&gt;https://newsletter.researchcomputingteams.org/archive/rct-183-we-need-to-talk-about-ai-plus-upfront/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Engler, Alex. 2021. ‘How Open-Source Software Shapes AI Policy’. Brookings. 10 August 2021. &lt;a href=&quot;https://www.brookings.edu/articles/how-open-source-software-shapes-ai-policy/&quot;&gt;https://www.brookings.edu/articles/how-open-source-software-shapes-ai-policy/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Goodin, Dan. 2024. ‘The XZ Backdoor: Everything You Need to Know’. Wired. 2 April 2024. &lt;a href=&quot;https://www.wired.com/story/xz-backdoor-everything-you-need-to-know/&quot;&gt;https://www.wired.com/story/xz-backdoor-everything-you-need-to-know/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gruenpeter, Morane, Daniel S. Katz, Anna-Lena Lamprecht, Tom Honeyman, Daniel Garijo, Alexander Struck, Anna Niehues, et al. 2021. ‘Defining Research Software: A Controversial Discussion’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.5504016&quot;&gt;https://doi.org/10.5281/ZENODO.5504016&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hettrick, Simon, Radovan Bast, Steve Crouch, Claire Bradley, Philippe, Botzki, Alex, Carver, Jeffrey, et al. 2022. ‘International RSE Survey 2022’. &lt;a href=&quot;https://softwaresaved.github.io/international-survey-2022/&quot;&gt;https://softwaresaved.github.io/international-survey-2022/&lt;/a&gt;. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6884882&quot;&gt;https://doi.org/10.5281/ZENODO.6884882&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hocquet, Alexandre, Frédéric Wieber, Gabriele Gramelsberger, Konrad Hinsen, Markus Diesmann, Fernando Pasquini Santos, Catharina Landström, et al. 2024. ‘Software in Science Is Ubiquitous yet Overlooked’. &lt;em&gt;Nature Computational Science&lt;/em&gt;, July. &lt;a href=&quot;https://doi.org/10.1038/s43588-024-00651-2&quot;&gt;https://doi.org/10.1038/s43588-024-00651-2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ISED. 2022. ‘Pan-Canadian Artificial Intelligence Strategy’. Home page; Innovation, Science and Economic Development Canada. 20 July 2022. &lt;a href=&quot;https://ised-isde.canada.ca/site/ai-strategy/en/pan-canadian-artificial-intelligence-strategy&quot;&gt;https://ised-isde.canada.ca/site/ai-strategy/en/pan-canadian-artificial-intelligence-strategy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lazauskas, Tomas, Jennifer Ding, Neil Brown, Reda Nausedaite, Felix Dijkstal, Aaron Vinnik, Bruno Raabe, et al. 2022. ‘Review of Digital Research Infrastructure Requirements for AI’. &lt;a href=&quot;https://doi.org/10.13140/RG.2.2.29376.00009&quot;&gt;https://doi.org/10.13140/RG.2.2.29376.00009&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Martineau, Kim. 2021. ‘What Is Generative AI?’ IBM Research. 9 February 2021. &lt;a href=&quot;https://research.ibm.com/blog/what-is-generative-AI&quot;&gt;https://research.ibm.com/blog/what-is-generative-AI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nahar, Nadia, Haoran Zhang, Grace Lewis, Shurui Zhou, and Christian Kästner. Forthcoming. ‘The Product Beyond the Model — An Empirical Study of Repositories of Open-Source ML Products’. In . &lt;a href=&quot;https://www.cs.cmu.edu/~ckaestne/publications.html&quot;&gt;https://www.cs.cmu.edu/~ckaestne/publications.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;National Security Agency. 2024. ‘Recommendations for Software Bill of Materials (SBOM) Management’. &lt;a href=&quot;https://media.defense.gov/2023/Dec/14/2003359097/-1/-1/0/CSI-SCRM-SBOM-MANAGEMENT.PDF&quot;&gt;https://media.defense.gov/2023/Dec/14/2003359097/-1/-1/0/CSI-SCRM-SBOM-MANAGEMENT.PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nordling, Linda. 2023. ‘How ChatGPT Is Transforming the Postdoc Experience’. &lt;em&gt;Nature&lt;/em&gt; 622 (7983): 655–57. &lt;a href=&quot;https://doi.org/10.1038/d41586-023-03235-8&quot;&gt;https://doi.org/10.1038/d41586-023-03235-8&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;NSF. 2024. ‘National Artificial Intelligence Research Resource Pilot’. 2024. &lt;a href=&quot;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&quot;&gt;https://new.nsf.gov/focus-areas/artificial-intelligence/nairr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ODSS. 2024. ‘Toward an Ethical Framework for AI in Biomedical and Behavioral Research’. 2024. &lt;a href=&quot;https://www.scgcorp.com/ethicalframework2024/Agenda&quot;&gt;https://www.scgcorp.com/ethicalframework2024/Agenda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OECD. 2023. &lt;em&gt;Artificial Intelligence in Science: Challenges, Opportunities and the Future of Research&lt;/em&gt;. OECD. &lt;a href=&quot;https://doi.org/10.1787/a8d820bd-en&quot;&gt;https://doi.org/10.1787/a8d820bd-en&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Parsons, Mark, Alastair Basden, Richard Bower, Neil P. Chue Hong, Davide Constanzo, Shaun Witt, Luigi Del Debbio, et al. 2021. ‘ExCALIBUR Research Software Engineer Knowledge Integration Landscape Review’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.4986062&quot;&gt;https://doi.org/10.5281/ZENODO.4986062&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ReSA. 2023. ‘Amsterdam Declaration on Funding Research Software Sustainability’, August. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.8325436&quot;&gt;https://doi.org/10.5281/ZENODO.8325436&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024a. ‘Research Software Funders Forum’. 2024. &lt;a href=&quot;https://researchsoft.org/funders-forum/&quot;&gt;https://researchsoft.org/funders-forum/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024b. ‘Research Software Funding Opportunities’. 2024. &lt;a href=&quot;https://researchsoft.org/funding-opportunities/&quot;&gt;https://researchsoft.org/funding-opportunities/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Robins-Early, Nick. 2024. ‘What Is CrowdStrike, and How Did It Cause a Global Windows Outage?’ &lt;em&gt;The Guardian&lt;/em&gt;, 19 July 2024. &lt;a href=&quot;https://www.theguardian.com/technology/article/2024/jul/19/what-is-crowdstrike-microsoft-windows-outage&quot;&gt;https://www.theguardian.com/technology/article/2024/jul/19/what-is-crowdstrike-microsoft-windows-outage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;SCAWG. 2022. ‘Recommendations to Improve the Resilience of Canada’s Digital Supply Chain’. &lt;a href=&quot;https://ised-isde.canada.ca/site/spectrum-management-telecommunications/sites/default/files/attachments/2022/CFDIR-June2022-recommendations.pdf&quot;&gt;https://ised-isde.canada.ca/site/spectrum-management-telecommunications/sites/default/files/attachments/2022/CFDIR-June2022-recommendations.pdf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Strasser, Carly, Kate Hertweck, Josh Greenberg, Dario Taraborelli, and Elizabeth Vu. 2022. ’10 Simple Rules for Funding Scientific Open Source Software’, June. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.6611500&quot;&gt;https://doi.org/10.5281/ZENODO.6611500&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Trueman, Charlotte. 2024. ‘UK Government Shelves £1.3bn of Tech and AI Projects; Scraps Plans for First Exascale Supercomputer in Edinburgh’. 2 August 2024. &lt;a href=&quot;https://www.datacenterdynamics.com/en/news/uk-government-shelves-13bn-of-tech-and-ai-projects-scraps-plans-for-first-exascale-supercomputer-in-edinburgh/&quot;&gt;https://www.datacenterdynamics.com/en/news/uk-government-shelves-13bn-of-tech-and-ai-projects-scraps-plans-for-first-exascale-supercomputer-in-edinburgh/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UKRI. 2023. ‘£300 Million to Launch First Phase of New AI Research Resource’. 1 November 2023. &lt;a href=&quot;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&quot;&gt;https://www.ukri.org/news/300-million-to-launch-first-phase-of-new-ai-research-resource/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024a. ‘New Funding to Support Research Technical Professionals’. 18 March 2024. &lt;a href=&quot;https://www.ukri.org/news/new-funding-to-support-research-technical-professionals/&quot;&gt;https://www.ukri.org/news/new-funding-to-support-research-technical-professionals/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;— — — . 2024b. ‘UKRI Digital Research Technical Professional Skills NetworkPlus’. 22 April 2024. &lt;a href=&quot;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&quot;&gt;https://www.ukri.org/opportunity/ukri-digital-research-technical-professional-skills-networkplus/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;US-RSE Association and IEEE Computer Society. 2023. ‘Research Software Engineers: Creating a Career Path — and a Career’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.10073232&quot;&gt;https://doi.org/10.5281/ZENODO.10073232&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Van Tuyl, Steve (Ed.). 2023. ‘Hiring, Managing, and Retaining Data Scientists and Research Software Engineers in Academia: A Career Guidebook from ADSA and US-RSE’. Zenodo. &lt;a href=&quot;https://doi.org/10.5281/ZENODO.8274378&quot;&gt;https://doi.org/10.5281/ZENODO.8274378&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/research-software-is-critical-to-the-fut-cea947aa.CtbIw_yP.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Scripting vs. Programming</title><link>https://blog.esciencecenter.nl/posts/2024-08-01---scripting-vs-programming</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-08-01---scripting-vs-programming</guid><description>&lt;p&gt;][Lourens Veen]·Apr 26, 2023&lt;/p&gt;
&lt;p&gt;Any remaining differences are usually due to particular features supported by certain languages. In R for example, you can write down a statistical model equation, for which it has a special syntax using the &lt;code&gt;~&lt;/code&gt; symbol. There’s no equivalent of that in Python or C or Pascal, because those languages weren’t designed for statistics.&lt;/p&gt;
&lt;h3 id=&quot;structure&quot;&gt;Structure&lt;/h3&gt;
&lt;p&gt;Scripts typically have a simple structure. They consist of a single file, all variables are global, and there may be a function or two but mostly it’s a straightforward list of instructions. This works fine for small scripts, but it becomes impossible to manage for a thousand- or million-line library. To keep those organised, you need functions, classes, packages/modules and namespaces.&lt;/p&gt;
&lt;p&gt;Languages like Java and C++ are designed for this, and do well on this criterion. Python is actually pretty good as well, it does have all of these and there are some large programs written in it. These features are anyway quite common in modern languages, even ones intended for scripting-type work.&lt;/p&gt;
&lt;p&gt;Of course, adding features makes the language more complex (i.e., it makes the manual bigger). Even if you don’t use them, others will, and so you’ll have to learn how they work if you want to be able to use other people’s packages for example. So there is a cost to this additional functionality as well as a benefit, which is what Jisk was getting at with his comment on languages being too “computer science oriented” for what he wants to do.&lt;/p&gt;
&lt;h3 id=&quot;error-handling&quot;&gt;Error handling&lt;/h3&gt;
&lt;p&gt;Finally, error handling. Your basic script handles errors in a basic way: it prints an error message (comprehensible or not) and then halts. Normally, this isn’t done by the script itself but by the programming environment it runs in, with the script simply ignoring the possibility of anything going wrong. This actually works quite well in a notebook environment, where you execute one statement at a time (so it’s usually clear where the problem is) and where there’s a human to read the error message and handle the problem.&lt;/p&gt;
&lt;p&gt;For a web service, or a complex library, or a desktop application, crashing whenever something goes wrong is not acceptable. Errors need to be handled, and only if there’s nothing the program can do to fix it does the error get forwarded to a human, after which we continue with handling the next request. At the language level, this is implemented either through returning an error code from a function, or by using exceptions. Older languages like C and Fortran don’t support exceptions, so all errors have to be signalled and handled explicitly. This means that if you do it right, basically every function call is &lt;a href=&quot;https://github.com/SecConNet/net-admin-helper/blob/8bd39c6ca5fb4c7787bba72b060485e7cc57e3aa/src/container_wireguard.c#L205&quot;&gt;followed by an “if” block that checks for errors and handles them&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This gets very very wordy, so newer languages like Java and Python support exceptions. Exceptions automate keeping track of errors, and by default escalate any errors in a function you called to the function that called you, and so on. In other words, if something goes wrong, you tell the boss, who tells her boss, etc. until the problem reaches someone who can decide what to do. If the error reaches the top without having been solved then the program crashes and the user will have to figure it out, but ideally something handled the problem before we got to that point. Crucially, if the programmer ignores the possibility of errors, then they will end up with the user. That’s not so good, but it’s better than the error being quietly ignored, as would be the case with ignoring returned error codes.&lt;/p&gt;
&lt;p&gt;One disadvantage of exceptions is that to be completely robust, you need to carefully keep track of which exceptions can be raised by functions you call, and make sure you handle them all. In Python, this is pretty much impossible because they’re not documented very well. Java provides syntax for this, and forces you to declare all exceptions a function can raise, which is much better for reliability but is also sure to make Jisk unhappy in his quest for a simple language.&lt;/p&gt;
&lt;p&gt;It’s interesting to see that after all the exceptions in C++ and Java, in yet newer languages like Rust and Go there’s a bit more emphasis on returning errors again. There’s the idea there that most errors are just “normal” possible outcomes of calling a function that should be handled immediately, and that an exception-like “panic” system is to be used only in truly exceptional circumstances. Meanwhile in Python it’s the other way around, and exceptions are sometimes even used for things that are expected to happen during normal control flow (e.g. StopIteration).&lt;/p&gt;
&lt;p&gt;There’s more to say and explain about error handling, and we’ll come back to it in a future TEC. For now, the point is that languages that allow you to completely ignore the possibility of an error occurring are more suitable for scripting, while languages that require you to take possible errors into account lead to more reliable programs.&lt;/p&gt;
&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;So, which language is best for which purpose? Python is obviously good for scripting, and Julia is an interesting alternative that I think may be a better fit for Jisk than Go, seeing as he is interested in calculating things. R seems to work well as a command-line interface for doing statistics but I don’t like it as a programming language (although the Tidyverse is a good development).&lt;/p&gt;
&lt;p&gt;On the programs and libraries side, I’ve built a few slightly bigger systems (in the tens-of-files, thousands-of-lines range) in Python, and it works pretty well, plus you can still put something together very quickly. The downside is that the dynamic typing, lack of encapsulation and lack of exception specifications make it more difficult to make things robust, and performance is also nothing to write home about. Potentially better if slower to work in alternatives would be Java, (modern) C++, and new kid on the block Rust. For now, C++ is my go-to language if I need more performance, even though it’s very complex and by no means perfect.&lt;/p&gt;
&lt;p&gt;What works best for you depends on what you want to do, how much time you have available to learn, a bit on taste, and on external factors like availability of software and of support from the people around you. Many concepts carry over from one language to another though, so don’t worry too much about choosing the wrong one: once you know one programming language, learning others gets a lot easier.&lt;/p&gt;
&lt;p&gt;Well, that concludes the first instalment of The Engineering Corner*. Hope you liked it! Do you write scripts or programs or both? What’s your favourite programming language? Did you like this topic? Was this too basic or too advanced or maybe just right? What would you like to read about next? I’d love to hear about all these things in the comments below. In the mean time:&lt;/p&gt;
&lt;p&gt;Choo choo! Happy Engineering!&lt;/p&gt;
&lt;p&gt;Lourens&lt;/p&gt;
&lt;p&gt;← &amp;#x3C;previous TEC not found&gt; — TEC 1: &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;Better scripts with typing&lt;/a&gt; →&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#2e2f&quot;&gt;[0]&lt;/a&gt; &lt;em&gt;Control flow&lt;/em&gt; refers to the order in which commands are executed, and to branches (if..then) and loops (for.., while..) causing them to be executed not at all, or more than once. In other words, the path through the code taken by the computer’s “cursor” as the code runs.&lt;/p&gt;</description><pubDate>Thu, 01 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;][Lourens Veen]·Apr 26, 2023&lt;/p&gt;
&lt;p&gt;Any remaining differences are usually due to particular features supported by certain languages. In R for example, you can write down a statistical model equation, for which it has a special syntax using the &lt;code&gt;~&lt;/code&gt; symbol. There’s no equivalent of that in Python or C or Pascal, because those languages weren’t designed for statistics.&lt;/p&gt;
&lt;h3 id=&quot;structure&quot;&gt;Structure&lt;/h3&gt;
&lt;p&gt;Scripts typically have a simple structure. They consist of a single file, all variables are global, and there may be a function or two but mostly it’s a straightforward list of instructions. This works fine for small scripts, but it becomes impossible to manage for a thousand- or million-line library. To keep those organised, you need functions, classes, packages/modules and namespaces.&lt;/p&gt;
&lt;p&gt;Languages like Java and C++ are designed for this, and do well on this criterion. Python is actually pretty good as well, it does have all of these and there are some large programs written in it. These features are anyway quite common in modern languages, even ones intended for scripting-type work.&lt;/p&gt;
&lt;p&gt;Of course, adding features makes the language more complex (i.e., it makes the manual bigger). Even if you don’t use them, others will, and so you’ll have to learn how they work if you want to be able to use other people’s packages for example. So there is a cost to this additional functionality as well as a benefit, which is what Jisk was getting at with his comment on languages being too “computer science oriented” for what he wants to do.&lt;/p&gt;
&lt;h3 id=&quot;error-handling&quot;&gt;Error handling&lt;/h3&gt;
&lt;p&gt;Finally, error handling. Your basic script handles errors in a basic way: it prints an error message (comprehensible or not) and then halts. Normally, this isn’t done by the script itself but by the programming environment it runs in, with the script simply ignoring the possibility of anything going wrong. This actually works quite well in a notebook environment, where you execute one statement at a time (so it’s usually clear where the problem is) and where there’s a human to read the error message and handle the problem.&lt;/p&gt;
&lt;p&gt;For a web service, or a complex library, or a desktop application, crashing whenever something goes wrong is not acceptable. Errors need to be handled, and only if there’s nothing the program can do to fix it does the error get forwarded to a human, after which we continue with handling the next request. At the language level, this is implemented either through returning an error code from a function, or by using exceptions. Older languages like C and Fortran don’t support exceptions, so all errors have to be signalled and handled explicitly. This means that if you do it right, basically every function call is &lt;a href=&quot;https://github.com/SecConNet/net-admin-helper/blob/8bd39c6ca5fb4c7787bba72b060485e7cc57e3aa/src/container_wireguard.c#L205&quot;&gt;followed by an “if” block that checks for errors and handles them&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This gets very very wordy, so newer languages like Java and Python support exceptions. Exceptions automate keeping track of errors, and by default escalate any errors in a function you called to the function that called you, and so on. In other words, if something goes wrong, you tell the boss, who tells her boss, etc. until the problem reaches someone who can decide what to do. If the error reaches the top without having been solved then the program crashes and the user will have to figure it out, but ideally something handled the problem before we got to that point. Crucially, if the programmer ignores the possibility of errors, then they will end up with the user. That’s not so good, but it’s better than the error being quietly ignored, as would be the case with ignoring returned error codes.&lt;/p&gt;
&lt;p&gt;One disadvantage of exceptions is that to be completely robust, you need to carefully keep track of which exceptions can be raised by functions you call, and make sure you handle them all. In Python, this is pretty much impossible because they’re not documented very well. Java provides syntax for this, and forces you to declare all exceptions a function can raise, which is much better for reliability but is also sure to make Jisk unhappy in his quest for a simple language.&lt;/p&gt;
&lt;p&gt;It’s interesting to see that after all the exceptions in C++ and Java, in yet newer languages like Rust and Go there’s a bit more emphasis on returning errors again. There’s the idea there that most errors are just “normal” possible outcomes of calling a function that should be handled immediately, and that an exception-like “panic” system is to be used only in truly exceptional circumstances. Meanwhile in Python it’s the other way around, and exceptions are sometimes even used for things that are expected to happen during normal control flow (e.g. StopIteration).&lt;/p&gt;
&lt;p&gt;There’s more to say and explain about error handling, and we’ll come back to it in a future TEC. For now, the point is that languages that allow you to completely ignore the possibility of an error occurring are more suitable for scripting, while languages that require you to take possible errors into account lead to more reliable programs.&lt;/p&gt;
&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;So, which language is best for which purpose? Python is obviously good for scripting, and Julia is an interesting alternative that I think may be a better fit for Jisk than Go, seeing as he is interested in calculating things. R seems to work well as a command-line interface for doing statistics but I don’t like it as a programming language (although the Tidyverse is a good development).&lt;/p&gt;
&lt;p&gt;On the programs and libraries side, I’ve built a few slightly bigger systems (in the tens-of-files, thousands-of-lines range) in Python, and it works pretty well, plus you can still put something together very quickly. The downside is that the dynamic typing, lack of encapsulation and lack of exception specifications make it more difficult to make things robust, and performance is also nothing to write home about. Potentially better if slower to work in alternatives would be Java, (modern) C++, and new kid on the block Rust. For now, C++ is my go-to language if I need more performance, even though it’s very complex and by no means perfect.&lt;/p&gt;
&lt;p&gt;What works best for you depends on what you want to do, how much time you have available to learn, a bit on taste, and on external factors like availability of software and of support from the people around you. Many concepts carry over from one language to another though, so don’t worry too much about choosing the wrong one: once you know one programming language, learning others gets a lot easier.&lt;/p&gt;
&lt;p&gt;Well, that concludes the first instalment of The Engineering Corner*. Hope you liked it! Do you write scripts or programs or both? What’s your favourite programming language? Did you like this topic? Was this too basic or too advanced or maybe just right? What would you like to read about next? I’d love to hear about all these things in the comments below. In the mean time:&lt;/p&gt;
&lt;p&gt;Choo choo! Happy Engineering!&lt;/p&gt;
&lt;p&gt;Lourens&lt;/p&gt;
&lt;p&gt;← &amp;#x3C;previous TEC not found&gt; — TEC 1: &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;Better scripts with typing&lt;/a&gt; →&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#2e2f&quot;&gt;[0]&lt;/a&gt; &lt;em&gt;Control flow&lt;/em&gt; refers to the order in which commands are executed, and to branches (if..then) and loops (for.., while..) causing them to be executed not at all, or more than once. In other words, the path through the code taken by the computer’s “cursor” as the code runs.&lt;/p&gt;</content:encoded><author>Lourens Veen</author></item><item><title>Decoding Research Software Impact: A Collaborative Journey</title><link>https://blog.esciencecenter.nl/posts/2024-07-26---decoding-research-software-impact-a-collaborative-journey</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-07-26---decoding-research-software-impact-a-collaborative-journey</guid><description>&lt;h1 id=&quot;decoding-research-software-impact-a-collaborative-journey&quot;&gt;&lt;strong&gt;Decoding Research Software Impact: A Collaborative Journey&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;on-23-april-2024-the-first-national-research-software-day-took-place-in-hilversum-the-netherlands-during-the-unconference-part-of-the-program-deekshitha-ran-the-session-titled-decoding-research-software-impact-a-collaborative-journey-where-a-model-for-research-software-impact-was-at-the-center-of-the-discussion&quot;&gt;On 23 April 2024, the first ‘&lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt;’ took place in Hilversum, the Netherlands. During the unconference part of the program, &lt;a href=&quot;https://www.linkedin.com/in/deekshitha-m/&quot;&gt;Deekshitha&lt;/a&gt; ran the session titled, ‘Decoding Research Software Impact: A Collaborative Journey’, where a model for research software impact was at the center of the discussion.&lt;/h2&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Authors: Deekshitha¹, Carlos Martinez Ortiz¹, Rena Bakhshi¹, Jason Maassen¹, Rob van Nieuwpoort², Slinger Jansen³, Ton Smeele³, Andrew Treloar⁴, Louise Bezuidenhout², Maarten Schermer³, Laurents Sesink⁵, Pui-Kei Fung³, and Colette Bos¹&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-f6a11552.CWh0HtBC_Z2aDNE7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@aleexcif?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Soliman Cifuentes&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this session, participants collaborated on the topic of research software impact. Participants took the perspective of policymakers, funders, researchers and Research Software Engineers (RSEs) to explore perspectives of research software impact in four 15-minute rounds, in which participants attempted to answer a set of questions from the perspective they were exploring. After each round, the participants changed groups to cover a different perspective. This workshop aimed to define the impact of research software from the perspectives of these 4 stakeholders. Here the term impact refers to the difference the research software makes to the research process or community.&lt;/p&gt;
&lt;p&gt;Measuring the impact of research software is the main focus of Deekshitha’s PhD study. Currently, there is a lack of sufficient methods to accurately measure research software impact. Her study seeks to develop an impact model that will enable all stakeholders of research software to measure its impact effectively and ensure recognition for the individuals behind its development. During the sessions, four questions were discussed (from different perspectives):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the goals of measuring research software impact?&lt;/li&gt;
&lt;li&gt;How can research software impact be measured?&lt;/li&gt;
&lt;li&gt;Which measures correspond to which goal?&lt;/li&gt;
&lt;li&gt;How should these goals be prioritized?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;researchers-and-research-software-engineers-perspective&quot;&gt;Researchers and Research Software Engineers’ perspective&lt;/h2&gt;
&lt;p&gt;From the researcher’s and RSEs perspective, we have identified six goals, as shown in the Figure 1. Among these, recognition and a track record for funding are essential goals for this group. Despite differing priorities, researchers and RSEs share similar perspectives. Therefore, they are represented together in a single diagram illustrating both viewpoints.&lt;/p&gt;
&lt;p&gt;The figure below illustrates the goals and the factors that help measure their impact and interdependencies. The first branch represents the goals (Answer to question 1), the second connection illustrates how to measure those goals (impact factors and their connection with goals- Answer to questions 2 and 3), and the third branch shows their prioritization value (Answer to question 4) along with the corresponding group (Researchers and RSEs; National and Institutional; no other group identified for Funders). This prioritization resulted from discussions with the workshop participants and the value starts from one. For example, in Figure 1, there are three impact factors grouped under Researchers. Based on the discussion, we found that the impact factor ‘citations’ has higher priority compared to other factors, so it is ranked 1 in the category for Researchers. Grey-colored boxes in front of the impact factors indicate the groups they belong to (eg: Researchers and RSEs). Additionally, impact factors unrelated to the goals (or we couldn’t find a relation with identified goals) are presented in separate black-colored boxes (see Figure 2 and Figure 3).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;349&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-a82b0191.Bq8WrD-D_1ge0nk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Researchers/RSEs perspective&lt;/p&gt;
&lt;h2 id=&quot;funders-perspective&quot;&gt;Funders perspective&lt;/h2&gt;
&lt;p&gt;Funders like NWO, SURF, and eScience Center who support research software projects, prioritize demonstrating value for money and aligning with international strategic goals like Open Science. By emphasizing research software impact, funders can act as change agents, influencing research and ensuring it aligns with broader institutional objectives. Selecting projects with significant impact enhances the funders’ image and showcases their commitment to supporting valuable and innovative research. Furthermore, funders contribute to research and educational institutions by funding unique and impactful software, thus enhancing their overall value.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;361&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-d9d7efe8.COVBJfrs_NFPpS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Funders perspective&lt;/p&gt;
&lt;h2 id=&quot;policy-makers-perspective&quot;&gt;Policy makers perspective&lt;/h2&gt;
&lt;p&gt;Policy makers and funders play distinct yet interconnected roles within governance and funding, particularly in research, education, and public policy sectors. Funders focus primarily on providing financial support and resources to achieve specific objectives and outcomes. On the other hand, policy makers are responsible for formulating and implementing regulations, guidelines, and directives that shape the strategic direction and operational frameworks of institutions and organizations.&lt;/p&gt;
&lt;p&gt;In terms of policy making, we realized there should be a distinction between national and international policies to ensure alignment with the institutional mission and purpose, maintain the independence and sovereignty of research institutes, and adequately consider risk assessment, marketability, and valorization. Figure 3 shows goals, impact factors, and their groups with priority values from the policymakers’ perspective.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;312&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-a6d8bab9.FE1foMTn_2kmlyN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Policy makers perspective&lt;/p&gt;
&lt;h2 id=&quot;take-home-message&quot;&gt;Take home message&lt;/h2&gt;
&lt;p&gt;The collaborative and dynamic nature of the session made it a memorable experience, combining serious discussion with a touch of fun. This approach not only sparked insightful conversations but also strengthened the community’s commitment to advancing the understanding and measurement of research software impact. Additionally, everyone agrees that RSEs are not appropriately recognized for their work, and recognition is one of the main goals for measuring impact. Funders have open science goals to achieve and policymakers want to ensure value for money.&lt;/p&gt;
&lt;p&gt;We look forward to continuing this journey and invite all who are passionate about the transformative power of research software to join us. Together, we can build a robust and internationally recognized model for assessing research software impact. If you’re eager to join this impactful journey, reach out and we can connect over a cup of coffee to further the discussion.&lt;/p&gt;
&lt;p&gt;Credit: We want to credit the tool we used, the free version of EdrawMind, in this blog post.&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.universiteitleiden.nl/en&quot;&gt;Leiden University&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.uu.nl/&quot;&gt;Utrecht University&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ardc.edu.au/&quot;&gt;Australian Research Data Commons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.surf.nl/&quot;&gt;SURF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Fri, 26 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;decoding-research-software-impact-a-collaborative-journey&quot;&gt;&lt;strong&gt;Decoding Research Software Impact: A Collaborative Journey&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;on-23-april-2024-the-first-national-research-software-day-took-place-in-hilversum-the-netherlands-during-the-unconference-part-of-the-program-deekshitha-ran-the-session-titled-decoding-research-software-impact-a-collaborative-journey-where-a-model-for-research-software-impact-was-at-the-center-of-the-discussion&quot;&gt;On 23 April 2024, the first ‘&lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day&lt;/a&gt;’ took place in Hilversum, the Netherlands. During the unconference part of the program, &lt;a href=&quot;https://www.linkedin.com/in/deekshitha-m/&quot;&gt;Deekshitha&lt;/a&gt; ran the session titled, ‘Decoding Research Software Impact: A Collaborative Journey’, where a model for research software impact was at the center of the discussion.&lt;/h2&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Authors: Deekshitha¹, Carlos Martinez Ortiz¹, Rena Bakhshi¹, Jason Maassen¹, Rob van Nieuwpoort², Slinger Jansen³, Ton Smeele³, Andrew Treloar⁴, Louise Bezuidenhout², Maarten Schermer³, Laurents Sesink⁵, Pui-Kei Fung³, and Colette Bos¹&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-f6a11552.CWh0HtBC_Z2aDNE7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@aleexcif?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Soliman Cifuentes&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this session, participants collaborated on the topic of research software impact. Participants took the perspective of policymakers, funders, researchers and Research Software Engineers (RSEs) to explore perspectives of research software impact in four 15-minute rounds, in which participants attempted to answer a set of questions from the perspective they were exploring. After each round, the participants changed groups to cover a different perspective. This workshop aimed to define the impact of research software from the perspectives of these 4 stakeholders. Here the term impact refers to the difference the research software makes to the research process or community.&lt;/p&gt;
&lt;p&gt;Measuring the impact of research software is the main focus of Deekshitha’s PhD study. Currently, there is a lack of sufficient methods to accurately measure research software impact. Her study seeks to develop an impact model that will enable all stakeholders of research software to measure its impact effectively and ensure recognition for the individuals behind its development. During the sessions, four questions were discussed (from different perspectives):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the goals of measuring research software impact?&lt;/li&gt;
&lt;li&gt;How can research software impact be measured?&lt;/li&gt;
&lt;li&gt;Which measures correspond to which goal?&lt;/li&gt;
&lt;li&gt;How should these goals be prioritized?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;researchers-and-research-software-engineers-perspective&quot;&gt;Researchers and Research Software Engineers’ perspective&lt;/h2&gt;
&lt;p&gt;From the researcher’s and RSEs perspective, we have identified six goals, as shown in the Figure 1. Among these, recognition and a track record for funding are essential goals for this group. Despite differing priorities, researchers and RSEs share similar perspectives. Therefore, they are represented together in a single diagram illustrating both viewpoints.&lt;/p&gt;
&lt;p&gt;The figure below illustrates the goals and the factors that help measure their impact and interdependencies. The first branch represents the goals (Answer to question 1), the second connection illustrates how to measure those goals (impact factors and their connection with goals- Answer to questions 2 and 3), and the third branch shows their prioritization value (Answer to question 4) along with the corresponding group (Researchers and RSEs; National and Institutional; no other group identified for Funders). This prioritization resulted from discussions with the workshop participants and the value starts from one. For example, in Figure 1, there are three impact factors grouped under Researchers. Based on the discussion, we found that the impact factor ‘citations’ has higher priority compared to other factors, so it is ranked 1 in the category for Researchers. Grey-colored boxes in front of the impact factors indicate the groups they belong to (eg: Researchers and RSEs). Additionally, impact factors unrelated to the goals (or we couldn’t find a relation with identified goals) are presented in separate black-colored boxes (see Figure 2 and Figure 3).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;349&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-a82b0191.Bq8WrD-D_1ge0nk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Researchers/RSEs perspective&lt;/p&gt;
&lt;h2 id=&quot;funders-perspective&quot;&gt;Funders perspective&lt;/h2&gt;
&lt;p&gt;Funders like NWO, SURF, and eScience Center who support research software projects, prioritize demonstrating value for money and aligning with international strategic goals like Open Science. By emphasizing research software impact, funders can act as change agents, influencing research and ensuring it aligns with broader institutional objectives. Selecting projects with significant impact enhances the funders’ image and showcases their commitment to supporting valuable and innovative research. Furthermore, funders contribute to research and educational institutions by funding unique and impactful software, thus enhancing their overall value.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;361&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-d9d7efe8.COVBJfrs_NFPpS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Funders perspective&lt;/p&gt;
&lt;h2 id=&quot;policy-makers-perspective&quot;&gt;Policy makers perspective&lt;/h2&gt;
&lt;p&gt;Policy makers and funders play distinct yet interconnected roles within governance and funding, particularly in research, education, and public policy sectors. Funders focus primarily on providing financial support and resources to achieve specific objectives and outcomes. On the other hand, policy makers are responsible for formulating and implementing regulations, guidelines, and directives that shape the strategic direction and operational frameworks of institutions and organizations.&lt;/p&gt;
&lt;p&gt;In terms of policy making, we realized there should be a distinction between national and international policies to ensure alignment with the institutional mission and purpose, maintain the independence and sovereignty of research institutes, and adequately consider risk assessment, marketability, and valorization. Figure 3 shows goals, impact factors, and their groups with priority values from the policymakers’ perspective.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Decoding Research Software Impact: A Collaborative Journey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;312&quot; src=&quot;https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-a6d8bab9.FE1foMTn_2kmlyN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Policy makers perspective&lt;/p&gt;
&lt;h2 id=&quot;take-home-message&quot;&gt;Take home message&lt;/h2&gt;
&lt;p&gt;The collaborative and dynamic nature of the session made it a memorable experience, combining serious discussion with a touch of fun. This approach not only sparked insightful conversations but also strengthened the community’s commitment to advancing the understanding and measurement of research software impact. Additionally, everyone agrees that RSEs are not appropriately recognized for their work, and recognition is one of the main goals for measuring impact. Funders have open science goals to achieve and policymakers want to ensure value for money.&lt;/p&gt;
&lt;p&gt;We look forward to continuing this journey and invite all who are passionate about the transformative power of research software to join us. Together, we can build a robust and internationally recognized model for assessing research software impact. If you’re eager to join this impactful journey, reach out and we can connect over a cup of coffee to further the discussion.&lt;/p&gt;
&lt;p&gt;Credit: We want to credit the tool we used, the free version of EdrawMind, in this blog post.&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.universiteitleiden.nl/en&quot;&gt;Leiden University&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.uu.nl/&quot;&gt;Utrecht University&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ardc.edu.au/&quot;&gt;Australian Research Data Commons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.surf.nl/&quot;&gt;SURF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/decoding-research-software-impact-a-coll-f6a11552.CWh0HtBC.jpg" medium="image"/><author>Deekshitha</author></item><item><title>What Research Software Engineers can learn from Taylor Swift</title><link>https://blog.esciencecenter.nl/posts/2024-07-18---what-research-software-engineers-can-learn-from-taylor-swift</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-07-18---what-research-software-engineers-can-learn-from-taylor-swift</guid><description>&lt;p&gt;14&lt;/p&gt;
&lt;p&gt;It’s Friday night, 5 July 2024. After some out-of-this-world pizza and a couple of drinks with colleagues, I’m on my way to catching a late train home. I get to the station just in time to park my bike. (I don’t know if it turns into a pumpkin, but the parking closes at midnight so if you’re late, it sleeps outside.)&lt;/p&gt;
&lt;p&gt;It’s crowded in the building. This is Amsterdam Central on a Friday night, so I wasn’t expecting deserted platforms, but tonight it’s packed and somewhat confusingly there are many people dressed in white, with glitters on their faces or even dressed in them completely.&lt;/p&gt;
&lt;p&gt;Then I remember the morning’s news. Taylor Swift concert. Incredibly popular pop singer, researchers studying why. Billionaire. First tour to gross a billion dollars. First concert in The Netherlands in seven years, and sold out way in advance. Fans called Swifties, waiting in line all day in the rain to get a good spot. I’ve never heard a Taylor Swift song.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;What Research Software Engineers can learn from Taylor Swift&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;460&quot; src=&quot;https://blog.esciencecenter.nl/_astro/what-research-software-engineers-can-lea-5255c30b.Bky7Uy2M_Z1ehXPO.webp&quot; srcset=&quot;&quot;&gt;
Oasis in Montreal, Canada, in 2002. The lyrics to their 1997 song *D’You Know What I Mean describe the singer visiting his childhood home and seeing the Bob Dylan album and a Beatles single that would inspire his music. &lt;em&gt;&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Oasis-band-concert-Montreal-Canada-Aug2002.jpg&quot;&gt;&lt;em&gt;Photo by Nesnad&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; on Wikimedia Commons. CC-BY-SA 4.0.*The next morning I decide that I should probably find out what all the fuss is about. You have to keep up with the times after all. I pull up YouTube and type “Taylor Swift”. A song called “&lt;a href=&quot;https://www.youtube.com/watch?v=q3zqJs7JUCQ&quot;&gt;Fortnight&lt;/a&gt;” comes up, apparently her latest single. Featuring someone called Post Malone, which raises the question of why Malone ended, and whether there was a Pre Malone before him, but I digress. I click the link.&lt;/p&gt;
&lt;p&gt;“&lt;a href=&quot;https://youtu.be/aB4OzAEgfD0?t=305&quot;&gt;Goldband!&lt;/a&gt;” my brain goes as the song starts playing. The very first sound is a 1980s-style synthesizer melody that immediately reminds me of this Dutch pop band. They had their Taylor Swift moment for me last year, as I similarly read about their popularity in the news and decided to investigate.&lt;/p&gt;
&lt;p&gt;One of the things I found then was an &lt;a href=&quot;https://www.annavastgoedencultuur.nl/nieuws-1/producerwiegerhoogendorp&quot;&gt;interview&lt;/a&gt; with Goldband’s producer Wieger Hoogendorp that I found very interesting. He explained that the 1980s sounds in their music make it popular because their audience has parents who were teenagers in the 1980s, and they played that stuff to their children. Similar music reminds the now-older kids of those good times, and so this is a recurring cycle in music. People like the familiar.&lt;/p&gt;
&lt;p&gt;I thought about this. As a teenager in the ‘90s, I’d listen to the sound of boy bands emanating from my sister’s room. I liked Father and Son, by Boyzone. It wasn’t until much later that I discovered that it was a cover, the original having been written by Cat Stevens 25 years earlier. My favorite band in the ’90s was Oasis, who was huge and took their inspiration from The Beatles, popular in the ’60s. Maybe there was something to this.&lt;/p&gt;
&lt;p&gt;In the Fortnight video meanwhile, Swift is singing the song while moving from a suspended bed frame to a library where she uses a typewriter. Somehow this feels familiar. She casts a glance at Malone, similarly equipped, and straightens out some papers. At the end of the song, the library scene returns, and all the papers catch fire, and it clicks. It’s another ’80s reference, this time to the clip for Toto’s Africa.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;What Research Software Engineers can learn from Taylor Swift&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/what-research-software-engineers-can-lea-01678a9a.C_wK8G7I_17E4mQ.webp&quot; srcset=&quot;&quot;&gt;
Stills from &lt;a href=&quot;https://www.youtube.com/watch?v=q3zqJs7JUCQ&quot;&gt;Fortnight by Taylor Swift&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=FTQbiNvZqaY&quot;&gt;Africa by Toto&lt;/a&gt;. Note the similarities, which make the clip for Fortnight feel familiar to the viewer, as they’ve likely seen the clip for Africa before. And then nostalgia does the rest. Copyright © 1982 and 2024 by the respective owners.&lt;/p&gt;
&lt;h2 id=&quot;about-that-software&quot;&gt;About that software&lt;/h2&gt;
&lt;p&gt;But Lourens, you may ask, that is all very interesting, but what does it have to do with Research Software Engineering?&lt;/p&gt;
&lt;p&gt;First, please don’t start programming in Fortran ’77 again because it was popular in the 80’s. We have better options now, like Julia or modern Fortran or, well, anything really. Ms. Swift didn’t hire Toto as her backing band either.&lt;/p&gt;
&lt;p&gt;Instead, there are a few aspects of what Taylor Swift does that we can learn from if we want to get more people to use our scientific software.&lt;/p&gt;
&lt;h3 id=&quot;what-users-want&quot;&gt;What users want&lt;/h3&gt;
&lt;p&gt;It may sound incredibly obvious, but we’ve seen above that one of the reasons Ms. Swift is so popular is that she gives people what they want. Note that that’s not the same as what they &lt;em&gt;say&lt;/em&gt; they want. I bet very few Swifties, if you asked them what they wanted to hear in the next song, would say “I’d like it to start with a 1980’s style synthesizer melody reminiscent of Goldband, and then I want her to start singing halfway through the first measure already (another recent innovation in pop music, it reduces the probability that people will skip to the next song right away), and then I want the music video to remind me of Toto’s ‘Africa’.” A much more likely answer would be “I’m so glad you’re here, do you know how I can get this glitter off my face?”&lt;/p&gt;
&lt;p&gt;But Swift and her team are professionals and they know what people actually want. They have all the know-how from decades of experience with pop music, and these days a ton of very detailed data too from streaming services on what people listen to and when and how.&lt;/p&gt;
&lt;h3 id=&quot;making-things-easy&quot;&gt;Making things easy&lt;/h3&gt;
&lt;p&gt;Another thing we can take inspiration from is the dress code. First, there’s apparently a dress code for Ms. Swift’s concerts (probably not a formal one, but enough to fill a train platform with similarly dressed people), which is nice because it means that you don’t have to feel insecure about what to wear to the concert. Nobody likes feeling insecure.&lt;/p&gt;
&lt;p&gt;Second, the dress code is white. Everyone has something white in their closet, so that’s easy. Glitter is easy to come by and cheap, and as an added bonus it reminds you of being a kid again. And then of course the concert is in a place that’s easy to reach for most people, and it ends on time so that you can still easily get home by public transport. In short, going to a Taylor Swift concert is easy! Anyone can do it and feel good doing it, and so more people do.&lt;/p&gt;
&lt;p&gt;The same principle applies to scientific software. Reduce the barrier to entry as much as you can. Make sure it installs (flawlessly!) in at most a single command (and that includes dependencies!). Put that command in the documentation so people can copy-paste and don’t have to type. Ensure there’s an easy-to-follow tutorial, and that it is written from the perspective of the users, which you figured out above. Add a ton of examples on how to do specific things that many people will want to do so that they can copy-paste without having to learn how to operate the software. And set up a chat channel so people can easily ask questions.&lt;/p&gt;
&lt;p&gt;The Toto reference gives us another hint: make your software familiar. Users are going to interact with it in a way that you design, and the more familiar that interaction feels to them, the more usable your software is. So look at other software that is similar, or that your users are likely to be using already, and try to design along similar lines. Clever tricks and highly artistic solutions may be fun to build, and they may make you feel very smart, but they don’t help the user.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short: Software exists to make people’s lives easier. Make sure yours does.&lt;/p&gt;
&lt;h3 id=&quot;community&quot;&gt;Community&lt;/h3&gt;
&lt;p&gt;There’s another thing that dress codes or uniforms (or &lt;a href=&quot;https://www.today.com/popculture/music/taylor-swift-eras-tour-friendship-bracelets-rcna99768&quot;&gt;friendship bracelets&lt;/a&gt;) do: they foster a sense of community. Humans are social animals, and we love being part of a group. That’s why we all dress in orange and go to a stadium to cheer on a group of people dressed in the same color, or grow our hair long and wear black and go to a metal concert, or put on suits and go to important meetings. All to be a part of something, to show that we’re part of the group.&lt;/p&gt;
&lt;p&gt;Software is more successful if it has a community around it because it helps people feel like they’re a part of something when they use it. Chat channels, mailing lists, meet-ups, workshops, all these things make it easier for people to start using software and to stay involved. I’ve worked with some software that’s really not very good technically but has an amazing community manager who keeps it alive, nonetheless. Whether that’s a good idea is questionable, but it shows that it works.&lt;/p&gt;
&lt;h3 id=&quot;advertising&quot;&gt;Advertising&lt;/h3&gt;
&lt;p&gt;Collaborations are quite popular in pop music these days. I don’t remember Madonna or Michael Jackson doing a lot of duets when I was a teenager, but it seems that these days every other single features someone or another. The reason of course is simple: it’s good advertising.&lt;/p&gt;
&lt;p&gt;Taylor Swift had a concert, causing a lot of people to gather at a train station, as a result of which I listened to Fortnight, and now I am aware of the existence of Post Malone (and Malone, and Pre Malone, look at that, triple word value!). Moreover, the cloud’s algorithms are now more likely to keep serving me Malones as well, and there’s someone out there whose bottom line is served by that.&lt;/p&gt;
&lt;p&gt;Of course, trying to influence search results using a link farm would be evil, but registering your software in the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt; is good practice, as is archiving it on &lt;a href=&quot;https://zenodo.org/&quot;&gt;Zenodo&lt;/a&gt;, and it works almost as well. Make it easy to use together with related software, and advertise that in that other software’s community. Glue some glitter on your colleague’s faces and send them to the local train station. The point is, if no one knows about your software, no one will use it.&lt;/p&gt;
&lt;h2 id=&quot;impact-is-more-than-numbers&quot;&gt;Impact is more than numbers&lt;/h2&gt;
&lt;p&gt;There’s another reason Taylor Swift is popular, and that is that her music is firmly mainstream. It features recognizable sounds and rhythms, the lyrics are relatable, and so it works for many people. Compare that with my favourite pop artist, &lt;a href=&quot;https://www.youtube.com/watch?v=Tv9YoYCKNoE&quot;&gt;Grimes&lt;/a&gt;, who makes songs about things as nerdy as &lt;a href=&quot;https://www.youtube.com/watch?v=gYG_4vJ4qNA&quot;&gt;Roko’s Basilisk&lt;/a&gt;. As a result, Grimes is not a billionaire. (She used to date one, but that doesn’t count.)&lt;/p&gt;
&lt;p&gt;Research Software Engineers are unlikely to become billionaires either, and sometimes we end up working on specialist software that does something only very few researchers need. It’s hard to have a lot of users then, even though the software could still be very important. On the other hand, something as generic as NumPy has a huge number of users, but then again if NumPy were the only thing we had we’d still not get much science done. (Are NumPy users called NumPies? If not, why not? And how do they get the glitter off their faces after finishing their calculations?)&lt;/p&gt;
&lt;p&gt;So it’s probably a good idea to not give the number of users too much importance when we’re trying to gauge the impact of research software. Do good science with it, make sure that it works for the people doing that science (however many there are), and enjoy the critical acclaim from the users you’ve got and whose lives you made easier. In the end, that’s what it’s all about.&lt;/p&gt;</description><pubDate>Thu, 18 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;14&lt;/p&gt;
&lt;p&gt;It’s Friday night, 5 July 2024. After some out-of-this-world pizza and a couple of drinks with colleagues, I’m on my way to catching a late train home. I get to the station just in time to park my bike. (I don’t know if it turns into a pumpkin, but the parking closes at midnight so if you’re late, it sleeps outside.)&lt;/p&gt;
&lt;p&gt;It’s crowded in the building. This is Amsterdam Central on a Friday night, so I wasn’t expecting deserted platforms, but tonight it’s packed and somewhat confusingly there are many people dressed in white, with glitters on their faces or even dressed in them completely.&lt;/p&gt;
&lt;p&gt;Then I remember the morning’s news. Taylor Swift concert. Incredibly popular pop singer, researchers studying why. Billionaire. First tour to gross a billion dollars. First concert in The Netherlands in seven years, and sold out way in advance. Fans called Swifties, waiting in line all day in the rain to get a good spot. I’ve never heard a Taylor Swift song.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;What Research Software Engineers can learn from Taylor Swift&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;460&quot; src=&quot;https://blog.esciencecenter.nl/_astro/what-research-software-engineers-can-lea-5255c30b.Bky7Uy2M_Z1ehXPO.webp&quot; srcset=&quot;&quot;&gt;
Oasis in Montreal, Canada, in 2002. The lyrics to their 1997 song *D’You Know What I Mean describe the singer visiting his childhood home and seeing the Bob Dylan album and a Beatles single that would inspire his music. &lt;em&gt;&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Oasis-band-concert-Montreal-Canada-Aug2002.jpg&quot;&gt;&lt;em&gt;Photo by Nesnad&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; on Wikimedia Commons. CC-BY-SA 4.0.*The next morning I decide that I should probably find out what all the fuss is about. You have to keep up with the times after all. I pull up YouTube and type “Taylor Swift”. A song called “&lt;a href=&quot;https://www.youtube.com/watch?v=q3zqJs7JUCQ&quot;&gt;Fortnight&lt;/a&gt;” comes up, apparently her latest single. Featuring someone called Post Malone, which raises the question of why Malone ended, and whether there was a Pre Malone before him, but I digress. I click the link.&lt;/p&gt;
&lt;p&gt;“&lt;a href=&quot;https://youtu.be/aB4OzAEgfD0?t=305&quot;&gt;Goldband!&lt;/a&gt;” my brain goes as the song starts playing. The very first sound is a 1980s-style synthesizer melody that immediately reminds me of this Dutch pop band. They had their Taylor Swift moment for me last year, as I similarly read about their popularity in the news and decided to investigate.&lt;/p&gt;
&lt;p&gt;One of the things I found then was an &lt;a href=&quot;https://www.annavastgoedencultuur.nl/nieuws-1/producerwiegerhoogendorp&quot;&gt;interview&lt;/a&gt; with Goldband’s producer Wieger Hoogendorp that I found very interesting. He explained that the 1980s sounds in their music make it popular because their audience has parents who were teenagers in the 1980s, and they played that stuff to their children. Similar music reminds the now-older kids of those good times, and so this is a recurring cycle in music. People like the familiar.&lt;/p&gt;
&lt;p&gt;I thought about this. As a teenager in the ‘90s, I’d listen to the sound of boy bands emanating from my sister’s room. I liked Father and Son, by Boyzone. It wasn’t until much later that I discovered that it was a cover, the original having been written by Cat Stevens 25 years earlier. My favorite band in the ’90s was Oasis, who was huge and took their inspiration from The Beatles, popular in the ’60s. Maybe there was something to this.&lt;/p&gt;
&lt;p&gt;In the Fortnight video meanwhile, Swift is singing the song while moving from a suspended bed frame to a library where she uses a typewriter. Somehow this feels familiar. She casts a glance at Malone, similarly equipped, and straightens out some papers. At the end of the song, the library scene returns, and all the papers catch fire, and it clicks. It’s another ’80s reference, this time to the clip for Toto’s Africa.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;What Research Software Engineers can learn from Taylor Swift&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/what-research-software-engineers-can-lea-01678a9a.C_wK8G7I_17E4mQ.webp&quot; srcset=&quot;&quot;&gt;
Stills from &lt;a href=&quot;https://www.youtube.com/watch?v=q3zqJs7JUCQ&quot;&gt;Fortnight by Taylor Swift&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=FTQbiNvZqaY&quot;&gt;Africa by Toto&lt;/a&gt;. Note the similarities, which make the clip for Fortnight feel familiar to the viewer, as they’ve likely seen the clip for Africa before. And then nostalgia does the rest. Copyright © 1982 and 2024 by the respective owners.&lt;/p&gt;
&lt;h2 id=&quot;about-that-software&quot;&gt;About that software&lt;/h2&gt;
&lt;p&gt;But Lourens, you may ask, that is all very interesting, but what does it have to do with Research Software Engineering?&lt;/p&gt;
&lt;p&gt;First, please don’t start programming in Fortran ’77 again because it was popular in the 80’s. We have better options now, like Julia or modern Fortran or, well, anything really. Ms. Swift didn’t hire Toto as her backing band either.&lt;/p&gt;
&lt;p&gt;Instead, there are a few aspects of what Taylor Swift does that we can learn from if we want to get more people to use our scientific software.&lt;/p&gt;
&lt;h3 id=&quot;what-users-want&quot;&gt;What users want&lt;/h3&gt;
&lt;p&gt;It may sound incredibly obvious, but we’ve seen above that one of the reasons Ms. Swift is so popular is that she gives people what they want. Note that that’s not the same as what they &lt;em&gt;say&lt;/em&gt; they want. I bet very few Swifties, if you asked them what they wanted to hear in the next song, would say “I’d like it to start with a 1980’s style synthesizer melody reminiscent of Goldband, and then I want her to start singing halfway through the first measure already (another recent innovation in pop music, it reduces the probability that people will skip to the next song right away), and then I want the music video to remind me of Toto’s ‘Africa’.” A much more likely answer would be “I’m so glad you’re here, do you know how I can get this glitter off my face?”&lt;/p&gt;
&lt;p&gt;But Swift and her team are professionals and they know what people actually want. They have all the know-how from decades of experience with pop music, and these days a ton of very detailed data too from streaming services on what people listen to and when and how.&lt;/p&gt;
&lt;h3 id=&quot;making-things-easy&quot;&gt;Making things easy&lt;/h3&gt;
&lt;p&gt;Another thing we can take inspiration from is the dress code. First, there’s apparently a dress code for Ms. Swift’s concerts (probably not a formal one, but enough to fill a train platform with similarly dressed people), which is nice because it means that you don’t have to feel insecure about what to wear to the concert. Nobody likes feeling insecure.&lt;/p&gt;
&lt;p&gt;Second, the dress code is white. Everyone has something white in their closet, so that’s easy. Glitter is easy to come by and cheap, and as an added bonus it reminds you of being a kid again. And then of course the concert is in a place that’s easy to reach for most people, and it ends on time so that you can still easily get home by public transport. In short, going to a Taylor Swift concert is easy! Anyone can do it and feel good doing it, and so more people do.&lt;/p&gt;
&lt;p&gt;The same principle applies to scientific software. Reduce the barrier to entry as much as you can. Make sure it installs (flawlessly!) in at most a single command (and that includes dependencies!). Put that command in the documentation so people can copy-paste and don’t have to type. Ensure there’s an easy-to-follow tutorial, and that it is written from the perspective of the users, which you figured out above. Add a ton of examples on how to do specific things that many people will want to do so that they can copy-paste without having to learn how to operate the software. And set up a chat channel so people can easily ask questions.&lt;/p&gt;
&lt;p&gt;The Toto reference gives us another hint: make your software familiar. Users are going to interact with it in a way that you design, and the more familiar that interaction feels to them, the more usable your software is. So look at other software that is similar, or that your users are likely to be using already, and try to design along similar lines. Clever tricks and highly artistic solutions may be fun to build, and they may make you feel very smart, but they don’t help the user.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short: Software exists to make people’s lives easier. Make sure yours does.&lt;/p&gt;
&lt;h3 id=&quot;community&quot;&gt;Community&lt;/h3&gt;
&lt;p&gt;There’s another thing that dress codes or uniforms (or &lt;a href=&quot;https://www.today.com/popculture/music/taylor-swift-eras-tour-friendship-bracelets-rcna99768&quot;&gt;friendship bracelets&lt;/a&gt;) do: they foster a sense of community. Humans are social animals, and we love being part of a group. That’s why we all dress in orange and go to a stadium to cheer on a group of people dressed in the same color, or grow our hair long and wear black and go to a metal concert, or put on suits and go to important meetings. All to be a part of something, to show that we’re part of the group.&lt;/p&gt;
&lt;p&gt;Software is more successful if it has a community around it because it helps people feel like they’re a part of something when they use it. Chat channels, mailing lists, meet-ups, workshops, all these things make it easier for people to start using software and to stay involved. I’ve worked with some software that’s really not very good technically but has an amazing community manager who keeps it alive, nonetheless. Whether that’s a good idea is questionable, but it shows that it works.&lt;/p&gt;
&lt;h3 id=&quot;advertising&quot;&gt;Advertising&lt;/h3&gt;
&lt;p&gt;Collaborations are quite popular in pop music these days. I don’t remember Madonna or Michael Jackson doing a lot of duets when I was a teenager, but it seems that these days every other single features someone or another. The reason of course is simple: it’s good advertising.&lt;/p&gt;
&lt;p&gt;Taylor Swift had a concert, causing a lot of people to gather at a train station, as a result of which I listened to Fortnight, and now I am aware of the existence of Post Malone (and Malone, and Pre Malone, look at that, triple word value!). Moreover, the cloud’s algorithms are now more likely to keep serving me Malones as well, and there’s someone out there whose bottom line is served by that.&lt;/p&gt;
&lt;p&gt;Of course, trying to influence search results using a link farm would be evil, but registering your software in the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt; is good practice, as is archiving it on &lt;a href=&quot;https://zenodo.org/&quot;&gt;Zenodo&lt;/a&gt;, and it works almost as well. Make it easy to use together with related software, and advertise that in that other software’s community. Glue some glitter on your colleague’s faces and send them to the local train station. The point is, if no one knows about your software, no one will use it.&lt;/p&gt;
&lt;h2 id=&quot;impact-is-more-than-numbers&quot;&gt;Impact is more than numbers&lt;/h2&gt;
&lt;p&gt;There’s another reason Taylor Swift is popular, and that is that her music is firmly mainstream. It features recognizable sounds and rhythms, the lyrics are relatable, and so it works for many people. Compare that with my favourite pop artist, &lt;a href=&quot;https://www.youtube.com/watch?v=Tv9YoYCKNoE&quot;&gt;Grimes&lt;/a&gt;, who makes songs about things as nerdy as &lt;a href=&quot;https://www.youtube.com/watch?v=gYG_4vJ4qNA&quot;&gt;Roko’s Basilisk&lt;/a&gt;. As a result, Grimes is not a billionaire. (She used to date one, but that doesn’t count.)&lt;/p&gt;
&lt;p&gt;Research Software Engineers are unlikely to become billionaires either, and sometimes we end up working on specialist software that does something only very few researchers need. It’s hard to have a lot of users then, even though the software could still be very important. On the other hand, something as generic as NumPy has a huge number of users, but then again if NumPy were the only thing we had we’d still not get much science done. (Are NumPy users called NumPies? If not, why not? And how do they get the glitter off their faces after finishing their calculations?)&lt;/p&gt;
&lt;p&gt;So it’s probably a good idea to not give the number of users too much importance when we’re trying to gauge the impact of research software. Do good science with it, make sure that it works for the people doing that science (however many there are), and enjoy the critical acclaim from the users you’ve got and whose lives you made easier. In the end, that’s what it’s all about.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/what-research-software-engineers-can-lea-5255c30b.Bky7Uy2M.jpg" medium="image"/><author>Lourens Veen</author></item><item><title>Better scripts with typing</title><link>https://blog.esciencecenter.nl/posts/2024-07-05---better-scripts-with-typing</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-07-05---better-scripts-with-typing</guid><description>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;-1-better-scripts-with-typing&quot;&gt;№ 1: Better scripts with typing&lt;/h3&gt;
&lt;p&gt;Imagine that one day you are in the office, and a colleague comes by explaining that their Python script isn’t doing what it’s supposed to. They ask you to help solve the problem. You happily agree. You see they’ve written a function:&lt;/p&gt;
&lt;p&gt;def foo(a, b):
return a + bIs this code correct, or will it give an error if you run it? (&lt;code&gt;foo&lt;/code&gt; is a traditional name for example functions, it doesn’t mean anything.)&lt;/p&gt;
&lt;p&gt;The answer, as often in engineering, is, “It depends”. It depends, in this case, on how the function is called. Something like this will work:&lt;/p&gt;
&lt;p&gt;print(foo(1, 1))On the other hand, this won’t work:&lt;/p&gt;
&lt;p&gt;print(foo([1], 1))So, whether this function is correct or not depends on what you pass into it. It works for two &lt;code&gt;int&lt;/code&gt;s (and for two strings too), but not for a &lt;code&gt;list&lt;/code&gt; and an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So how do you tell whether the problem is in this function? Well, you can simply check the rest of the script, find where the function is called, see what goes into it, and if &lt;code&gt;a+b&lt;/code&gt; works for whatever &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are put in, then the code is correct and the mistake must be somewhere else.&lt;/p&gt;
&lt;p&gt;So far, so good. But what if this is more than just a script? If you have functions calling functions, and functions being called from different places, then figuring out all the different things that can go into the function is going to be quite a bit of detective work. Pretty soon, it’s going to be quite difficult to know whether a function will work or crash. It can even be impossible:&lt;/p&gt;
&lt;p&gt;import json&lt;/p&gt;
&lt;p&gt;with open(‘input.json’) as f:
a = json.load(f)
print(foo(a, 1))Now whether the program works or crashes depends on what’s in some file on the user’s computer! So maybe the script is correct after all, and the problem is elsewhere? This doesn’t make for reliable scripts, or even reproducible science, for that matter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Better scripts with typing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/better-scripts-with-typing-f3cdba31._GLiRtde_ZNYdGP.webp&quot; srcset=&quot;&quot;&gt;
The Philippeion of Olympia (Mark Cartwright — &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot;&gt;CC BY-NC-SA&lt;/a&gt;)&lt;/p&gt;
&lt;h3 id=&quot;modularity-and-types&quot;&gt;Modularity and types&lt;/h3&gt;
&lt;p&gt;Clearly, we get all kinds of problems when we try to make software that will reliably get the user what they want, especially if the software is large and complex. Fortunately, there’s a good way of dealing with complexity. Invented by legendary RSE &lt;a href=&quot;https://www.worldhistory.org/Philip_II_of_Macedon/&quot;&gt;Philip II of Macedon&lt;/a&gt; some 2300 years ago: Divide et Impera (Divide and Rule). You split up your program into components (functions, procedures, classes, packages, etc.) that you can deal with one by one, then assemble them into a reliably operating empire, I mean program. Let’s look again at that function:&lt;/p&gt;
&lt;p&gt;def foo(a, b):
return a + bIt receives two arguments, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, from the caller, and returns some value that is the result of the operation &lt;code&gt;a + b&lt;/code&gt;. Receiving arguments and returning a value are the only connections it has to the outside world (such a function is called &lt;em&gt;pure&lt;/em&gt;). But whether the function works correctly depends on the values of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, and therefore on the outside world. That means it’s not a very reliable building block. Philip would be disappointed.&lt;/p&gt;
&lt;p&gt;What if we chose a set of acceptable values for both &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;? Then we could at least reason that if the function does not crash when an acceptable value is passed for both arguments, then the function works correctly. For example, we could specify that &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; both need to be in the set of all integer numbers. Such a collection of possible values is called a type*. Let’s annotate our function with the types we want to receive:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int):
return a + bWill this function work correctly? Yes! If you pass it two &lt;code&gt;int&lt;/code&gt; s, it will return their sum and not crash. The above is actually valid Python (the &lt;code&gt;:int&lt;/code&gt; bits are called &lt;em&gt;type annotations&lt;/em&gt;) and it will run just the same as the previous example:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int):
return a + b&lt;/p&gt;
&lt;p&gt;def bar():
print(foo(1, 1))&lt;/p&gt;
&lt;p&gt;def baz():
print(foo([1], 1))&lt;/p&gt;
&lt;p&gt;bar()
baz()As you can see, if you run this, the code does exactly the same. There is something funny though. In principle, Python could see when it reads the part &lt;code&gt;foo([1], 1)&lt;/code&gt; that it is not correct. &lt;code&gt;[1]&lt;/code&gt; is a list, and the function &lt;code&gt;foo &lt;/code&gt;needs an int. Nevertheless, Python will happily accept the definition of &lt;code&gt;baz&lt;/code&gt;, and it won’t crash until you actually *run *&lt;code&gt;baz&lt;/code&gt;, in turn calling &lt;code&gt;foo&lt;/code&gt;and trying to add a list and an &lt;code&gt;int&lt;/code&gt;. It’s only then that Python realizes that the values are the wrong type and can no longer add them, so it dutifully generates a &lt;code&gt;TypeError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Better scripts with typing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/better-scripts-with-typing-df0ab36b.CrcPwBMQ_Z2shf4d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markkoenig?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mark König&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;static-vs-dynamic-typing&quot;&gt;Static vs. Dynamic typing&lt;/h3&gt;
&lt;p&gt;Not all programming languages are like this. The Python language is a so-called &lt;em&gt;dynamically typed&lt;/em&gt; language, which means it won’t check whether things are the right type until it’s running the code and trying to do something with that value. Furthermore, Python completely ignores those type annotations, which explains why it crashes only when it tries to execute &lt;code&gt;a + b&lt;/code&gt; rather than already when executing &lt;code&gt;foo([1], 1)&lt;/code&gt;. Nevertheless, it &lt;em&gt;will&lt;/em&gt; eventually realize that something is wrong at that point and give an error (or it would be an &lt;em&gt;untyped&lt;/em&gt; language, now mercifully extinct), so that we have a chance to find the problem.&lt;/p&gt;
&lt;p&gt;In contrast, languages like C++, Java and Rust are &lt;em&gt;statically typed&lt;/em&gt;, which means that they do the type checking immediately when the code is read before it’s ever started. It’s impossible to create an executable&lt;a href=&quot;#d5ef&quot;&gt;⁰&lt;/a&gt; from this C++ code:&lt;/p&gt;
&lt;p&gt;auto foo(int a, int b) -&gt; int {
return a + b;
}&lt;/p&gt;
&lt;p&gt;auto baz() -&gt; list&amp;#x3C;int&gt; {
return foo(list&amp;#x3C;int&gt;{1}, 1);
}If I try anyway, GCC tells me: &lt;code&gt;error: cannot convert &apos;std::__cxx11::list&amp;#x26;lt;int&amp;#x26;gt;&apos; to &apos;int&apos; for argument &apos;1&apos; to &apos;int foo(int, int)&apos;&lt;/code&gt;, correctly pointing out that &lt;code&gt;foo&lt;/code&gt; needs an int, where I’m trying to pass a list. Note that it’s doing this already at the call, not inside &lt;code&gt;foo&lt;/code&gt;, and since no executable is created, I can’t run the code either.&lt;/p&gt;
&lt;p&gt;Now if we review this code, we can see that the compiler is in fact right. Function &lt;code&gt;foo&lt;/code&gt; is fine, but &lt;code&gt;baz&lt;/code&gt; tries to pass a list as the first argument, and from the definition of &lt;code&gt;foo&lt;/code&gt; we can see that it takes an int, so that’s wrong. In fact, because the return types are also declared, we can see that there is another problem in this version of &lt;code&gt;baz&lt;/code&gt;: &lt;code&gt;foo&lt;/code&gt; returns an int, which &lt;code&gt;baz&lt;/code&gt; then tries to return even though it should return a list. The C++ compiler will give an error for that as well when we fix the first one.&lt;/p&gt;
&lt;p&gt;We didn’t annotate the return type in the Python code before, but you can do that:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int) -&gt; int:
return a + b&lt;/p&gt;
&lt;p&gt;def baz() -&gt; None:
print([1], 1)Again, this is not checked by Python, so it will happily return something that doesn’t match the annotation if you tell it to.&lt;/p&gt;
&lt;h3 id=&quot;mypy&quot;&gt;mypy&lt;/h3&gt;
&lt;p&gt;So what good do those annotations do, if Python ignores them? First of all, type annotating your Python code forces you to think about what kinds of values your functions should accept, and then what to do with different kinds of inputs. That helps you write better code. Second, type annotations are really useful for people reading your code, like another developer, a code reviewer or someone using your package. They don’t need to wonder about what to pass to &lt;code&gt;foo&lt;/code&gt; anymore as it’s now obvious: integer numbers! And finally, there are tools that will check your type annotations even if Python doesn’t.&lt;/p&gt;
&lt;p&gt;The oldest and probably most commonly used one of these (and the one that I use) is called &lt;code&gt;mypy&lt;/code&gt;. You can pip-install it, and then call &lt;code&gt;mypy script.py&lt;/code&gt;to check your types, just like &lt;code&gt;flake8&lt;/code&gt; checks your syntax (your IDE may do this for you actually, look it up!). When I give the above to &lt;code&gt;mypy&lt;/code&gt;, it tells me &lt;code&gt;test.py:8 error: Argument to &quot;foo&quot; has incompatible type &quot;List[int]&quot;; expected &quot;int&quot;&lt;/code&gt; and that is exactly what is wrong with my code (and exactly what the C++ compiler said). It points out the right location too! That makes it really easy to fix your code.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Type annotations and mypy make your Python code more modular and make it easier to find mistakes, and that is particularly important when you start making larger programs that you share with others. Your code becomes more predictable and easier to understand when you use it, and that makes for a more reliably good experience for its users and developers. There are some downsides, mostly to do with mypy and type annotations still in development and being bolted on after the fact to a language that wasn’t conceived as a statically typed language from the start, but for scientific software, it works fine and is an excellent idea.&lt;/p&gt;
&lt;p&gt;To summarise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As all good Macedonians know, modularity is good!&lt;/li&gt;
&lt;li&gt;To make functions modular (analyzable in isolation), you need to specify input and output types.&lt;/li&gt;
&lt;li&gt;Strongly typed languages check types on reading the code, dynamically typed ones do it when running.&lt;/li&gt;
&lt;li&gt;With mypy, you can check types in Python too, and find a ton of bugs much quicker than without it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;← &lt;a href=&quot;https://blog.esciencecenter.nl/scripting-vs-programming-8d7d276f3ba3&quot;&gt;TEC 0: Scripting vs. Programming&lt;/a&gt; — &lt;a href=&quot;https://blog.esciencecenter.nl/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2: Procedural Programming&lt;/a&gt; →&lt;/p&gt;
&lt;p&gt;[0] C++ is a compiled language. That means that there are two steps to running a C++ program: 1) translating (or &lt;em&gt;compiling&lt;/em&gt;) it from C++ text to machine code for whichever kind of computer you want to run it on, and 2) running the resulting &lt;em&gt;executable&lt;/em&gt;. Type checking happens as part of the first step in C++, not the second.&lt;/p&gt;</description><pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;-1-better-scripts-with-typing&quot;&gt;№ 1: Better scripts with typing&lt;/h3&gt;
&lt;p&gt;Imagine that one day you are in the office, and a colleague comes by explaining that their Python script isn’t doing what it’s supposed to. They ask you to help solve the problem. You happily agree. You see they’ve written a function:&lt;/p&gt;
&lt;p&gt;def foo(a, b):
return a + bIs this code correct, or will it give an error if you run it? (&lt;code&gt;foo&lt;/code&gt; is a traditional name for example functions, it doesn’t mean anything.)&lt;/p&gt;
&lt;p&gt;The answer, as often in engineering, is, “It depends”. It depends, in this case, on how the function is called. Something like this will work:&lt;/p&gt;
&lt;p&gt;print(foo(1, 1))On the other hand, this won’t work:&lt;/p&gt;
&lt;p&gt;print(foo([1], 1))So, whether this function is correct or not depends on what you pass into it. It works for two &lt;code&gt;int&lt;/code&gt;s (and for two strings too), but not for a &lt;code&gt;list&lt;/code&gt; and an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So how do you tell whether the problem is in this function? Well, you can simply check the rest of the script, find where the function is called, see what goes into it, and if &lt;code&gt;a+b&lt;/code&gt; works for whatever &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are put in, then the code is correct and the mistake must be somewhere else.&lt;/p&gt;
&lt;p&gt;So far, so good. But what if this is more than just a script? If you have functions calling functions, and functions being called from different places, then figuring out all the different things that can go into the function is going to be quite a bit of detective work. Pretty soon, it’s going to be quite difficult to know whether a function will work or crash. It can even be impossible:&lt;/p&gt;
&lt;p&gt;import json&lt;/p&gt;
&lt;p&gt;with open(‘input.json’) as f:
a = json.load(f)
print(foo(a, 1))Now whether the program works or crashes depends on what’s in some file on the user’s computer! So maybe the script is correct after all, and the problem is elsewhere? This doesn’t make for reliable scripts, or even reproducible science, for that matter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Better scripts with typing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/better-scripts-with-typing-f3cdba31._GLiRtde_ZNYdGP.webp&quot; srcset=&quot;&quot;&gt;
The Philippeion of Olympia (Mark Cartwright — &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot;&gt;CC BY-NC-SA&lt;/a&gt;)&lt;/p&gt;
&lt;h3 id=&quot;modularity-and-types&quot;&gt;Modularity and types&lt;/h3&gt;
&lt;p&gt;Clearly, we get all kinds of problems when we try to make software that will reliably get the user what they want, especially if the software is large and complex. Fortunately, there’s a good way of dealing with complexity. Invented by legendary RSE &lt;a href=&quot;https://www.worldhistory.org/Philip_II_of_Macedon/&quot;&gt;Philip II of Macedon&lt;/a&gt; some 2300 years ago: Divide et Impera (Divide and Rule). You split up your program into components (functions, procedures, classes, packages, etc.) that you can deal with one by one, then assemble them into a reliably operating empire, I mean program. Let’s look again at that function:&lt;/p&gt;
&lt;p&gt;def foo(a, b):
return a + bIt receives two arguments, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, from the caller, and returns some value that is the result of the operation &lt;code&gt;a + b&lt;/code&gt;. Receiving arguments and returning a value are the only connections it has to the outside world (such a function is called &lt;em&gt;pure&lt;/em&gt;). But whether the function works correctly depends on the values of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, and therefore on the outside world. That means it’s not a very reliable building block. Philip would be disappointed.&lt;/p&gt;
&lt;p&gt;What if we chose a set of acceptable values for both &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;? Then we could at least reason that if the function does not crash when an acceptable value is passed for both arguments, then the function works correctly. For example, we could specify that &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; both need to be in the set of all integer numbers. Such a collection of possible values is called a type*. Let’s annotate our function with the types we want to receive:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int):
return a + bWill this function work correctly? Yes! If you pass it two &lt;code&gt;int&lt;/code&gt; s, it will return their sum and not crash. The above is actually valid Python (the &lt;code&gt;:int&lt;/code&gt; bits are called &lt;em&gt;type annotations&lt;/em&gt;) and it will run just the same as the previous example:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int):
return a + b&lt;/p&gt;
&lt;p&gt;def bar():
print(foo(1, 1))&lt;/p&gt;
&lt;p&gt;def baz():
print(foo([1], 1))&lt;/p&gt;
&lt;p&gt;bar()
baz()As you can see, if you run this, the code does exactly the same. There is something funny though. In principle, Python could see when it reads the part &lt;code&gt;foo([1], 1)&lt;/code&gt; that it is not correct. &lt;code&gt;[1]&lt;/code&gt; is a list, and the function &lt;code&gt;foo &lt;/code&gt;needs an int. Nevertheless, Python will happily accept the definition of &lt;code&gt;baz&lt;/code&gt;, and it won’t crash until you actually *run *&lt;code&gt;baz&lt;/code&gt;, in turn calling &lt;code&gt;foo&lt;/code&gt;and trying to add a list and an &lt;code&gt;int&lt;/code&gt;. It’s only then that Python realizes that the values are the wrong type and can no longer add them, so it dutifully generates a &lt;code&gt;TypeError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Better scripts with typing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/better-scripts-with-typing-df0ab36b.CrcPwBMQ_Z2shf4d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markkoenig?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mark König&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;static-vs-dynamic-typing&quot;&gt;Static vs. Dynamic typing&lt;/h3&gt;
&lt;p&gt;Not all programming languages are like this. The Python language is a so-called &lt;em&gt;dynamically typed&lt;/em&gt; language, which means it won’t check whether things are the right type until it’s running the code and trying to do something with that value. Furthermore, Python completely ignores those type annotations, which explains why it crashes only when it tries to execute &lt;code&gt;a + b&lt;/code&gt; rather than already when executing &lt;code&gt;foo([1], 1)&lt;/code&gt;. Nevertheless, it &lt;em&gt;will&lt;/em&gt; eventually realize that something is wrong at that point and give an error (or it would be an &lt;em&gt;untyped&lt;/em&gt; language, now mercifully extinct), so that we have a chance to find the problem.&lt;/p&gt;
&lt;p&gt;In contrast, languages like C++, Java and Rust are &lt;em&gt;statically typed&lt;/em&gt;, which means that they do the type checking immediately when the code is read before it’s ever started. It’s impossible to create an executable&lt;a href=&quot;#d5ef&quot;&gt;⁰&lt;/a&gt; from this C++ code:&lt;/p&gt;
&lt;p&gt;auto foo(int a, int b) -&gt; int {
return a + b;
}&lt;/p&gt;
&lt;p&gt;auto baz() -&gt; list&amp;#x3C;int&gt; {
return foo(list&amp;#x3C;int&gt;{1}, 1);
}If I try anyway, GCC tells me: &lt;code&gt;error: cannot convert &apos;std::__cxx11::list&amp;#x26;lt;int&amp;#x26;gt;&apos; to &apos;int&apos; for argument &apos;1&apos; to &apos;int foo(int, int)&apos;&lt;/code&gt;, correctly pointing out that &lt;code&gt;foo&lt;/code&gt; needs an int, where I’m trying to pass a list. Note that it’s doing this already at the call, not inside &lt;code&gt;foo&lt;/code&gt;, and since no executable is created, I can’t run the code either.&lt;/p&gt;
&lt;p&gt;Now if we review this code, we can see that the compiler is in fact right. Function &lt;code&gt;foo&lt;/code&gt; is fine, but &lt;code&gt;baz&lt;/code&gt; tries to pass a list as the first argument, and from the definition of &lt;code&gt;foo&lt;/code&gt; we can see that it takes an int, so that’s wrong. In fact, because the return types are also declared, we can see that there is another problem in this version of &lt;code&gt;baz&lt;/code&gt;: &lt;code&gt;foo&lt;/code&gt; returns an int, which &lt;code&gt;baz&lt;/code&gt; then tries to return even though it should return a list. The C++ compiler will give an error for that as well when we fix the first one.&lt;/p&gt;
&lt;p&gt;We didn’t annotate the return type in the Python code before, but you can do that:&lt;/p&gt;
&lt;p&gt;def foo(a: int, b: int) -&gt; int:
return a + b&lt;/p&gt;
&lt;p&gt;def baz() -&gt; None:
print([1], 1)Again, this is not checked by Python, so it will happily return something that doesn’t match the annotation if you tell it to.&lt;/p&gt;
&lt;h3 id=&quot;mypy&quot;&gt;mypy&lt;/h3&gt;
&lt;p&gt;So what good do those annotations do, if Python ignores them? First of all, type annotating your Python code forces you to think about what kinds of values your functions should accept, and then what to do with different kinds of inputs. That helps you write better code. Second, type annotations are really useful for people reading your code, like another developer, a code reviewer or someone using your package. They don’t need to wonder about what to pass to &lt;code&gt;foo&lt;/code&gt; anymore as it’s now obvious: integer numbers! And finally, there are tools that will check your type annotations even if Python doesn’t.&lt;/p&gt;
&lt;p&gt;The oldest and probably most commonly used one of these (and the one that I use) is called &lt;code&gt;mypy&lt;/code&gt;. You can pip-install it, and then call &lt;code&gt;mypy script.py&lt;/code&gt;to check your types, just like &lt;code&gt;flake8&lt;/code&gt; checks your syntax (your IDE may do this for you actually, look it up!). When I give the above to &lt;code&gt;mypy&lt;/code&gt;, it tells me &lt;code&gt;test.py:8 error: Argument to &quot;foo&quot; has incompatible type &quot;List[int]&quot;; expected &quot;int&quot;&lt;/code&gt; and that is exactly what is wrong with my code (and exactly what the C++ compiler said). It points out the right location too! That makes it really easy to fix your code.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Type annotations and mypy make your Python code more modular and make it easier to find mistakes, and that is particularly important when you start making larger programs that you share with others. Your code becomes more predictable and easier to understand when you use it, and that makes for a more reliably good experience for its users and developers. There are some downsides, mostly to do with mypy and type annotations still in development and being bolted on after the fact to a language that wasn’t conceived as a statically typed language from the start, but for scientific software, it works fine and is an excellent idea.&lt;/p&gt;
&lt;p&gt;To summarise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As all good Macedonians know, modularity is good!&lt;/li&gt;
&lt;li&gt;To make functions modular (analyzable in isolation), you need to specify input and output types.&lt;/li&gt;
&lt;li&gt;Strongly typed languages check types on reading the code, dynamically typed ones do it when running.&lt;/li&gt;
&lt;li&gt;With mypy, you can check types in Python too, and find a ton of bugs much quicker than without it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;← &lt;a href=&quot;https://blog.esciencecenter.nl/scripting-vs-programming-8d7d276f3ba3&quot;&gt;TEC 0: Scripting vs. Programming&lt;/a&gt; — &lt;a href=&quot;https://blog.esciencecenter.nl/procedural-programming-f1d8cdef7540&quot;&gt;TEC 2: Procedural Programming&lt;/a&gt; →&lt;/p&gt;
&lt;p&gt;[0] C++ is a compiled language. That means that there are two steps to running a C++ program: 1) translating (or &lt;em&gt;compiling&lt;/em&gt;) it from C++ text to machine code for whichever kind of computer you want to run it on, and 2) running the resulting &lt;em&gt;executable&lt;/em&gt;. Type checking happens as part of the first step in C++, not the second.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/better-scripts-with-typing-f3cdba31._GLiRtde.jpg" medium="image"/><author>Lourens Veen</author></item><item><title>Procedural Programming</title><link>https://blog.esciencecenter.nl/posts/2024-07-05---procedural-programming</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-07-05---procedural-programming</guid><description>&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;-2-procedural-programming&quot;&gt;№ 2: Procedural Programming**&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/escience-center/scripting-vs-programming-8d7d276f3ba3&quot;&gt;Previously&lt;/a&gt; we talked about scripting and programming. One difference I mentioned between scripts and programs is that scripts usually consist of a single source file with a straightforward list of instructions, while programs are larger and have a more complex structure. If your script is getting too big to easily read and understand, what are the things you can do?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Procedural Programming&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/procedural-programming-01699b68.DVkCQOGp_Z1ocMer.webp&quot; srcset=&quot;&quot;&gt;
My copy of Pascal User Manual and Report by Jensen &amp;#x26; Wirth (1975).Here’s an example of a Pascal program (a lesser known programming language developed in the 1970s - Ed.), in fact Program 0.1 from &lt;em&gt;Pascal User Manual and Report&lt;/em&gt; (1975) by Kathleen Jensen and &lt;a href=&quot;https://en.wikipedia.org/wiki/Niklaus_Wirth&quot;&gt;Niklaus Wirth&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;program inflation(output);&lt;/p&gt;
&lt;p&gt;const n = 10;
var i : integer; w1,w2,w3 : real;
begin
i := 0; w1 := 1.0; w2 := 1.0; w3 := 1.0
repeat
i := i+ 1;
w1 := w1 * 1.07;
w2 := w2 * 1.08;
w3 := w3 * 1.10;
writeln(i,w1,w2,w3)
until i==n
end.If you are a Python user, you can see this is not that different&lt;a href=&quot;https://medium.com/p/f1d8cdef7540#bf2b&quot;&gt;⁰&lt;/a&gt;. A Pascal program begins by listing all the constants and variables we are going to need, and their types. Then follows a list of statements, which in this case calculate and print a table of inflation-adjustment factors for ten years and three different inflation rates.&lt;/p&gt;
&lt;p&gt;I’ll leave a Python version as an exercise to the reader, but you can see that it will be quite similar (answer below&lt;a href=&quot;#2c46&quot;&gt;¹&lt;/a&gt;, if you want to check your work). In Python, variables are made automatically and don’t have to be declared in advance, but the style of programming is similar. It’s known as &lt;em&gt;imperative programming&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;As the Pascal User Manual points out, &lt;em&gt;“A (…) computer program consists of two essential parts, a description of &lt;em&gt;actions&lt;/em&gt; which are to be performed, and a description of the &lt;em&gt;data&lt;/em&gt;, which are manipulated by these actions.”&lt;/em&gt; As your script gets larger and more complicated it will process more data, and it will perform more actions, until it all becomes too much to easily understand. What to do?&lt;/p&gt;
&lt;p&gt;Let’s start with those actions, as that’s what most people like to focus on. In bigger scripts you often see a long list of instructions, and if it’s more than a screenful, that list may be split up into several blocks by comments. A load-data/process/save-data structure is common for example. What’s been done here is that the script has been split up, so that we can deal with it one section at a time (Philip II of Macedon would be proud, see &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Can we really deal with the sections independently though? Not entirely, as they still communicate with each other. Each section reads variables written by a previous section, and creates variables for other sections to use. So, if you want to make changes to one section, you still have to take into account the interactions with the others.&lt;/p&gt;
&lt;p&gt;Unless the sections do completely different, independent things, this is inevitable: they have to communicate somehow. It’s tricky though. If you change the name of a variable for example, then you have to search the entire script to see if it’s shared with another section, which you then have to modify accordingly. This could trigger changes somewhere else, and before you know it everything is broken.&lt;/p&gt;
&lt;p&gt;So, we could use a bit of help. In Pascal, this comes in the form of a &lt;em&gt;procedure&lt;/em&gt;. Here’s a slightly modified version of Program 11.3 from the same book as above:&lt;/p&gt;
&lt;p&gt;program parameters(output);&lt;/p&gt;
&lt;p&gt;var a, b, c: integer;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;procedure h(x: integer, var y: integer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var z: integer;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;begin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    x := x + 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    y := y + 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    z := x + y;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    writeln(z)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
h(a, b);
writeln(a, b)
end.What we have here is a program like before, but the work it does is now split up between the main program and a separate section, which is our procedure. It consists of two parts: a &lt;em&gt;declaration&lt;/em&gt; (the first line) and an &lt;em&gt;implementation&lt;/em&gt; (the rest of the block).&lt;/p&gt;
&lt;p&gt;A procedure is a kind of box around a block of code (a &lt;em&gt;scope&lt;/em&gt;). Variables can not pass through the walls of the box, unless we explicitly pass them through. In the declaration &lt;code&gt;procedure h(x: integer, var y: integer);&lt;/code&gt; we specify explicitly which variables can be passed into the box to communicate between the procedure and the rest of the program: &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; in this example. These are called the procedure’s &lt;em&gt;parameters&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;var&lt;/code&gt; keyword in front of &lt;code&gt;y&lt;/code&gt; says that &lt;code&gt;y&lt;/code&gt; is passed by reference, while the lack of one for &lt;code&gt;x&lt;/code&gt; means that &lt;code&gt;x&lt;/code&gt; is passed by value. What that means is that when we call the procedure with arguments &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, the first parameter &lt;code&gt;x&lt;/code&gt; becomes a &lt;em&gt;copy&lt;/em&gt; of the first argument &lt;code&gt;a&lt;/code&gt; (so that changing &lt;code&gt;x&lt;/code&gt; doesn’t affect &lt;code&gt;a&lt;/code&gt;), while the second parameter &lt;code&gt;y&lt;/code&gt; becomes &lt;em&gt;another name&lt;/em&gt; for the second argument &lt;code&gt;b&lt;/code&gt; (and so changing &lt;code&gt;y&lt;/code&gt; changes &lt;code&gt;b&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;No other variables can enter or exit the box. Variable &lt;code&gt;z&lt;/code&gt;is declared inside the procedure, and it is only visible within the procedure because we haven’t said otherwise.&lt;/p&gt;
&lt;p&gt;{ The main program again }&lt;/p&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
h(a, b);
writeln(a, b)
end.This program has some nice properties. When we call procedure &lt;code&gt;h&lt;/code&gt; in the main program, we can be sure that variable &lt;code&gt;c&lt;/code&gt; will not be changed, without even looking at &lt;code&gt;h&lt;/code&gt;! Then, taking the declaration (the first line with the parameters) of &lt;code&gt;h&lt;/code&gt; into account, we can also tell that &lt;code&gt;a&lt;/code&gt; will probably be read by &lt;code&gt;h&lt;/code&gt; , but won’t be changed, and that &lt;code&gt;b&lt;/code&gt; may end up having a different value after the call. Crucially, we can know all of this without ever reading &lt;code&gt;h&lt;/code&gt;’s implementation.&lt;/p&gt;
&lt;p&gt;{ Procedure h by itself }&lt;/p&gt;
&lt;p&gt;procedure h(x: integer, var y: integer);
var z: integer;
begin
x := x + 1;
y := y + 1;
z := x + y;
writeln(z)
end;Looking at procedure &lt;code&gt;h&lt;/code&gt;, we can tell by looking only at the procedure that any changes we make to it that do not affect what we do to &lt;code&gt;y&lt;/code&gt; will not affect how the rest of the program runs, again &lt;em&gt;without inspecting the rest of the program&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course, if we do make such a change, then we will still have to find all the places in which &lt;code&gt;h&lt;/code&gt; is called and possibly modify them. There is still a dependency! It’s just been made explicit. The same goes if we change the declaration, for example by changing &lt;code&gt;x&lt;/code&gt; to be a &lt;code&gt;real&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(To clear up the potentially confusing terminology: Pascal has both procedures and functions. Conceptually, a procedure is a list of actions that together enact a desired change (like directions for navigating to a destination), while a function is a list of instructions that produce a result (like how to calculate the length of the hypotenuse of a right triangle).&lt;/p&gt;
&lt;p&gt;Pascal has different language features for procedures and functions, as does Fortran, but more modern programming languages don’t bother with this and just allow you to make a function that returns &lt;code&gt;void&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;. So, practically speaking, a function in Pascal is the same as a function in Python, and a Pascal procedure is a Python function that doesn’t return a value.&lt;/p&gt;
&lt;p&gt;I’m going to continue to use the term procedure here, because we’re talking about procedural programming, and we can talk about functions later when we talk about functional programming, which is a different beast altogether.)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Procedural Programming&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/procedural-programming-9ac4b700.CbT7Cftq_Z1z8saP.webp&quot; srcset=&quot;&quot;&gt;
Procedures for making a tasty lunch. Photo by &lt;a href=&quot;https://unsplash.com/@socialcut?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;S O C I A L . C U T&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;making-a-good-procedure&quot;&gt;Making a good procedure&lt;/h3&gt;
&lt;p&gt;So, when should you make a procedure, and what does a good procedure look like? One good programming rule to live by is DRY: Don’t Repeat Yourself. So, if you find yourself copy-pasting some code, consider making a procedure instead, and calling it twice.&lt;/p&gt;
&lt;p&gt;Procedures are also fine if they’re only called once though. In the words of Jensen and Wirth: “One should not hesitate, however, from formulating an action as a procedure — even when called only once — if doing so enhances the readability. Defining development steps as procedures makes a more communicable and verifiable program.”* Hear hear!&lt;/p&gt;
&lt;p&gt;As we’ve seen above, the point of procedures is to split up your program into self-contained components, which can be modified independently. On the other hand, these components have to work together, for which they need to exchange information, and that introduces dependencies. There’s no perfect solution to this paradox, but it does lead to some good advice: fewer parameters is better, relative to the length of your procedure.&lt;/p&gt;
&lt;p&gt;If you’re a statistician or a graph theorist, consider a procedure to be a cluster: a good cluster has lots of stuff and connections inside it, but few connections to things outside it. Or if you’ve ever written a text: a procedure is like a paragraph, with some closely related sentences inside it, but connected to the rest of the text only by the things in its topic sentence.&lt;/p&gt;
&lt;p&gt;How about length? Some purveyors of questionable programming advice suggest hard length limits of sometimes as little as five lines per procedure&lt;a href=&quot;#f9c1&quot;&gt;²&lt;/a&gt;. I think the idea behind that is that humans can keep track of five to seven objects (chunks) at a time in short-term memory, so that this allows the reader to keep the whole procedure actively available.&lt;/p&gt;
&lt;p&gt;I don’t think it really works this way though. Blog posts tend to have really short paragraphs for easier reading on screen, but novels don’t and they are still perfectly readable. Grabbing a random one off my bookshelf I count 8 sentences and 163 words in a paragraph, which is three to four times the previous paragraph in this blog and it still reads just fine. So I think that longer procedures are okay, as long as they don’t get so long that you find yourself searching back and forth for something while reading them, or you (or rather someone else who isn’t all that familiar with the code!) have trouble keeping track of what’s going on.&lt;/p&gt;
&lt;p&gt;I also think that short procedures should be avoided. Here’s the above example without procedure &lt;code&gt;h&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;program parameters(output);&lt;/p&gt;
&lt;p&gt;var a, b, c, z: integer;&lt;/p&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
y := y + 1
z := x + 1 + y;
writeln(z);
writeln(x, y);
end.9 lines of code, versus 15 before. And it looks simpler too, doesn’t it? No need to look at the parameter declaration, or to consider which variable belongs where. So maybe procedures aren’t all they’re made out to be?&lt;/p&gt;
&lt;h3 id=&quot;costs-and-benefits&quot;&gt;Costs and benefits&lt;/h3&gt;
&lt;p&gt;Well, no, it’s not that simple. Procedures are an abstraction. Abstractions make it possible to write larger programs with a finite human brain, but they come at a cost of extra overhead. The shorter your procedures, the more of them you’ll need, and the more &lt;em&gt;abstraction overhead&lt;/em&gt; (procedure declarations and calls) you’ll introduce. At some point, that’s actually going to make the code more difficult to read, and it’s up to you, the programmer, to find a happy medium that allows others to easily understand your code.&lt;/p&gt;
&lt;p&gt;I do often find myself writing one-line or few-line procedures, but they’re usually actually abstraction overhead introduced by larger-scale abstractions like classes and modules. Not counting those, my normal range seems to be something like 5 to 20 lines, with an occasional stretch into the thirties or more.&lt;/p&gt;
&lt;p&gt;What matters is not so much the number of lines, but whether everything within the procedure belongs together, and whether the whole thing is still comprehensible. Sometimes splitting up a longer list of instructions that fundamentally belong together will actually make the code harder to read.&lt;/p&gt;
&lt;p&gt;This brings me back to what I said above about the number of parameters relative to the length of the procedure. A good procedure does something that can be described in a few words, all of which are in its name. If you need many words to say &lt;em&gt;what&lt;/em&gt; it does, then you’re trying to cram too much in, and should split it up. If you need many words to say &lt;em&gt;how&lt;/em&gt; it does it, and you find that that recipe naturally breaks up into several blocks, then make separate procedures for each block. If &lt;em&gt;what&lt;/em&gt; it does can be expressed simply, and &lt;em&gt;how&lt;/em&gt; it does it doesn’t split easily, then you have a nice procedure.&lt;/p&gt;
&lt;h3 id=&quot;final-words&quot;&gt;Final words&lt;/h3&gt;
&lt;p&gt;Procedures are a useful way of breaking up all the things your program does into manageable chunks. They impose a hierarchical organisation on the functionality of your program, and hierarchies are powerful means of simplification. (Niklaus Wirth wrote a &lt;a href=&quot;https://dl.acm.org/doi/pdf/10.1145/362575.362577&quot;&gt;famous paper about it&lt;/a&gt;, actually, which is why he and Pascal made an appearance here.) As pointed out by Jensen and Wirth however, there’s another essential part of any computer program: data. We’ll talk more about variables and records, values and objects in future posts.&lt;/p&gt;
&lt;p&gt;← &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1: Better scripts with typing&lt;/a&gt; — TEC 3: &amp;#x3C;Stay tuned!&gt; →&lt;/p&gt;
&lt;p&gt;[0] Modern languages don’t seem to have repeat..until loops anymore. I miss them sometimes.&lt;/p&gt;
&lt;p&gt;[1] Here’s a Python version. As you can see, Pascal and Python use different symbols for things, and I’ve used a for-loop because Python doesn’t have repeat..until, but it looks pretty similar.&lt;/p&gt;
&lt;h1 id=&quot;inflation&quot;&gt;inflation&lt;/h1&gt;
&lt;p&gt;N = 10
i = 0; w1 = 1.0; w2 = 1.0; w3 = 1.0
for i in range(1, N+1):
w1 = w1 * 1.07
w2 = w2 * 1.08
w3 = w3 * 1.10
print(i, w1, w2, w3)[2] I’m not naming names here…&lt;/p&gt;</description><pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The Engineering Corner&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A blog-within-a-blog on the transition from writing simple scripts for yourself to writing larger programs with and for others. TEC appears on an irregular schedule driven by workload and inspiration.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;-2-procedural-programming&quot;&gt;№ 2: Procedural Programming**&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/escience-center/scripting-vs-programming-8d7d276f3ba3&quot;&gt;Previously&lt;/a&gt; we talked about scripting and programming. One difference I mentioned between scripts and programs is that scripts usually consist of a single source file with a straightforward list of instructions, while programs are larger and have a more complex structure. If your script is getting too big to easily read and understand, what are the things you can do?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Procedural Programming&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/procedural-programming-01699b68.DVkCQOGp_Z1ocMer.webp&quot; srcset=&quot;&quot;&gt;
My copy of Pascal User Manual and Report by Jensen &amp;#x26; Wirth (1975).Here’s an example of a Pascal program (a lesser known programming language developed in the 1970s - Ed.), in fact Program 0.1 from &lt;em&gt;Pascal User Manual and Report&lt;/em&gt; (1975) by Kathleen Jensen and &lt;a href=&quot;https://en.wikipedia.org/wiki/Niklaus_Wirth&quot;&gt;Niklaus Wirth&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;program inflation(output);&lt;/p&gt;
&lt;p&gt;const n = 10;
var i : integer; w1,w2,w3 : real;
begin
i := 0; w1 := 1.0; w2 := 1.0; w3 := 1.0
repeat
i := i+ 1;
w1 := w1 * 1.07;
w2 := w2 * 1.08;
w3 := w3 * 1.10;
writeln(i,w1,w2,w3)
until i==n
end.If you are a Python user, you can see this is not that different&lt;a href=&quot;https://medium.com/p/f1d8cdef7540#bf2b&quot;&gt;⁰&lt;/a&gt;. A Pascal program begins by listing all the constants and variables we are going to need, and their types. Then follows a list of statements, which in this case calculate and print a table of inflation-adjustment factors for ten years and three different inflation rates.&lt;/p&gt;
&lt;p&gt;I’ll leave a Python version as an exercise to the reader, but you can see that it will be quite similar (answer below&lt;a href=&quot;#2c46&quot;&gt;¹&lt;/a&gt;, if you want to check your work). In Python, variables are made automatically and don’t have to be declared in advance, but the style of programming is similar. It’s known as &lt;em&gt;imperative programming&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;As the Pascal User Manual points out, &lt;em&gt;“A (…) computer program consists of two essential parts, a description of &lt;em&gt;actions&lt;/em&gt; which are to be performed, and a description of the &lt;em&gt;data&lt;/em&gt;, which are manipulated by these actions.”&lt;/em&gt; As your script gets larger and more complicated it will process more data, and it will perform more actions, until it all becomes too much to easily understand. What to do?&lt;/p&gt;
&lt;p&gt;Let’s start with those actions, as that’s what most people like to focus on. In bigger scripts you often see a long list of instructions, and if it’s more than a screenful, that list may be split up into several blocks by comments. A load-data/process/save-data structure is common for example. What’s been done here is that the script has been split up, so that we can deal with it one section at a time (Philip II of Macedon would be proud, see &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Can we really deal with the sections independently though? Not entirely, as they still communicate with each other. Each section reads variables written by a previous section, and creates variables for other sections to use. So, if you want to make changes to one section, you still have to take into account the interactions with the others.&lt;/p&gt;
&lt;p&gt;Unless the sections do completely different, independent things, this is inevitable: they have to communicate somehow. It’s tricky though. If you change the name of a variable for example, then you have to search the entire script to see if it’s shared with another section, which you then have to modify accordingly. This could trigger changes somewhere else, and before you know it everything is broken.&lt;/p&gt;
&lt;p&gt;So, we could use a bit of help. In Pascal, this comes in the form of a &lt;em&gt;procedure&lt;/em&gt;. Here’s a slightly modified version of Program 11.3 from the same book as above:&lt;/p&gt;
&lt;p&gt;program parameters(output);&lt;/p&gt;
&lt;p&gt;var a, b, c: integer;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;procedure h(x: integer, var y: integer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var z: integer;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;begin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    x := x + 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    y := y + 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    z := x + y;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    writeln(z)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
h(a, b);
writeln(a, b)
end.What we have here is a program like before, but the work it does is now split up between the main program and a separate section, which is our procedure. It consists of two parts: a &lt;em&gt;declaration&lt;/em&gt; (the first line) and an &lt;em&gt;implementation&lt;/em&gt; (the rest of the block).&lt;/p&gt;
&lt;p&gt;A procedure is a kind of box around a block of code (a &lt;em&gt;scope&lt;/em&gt;). Variables can not pass through the walls of the box, unless we explicitly pass them through. In the declaration &lt;code&gt;procedure h(x: integer, var y: integer);&lt;/code&gt; we specify explicitly which variables can be passed into the box to communicate between the procedure and the rest of the program: &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; in this example. These are called the procedure’s &lt;em&gt;parameters&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;var&lt;/code&gt; keyword in front of &lt;code&gt;y&lt;/code&gt; says that &lt;code&gt;y&lt;/code&gt; is passed by reference, while the lack of one for &lt;code&gt;x&lt;/code&gt; means that &lt;code&gt;x&lt;/code&gt; is passed by value. What that means is that when we call the procedure with arguments &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, the first parameter &lt;code&gt;x&lt;/code&gt; becomes a &lt;em&gt;copy&lt;/em&gt; of the first argument &lt;code&gt;a&lt;/code&gt; (so that changing &lt;code&gt;x&lt;/code&gt; doesn’t affect &lt;code&gt;a&lt;/code&gt;), while the second parameter &lt;code&gt;y&lt;/code&gt; becomes &lt;em&gt;another name&lt;/em&gt; for the second argument &lt;code&gt;b&lt;/code&gt; (and so changing &lt;code&gt;y&lt;/code&gt; changes &lt;code&gt;b&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;No other variables can enter or exit the box. Variable &lt;code&gt;z&lt;/code&gt;is declared inside the procedure, and it is only visible within the procedure because we haven’t said otherwise.&lt;/p&gt;
&lt;p&gt;{ The main program again }&lt;/p&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
h(a, b);
writeln(a, b)
end.This program has some nice properties. When we call procedure &lt;code&gt;h&lt;/code&gt; in the main program, we can be sure that variable &lt;code&gt;c&lt;/code&gt; will not be changed, without even looking at &lt;code&gt;h&lt;/code&gt;! Then, taking the declaration (the first line with the parameters) of &lt;code&gt;h&lt;/code&gt; into account, we can also tell that &lt;code&gt;a&lt;/code&gt; will probably be read by &lt;code&gt;h&lt;/code&gt; , but won’t be changed, and that &lt;code&gt;b&lt;/code&gt; may end up having a different value after the call. Crucially, we can know all of this without ever reading &lt;code&gt;h&lt;/code&gt;’s implementation.&lt;/p&gt;
&lt;p&gt;{ Procedure h by itself }&lt;/p&gt;
&lt;p&gt;procedure h(x: integer, var y: integer);
var z: integer;
begin
x := x + 1;
y := y + 1;
z := x + y;
writeln(z)
end;Looking at procedure &lt;code&gt;h&lt;/code&gt;, we can tell by looking only at the procedure that any changes we make to it that do not affect what we do to &lt;code&gt;y&lt;/code&gt; will not affect how the rest of the program runs, again &lt;em&gt;without inspecting the rest of the program&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course, if we do make such a change, then we will still have to find all the places in which &lt;code&gt;h&lt;/code&gt; is called and possibly modify them. There is still a dependency! It’s just been made explicit. The same goes if we change the declaration, for example by changing &lt;code&gt;x&lt;/code&gt; to be a &lt;code&gt;real&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(To clear up the potentially confusing terminology: Pascal has both procedures and functions. Conceptually, a procedure is a list of actions that together enact a desired change (like directions for navigating to a destination), while a function is a list of instructions that produce a result (like how to calculate the length of the hypotenuse of a right triangle).&lt;/p&gt;
&lt;p&gt;Pascal has different language features for procedures and functions, as does Fortran, but more modern programming languages don’t bother with this and just allow you to make a function that returns &lt;code&gt;void&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;. So, practically speaking, a function in Pascal is the same as a function in Python, and a Pascal procedure is a Python function that doesn’t return a value.&lt;/p&gt;
&lt;p&gt;I’m going to continue to use the term procedure here, because we’re talking about procedural programming, and we can talk about functions later when we talk about functional programming, which is a different beast altogether.)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Procedural Programming&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/procedural-programming-9ac4b700.CbT7Cftq_Z1z8saP.webp&quot; srcset=&quot;&quot;&gt;
Procedures for making a tasty lunch. Photo by &lt;a href=&quot;https://unsplash.com/@socialcut?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;S O C I A L . C U T&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;making-a-good-procedure&quot;&gt;Making a good procedure&lt;/h3&gt;
&lt;p&gt;So, when should you make a procedure, and what does a good procedure look like? One good programming rule to live by is DRY: Don’t Repeat Yourself. So, if you find yourself copy-pasting some code, consider making a procedure instead, and calling it twice.&lt;/p&gt;
&lt;p&gt;Procedures are also fine if they’re only called once though. In the words of Jensen and Wirth: “One should not hesitate, however, from formulating an action as a procedure — even when called only once — if doing so enhances the readability. Defining development steps as procedures makes a more communicable and verifiable program.”* Hear hear!&lt;/p&gt;
&lt;p&gt;As we’ve seen above, the point of procedures is to split up your program into self-contained components, which can be modified independently. On the other hand, these components have to work together, for which they need to exchange information, and that introduces dependencies. There’s no perfect solution to this paradox, but it does lead to some good advice: fewer parameters is better, relative to the length of your procedure.&lt;/p&gt;
&lt;p&gt;If you’re a statistician or a graph theorist, consider a procedure to be a cluster: a good cluster has lots of stuff and connections inside it, but few connections to things outside it. Or if you’ve ever written a text: a procedure is like a paragraph, with some closely related sentences inside it, but connected to the rest of the text only by the things in its topic sentence.&lt;/p&gt;
&lt;p&gt;How about length? Some purveyors of questionable programming advice suggest hard length limits of sometimes as little as five lines per procedure&lt;a href=&quot;#f9c1&quot;&gt;²&lt;/a&gt;. I think the idea behind that is that humans can keep track of five to seven objects (chunks) at a time in short-term memory, so that this allows the reader to keep the whole procedure actively available.&lt;/p&gt;
&lt;p&gt;I don’t think it really works this way though. Blog posts tend to have really short paragraphs for easier reading on screen, but novels don’t and they are still perfectly readable. Grabbing a random one off my bookshelf I count 8 sentences and 163 words in a paragraph, which is three to four times the previous paragraph in this blog and it still reads just fine. So I think that longer procedures are okay, as long as they don’t get so long that you find yourself searching back and forth for something while reading them, or you (or rather someone else who isn’t all that familiar with the code!) have trouble keeping track of what’s going on.&lt;/p&gt;
&lt;p&gt;I also think that short procedures should be avoided. Here’s the above example without procedure &lt;code&gt;h&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;program parameters(output);&lt;/p&gt;
&lt;p&gt;var a, b, c, z: integer;&lt;/p&gt;
&lt;p&gt;begin
a := 0; b := 0; c := 0;
y := y + 1
z := x + 1 + y;
writeln(z);
writeln(x, y);
end.9 lines of code, versus 15 before. And it looks simpler too, doesn’t it? No need to look at the parameter declaration, or to consider which variable belongs where. So maybe procedures aren’t all they’re made out to be?&lt;/p&gt;
&lt;h3 id=&quot;costs-and-benefits&quot;&gt;Costs and benefits&lt;/h3&gt;
&lt;p&gt;Well, no, it’s not that simple. Procedures are an abstraction. Abstractions make it possible to write larger programs with a finite human brain, but they come at a cost of extra overhead. The shorter your procedures, the more of them you’ll need, and the more &lt;em&gt;abstraction overhead&lt;/em&gt; (procedure declarations and calls) you’ll introduce. At some point, that’s actually going to make the code more difficult to read, and it’s up to you, the programmer, to find a happy medium that allows others to easily understand your code.&lt;/p&gt;
&lt;p&gt;I do often find myself writing one-line or few-line procedures, but they’re usually actually abstraction overhead introduced by larger-scale abstractions like classes and modules. Not counting those, my normal range seems to be something like 5 to 20 lines, with an occasional stretch into the thirties or more.&lt;/p&gt;
&lt;p&gt;What matters is not so much the number of lines, but whether everything within the procedure belongs together, and whether the whole thing is still comprehensible. Sometimes splitting up a longer list of instructions that fundamentally belong together will actually make the code harder to read.&lt;/p&gt;
&lt;p&gt;This brings me back to what I said above about the number of parameters relative to the length of the procedure. A good procedure does something that can be described in a few words, all of which are in its name. If you need many words to say &lt;em&gt;what&lt;/em&gt; it does, then you’re trying to cram too much in, and should split it up. If you need many words to say &lt;em&gt;how&lt;/em&gt; it does it, and you find that that recipe naturally breaks up into several blocks, then make separate procedures for each block. If &lt;em&gt;what&lt;/em&gt; it does can be expressed simply, and &lt;em&gt;how&lt;/em&gt; it does it doesn’t split easily, then you have a nice procedure.&lt;/p&gt;
&lt;h3 id=&quot;final-words&quot;&gt;Final words&lt;/h3&gt;
&lt;p&gt;Procedures are a useful way of breaking up all the things your program does into manageable chunks. They impose a hierarchical organisation on the functionality of your program, and hierarchies are powerful means of simplification. (Niklaus Wirth wrote a &lt;a href=&quot;https://dl.acm.org/doi/pdf/10.1145/362575.362577&quot;&gt;famous paper about it&lt;/a&gt;, actually, which is why he and Pascal made an appearance here.) As pointed out by Jensen and Wirth however, there’s another essential part of any computer program: data. We’ll talk more about variables and records, values and objects in future posts.&lt;/p&gt;
&lt;p&gt;← &lt;a href=&quot;https://medium.com/escience-center/dynamic-types-static-types-oh-my-py-25c9743b72c4&quot;&gt;TEC 1: Better scripts with typing&lt;/a&gt; — TEC 3: &amp;#x3C;Stay tuned!&gt; →&lt;/p&gt;
&lt;p&gt;[0] Modern languages don’t seem to have repeat..until loops anymore. I miss them sometimes.&lt;/p&gt;
&lt;p&gt;[1] Here’s a Python version. As you can see, Pascal and Python use different symbols for things, and I’ve used a for-loop because Python doesn’t have repeat..until, but it looks pretty similar.&lt;/p&gt;
&lt;h1 id=&quot;inflation&quot;&gt;inflation&lt;/h1&gt;
&lt;p&gt;N = 10
i = 0; w1 = 1.0; w2 = 1.0; w3 = 1.0
for i in range(1, N+1):
w1 = w1 * 1.07
w2 = w2 * 1.08
w3 = w3 * 1.10
print(i, w1, w2, w3)[2] I’m not naming names here…&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/procedural-programming-01699b68.DVkCQOGp.jpeg" medium="image"/><author>Lourens Veen</author></item><item><title>Quantum Computing for Quantum Chemistry with qc2</title><link>https://blog.esciencecenter.nl/posts/2024-06-27---quantum-computing-for-quantum-chemistry-with-qc2</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-06-27---quantum-computing-for-quantum-chemistry-with-qc2</guid><description>&lt;p&gt;Q&lt;em&gt;uantum Computing is a rapidly evolving field that has the potential to transform the way we approach complex computational problems. Quantum Chemistry stands out as a prime application area, with anticipated impacts ranging from the development of new materials to novel drugs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this blog, we introduce &lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt;, a user-friendly, modular software designed to seamlessly integrate traditional quantum chemistry codes with modern quantum computing Software Development Kits (SDKs).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;550&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--f78b0228.hCUsNgvR_28XFny.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lazycreekimages?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Michael Dziedzic&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;
&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;258&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--59e5e045.TUY_z8tQ_pj3CX.webp&quot; srcset=&quot;&quot;&gt;
However, despite recent advances in both hardware and software, the path to fully error-corrected, utility-scale quantum computations may still take a while. For the moment, as we navigate in the &lt;a href=&quot;https://arxiv.org/abs/1801.00862&quot;&gt;Noisy Intermediate-Scale Quantum (NISQ) era&lt;/a&gt; towards &lt;a href=&quot;https://www.ibm.com/quantum/blog/what-is-quantum-utlity&quot;&gt;Quantum Utility&lt;/a&gt;, we need to learn how to make the most out of the available algorithms that run on as-yet error-prone, imperfect hardware: the so-called &lt;a href=&quot;https://arxiv.org/abs/2101.08448&quot;&gt;NISQ algorithms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unavoidably, &lt;a href=&quot;https://www.ibm.com/topics/quantum-computing&quot;&gt;Quantum Computing&lt;/a&gt; and &lt;a href=&quot;https://onlinelibrary.wiley.com/doi/book/10.1002/9781119019572&quot;&gt;Quantum Chemistry&lt;/a&gt;, and particularly &lt;a href=&quot;https://doi.org/10.48550/arXiv.2001.03685&quot;&gt;their combination&lt;/a&gt;, demand a high level of technical knowledge. The available software packages are highly specialised, requiring users to have an excellent understanding of the fundamental concepts involved from the start. This might scare away both computational chemists and software engineers alike.&lt;/p&gt;
&lt;p&gt;This situation has been greatly alleviated by the increasing availability of excellent &lt;a href=&quot;https://learning.quantum.ibm.com/&quot;&gt;&lt;em&gt;educational resources&lt;/em&gt;**&lt;/a&gt; and &lt;a href=&quot;https://journals.plos.org/plosone/article?id=10.1371%2Fjournal.pone.0208561&quot;&gt;&lt;em&gt;&lt;strong&gt;good quality open-source software&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;, some even tailored specifically for the quantum chemistry community, &lt;em&gt;e.g.&lt;/em&gt;, &lt;a href=&quot;https://qiskit-community.github.io/qiskit-nature/&quot;&gt;Qiskit-Nature&lt;/a&gt;, &lt;a href=&quot;https://docs.pennylane.ai/en/stable/introduction/chemistry.html&quot;&gt;PennyLane.qchem&lt;/a&gt; and &lt;a href=&quot;https://github.com/goodchemistryco/Tangelo&quot;&gt;Tangelo&lt;/a&gt;. And we believe that this is the right way forward.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt;, a user-friendly, modular software designed to seamlessly integrate traditional quantum chemistry codes with modern quantum computing SDKs. Designed with &lt;em&gt;reusability&lt;/em&gt; and &lt;em&gt;interoperability&lt;/em&gt; in mind, qc2 leverages popular existing tools such as the &lt;a href=&quot;https://wiki.fysik.dtu.dk/ase/&quot;&gt;Atomic Simulation Environment (ASE)&lt;/a&gt; and &lt;a href=&quot;https://molssi.org/software/qcschema-2/&quot;&gt;Quantum Chemistry Schema (QCSchema)&lt;/a&gt;. It can also be easily customized to work with your preferred backends, requiring minimal implementation effort.&lt;/p&gt;
&lt;p&gt;Before we dive in, let’s quickly recap some useful concepts…&lt;/p&gt;
&lt;h3 id=&quot;quick-recap-quantum-chemistry-with-classical-computers&quot;&gt;Quick Recap: Quantum Chemistry with Classical Computers&lt;/h3&gt;
&lt;p&gt;The primary goal of quantum chemistry is to understand the structure and properties of matter at microscopic level. Atoms and molecules are intricate quantum entities and are characterized by discrete energy levels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;549&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--b0883893.BEPjHfk4_Z2cfK1D.webp&quot; srcset=&quot;&quot;&gt;
Schematic representation of the discrete electronic energy levels of the water molecule in its most stable configuration.Such a quantized energy spectrum naturally arises from solving the systems’ Schrödinger equation (SE):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;484&quot; height=&quot;88&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--eb730c90.BKSd8jb3_W4Jr4.webp&quot; srcset=&quot;&quot;&gt;
Time-independent Schrödinger equation. H is the Hamiltonian operator (^); |ψ⟩ and E represent the wave function and energy of a quantum state i.This equation represents a typical eigenvalue problem that can only be solved exactly for one-electron systems, &lt;em&gt;e.g.&lt;/em&gt;, the hydrogen atom. For all other systems, we must rely on mathematical and physical models that approximate the exact solutions to the SE. Examples of such models are the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hartree%E2%80%93Fock_method&quot;&gt;Hartree–Fock (HF) method&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Coupled_cluster&quot;&gt;Coupled cluster&lt;/a&gt; (CC) and &lt;a href=&quot;https://en.wikipedia.org/wiki/Full_configuration_interaction&quot;&gt;Full configuration interaction&lt;/a&gt; (FCI).&lt;/p&gt;
&lt;p&gt;In general, the strategy involves expanding the unknown wave function of your system as a linear combination of &lt;em&gt;n&lt;/em&gt; known wave functions:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;41&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--2c0ee02a.BzErDrw7_Z2kDPkl.webp&quot; srcset=&quot;&quot;&gt;
Ground-state molecular wave function as a linear combination of Slater determinants (|φ₁⟩, .., |φₙ⟩) formed from a reference HF wave function, |φ₀⟩. The coefficients α, β, γ, and δ minimize the expectation value of H.Now, the task of determining the coefficients α, β, γ, and δ, along with the associated ground and possibly excited-state energies, involves setting up and diagonalizing a large &lt;em&gt;n&lt;/em&gt; by &lt;em&gt;n&lt;/em&gt; matrix:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;118&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--4d04a3d7.Cd4nYLiW_Z1Ssp1e.webp&quot; srcset=&quot;&quot;&gt;
Diagonalization by a unitary similarity transformation. &lt;strong&gt;U&lt;/strong&gt; is a matrix whose columns are the eigenvectors of H containing α, β, γ, and δ coefficients.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This step is certainly the major computational bottleneck for classical computers and the one that quantum algorithms seek to bypass.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a general rule, the larger &lt;em&gt;n&lt;/em&gt; is, the closer the solution approaches the exact solution to the SE, but the more &lt;a href=&quot;https://arxiv.org/abs/1208.3334&quot;&gt;computationally expensive&lt;/a&gt; it becomes. Not surprisingly, typical “gold-standard” methods like CCSD(T) (let alone FCI) quickly become unaffordable for medium-to-large sized molecules.&lt;/p&gt;
&lt;h3 id=&quot;quantum-chemistry-with-quantum-computers-nisq-algorithms&quot;&gt;Quantum Chemistry with Quantum Computers: NISQ algorithms&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;343&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--29ba8ef0.BpjsK2Fi_Z1KnFUV.webp&quot; srcset=&quot;&quot;&gt;
*Schematic representation of a VQE workflow. &lt;strong&gt;&lt;strong&gt;𝜃&lt;/strong&gt;&lt;/strong&gt; represent circuit parameters that are variationally optimized by an external classical routine. Expectation values of the molecular Hamiltonian 𝐻 are evaluated at circuit level.*Let’s now examine the problem we just discussed from a different perspective: that of Quantum Computing.&lt;/p&gt;
&lt;p&gt;Within the NISQ era, the task of approaching the exact solution to the SE primarily relies on &lt;a href=&quot;https://arxiv.org/abs/2101.08448&quot;&gt;hybrid quantum-classical algorithms&lt;/a&gt;, and there are compelling reasons for this. These algorithms are designed to run on noisy quantum hardware; they utilize as few quantum gates as possible and can be optimized to operate within the limited coherence time of the devices’ qubits, the units of quantum computation. Among these, the &lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;Variational Quantum Eigensolver (VQE)&lt;/a&gt; is specially prominent when the goal is to calculate ground-state energies and properties of molecules.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Reference quantum circuit&lt;/em&gt;.** Similar to a typical quantum chemistry calculation, we begin by defining a reference wave function for the target molecule, *|*φ₀⟩. This is usually accomplished by using traditional quantum chemistry packages, &lt;em&gt;e.g.&lt;/em&gt;, by conducting a HF calculation with &lt;a href=&quot;https://pyscf.org/&quot;&gt;PySCF&lt;/a&gt;. From this, a reference quantum circuit can be created by directly mapping the &lt;em&gt;spin-orbitals’ occupation numbers&lt;/em&gt; into initial qubit states (&lt;em&gt;the calculated &lt;em&gt;&lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;&lt;em&gt;electron integrals&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; are also useful later for building the molecular Hamiltonian in step 3&lt;/em&gt;). As an example, consider a hydrogen molecule (H₂) with a minimal basis set, such as STO-3G. Here, the final HF wave function |1100⟩ is mapped into a four-qubit quantum circuit |1⟩ ⊗ |1⟩ ⊗ |0⟩ ⊗ |0⟩. For larger molecules or one-electron bases, it may be necessary to restrict the qubit space by creating a reference quantum circuit out of a preselected &lt;em&gt;active space&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Parametrized quantum circuit.&lt;/strong&gt;&lt;/em&gt; After setting the initial qubit states, the next step is to represent the wave function &lt;em&gt;|Ψ&lt;/em&gt;₀⟩ on the quantum device, &lt;em&gt;i.e.&lt;/em&gt;, to prepare a parametrized quantum state. This is achieved by applying a predefined set of quantum gates, which depend on certain parameters &lt;em&gt;&lt;strong&gt;θ&lt;/strong&gt;&lt;/em&gt;, to the initial qubit states. Similarly to &lt;em&gt;|Ψ&lt;/em&gt;₀⟩, the resulting parametrized quantum circuit &lt;em&gt;|Ψ(&lt;strong&gt;&lt;strong&gt;θ&lt;/strong&gt;&lt;/strong&gt;)&lt;/em&gt;⟩, often referred to as the &lt;em&gt;ansatz&lt;/em&gt;, seeks to approximate the true ground-state wave function of the target molecule. The set of variational (qubit rotation) parameters ***θ ***is, in some sense, analogous to the coefficients α, β, γ, and δ discussed earlier in the context of traditional quantum chemistry.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Energy Estimation.&lt;/strong&gt;&lt;/em&gt;* *With the parametrized quantum circuit at hand and a set of initial parameters &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ&lt;/strong&gt;, we estimate the expectation value of the molecular Hamiltonian. This process involves mapping the &lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;Hamiltonian in second quantization into a qubit representation&lt;/a&gt;, namely, as a sum of Pauli terms. The final energy, which is given as a sum the measured expectation values of each Pauli term, depends on &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ&lt;/strong&gt; and should be minimized accordingly.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Classical Feedback:&lt;/strong&gt;&lt;/em&gt;* &lt;em&gt;The minimization process is carried out using an external classical optimization routine,&lt;/em&gt; *which updates the circuit parameters &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steps 3 and 4&lt;/strong&gt; are repeated until convergence is achieved, resulting in the lowest possible expectation value. The final energy corresponds to the ground-state energy of the target molecule as predicted by VQE.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The quality of the VQE solutions depends on several factors, including the size of the active space (if any), type of ansatz, initial guesses for the circuit parameters, the classical optimizer used, and other potential sources of error if run on real quantum hardware.&lt;/p&gt;
&lt;p&gt;Another popular NISQ algorithm for finding the ground-state energy of molecules is the &lt;a href=&quot;https://arxiv.org/abs/2212.02482&quot;&gt;orbital-optimized VQE&lt;/a&gt; (oo-VQE), which extends the traditional VQE. In oo-VQE, not only are the circuit parameters optimized, but the original HF molecular orbitals are also allowed to relax during the classical optimization process. For this reason, ground-state variational energies obtained with oo-VQE are generally lower than those from traditional VQE runs, but they are also computationally more expensive. As will be shown later, VQE and oo-VQE could be seen as some sort of quantum analogues of the traditional &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASCI and CASSCF&lt;/a&gt; &lt;em&gt;ab initio&lt;/em&gt; methods.&lt;/p&gt;
&lt;h3 id=&quot;overview-of-qc2&quot;&gt;Overview of qc2&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;278&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--da9ac281.LN0EABsU_Z1DyBEo.webp&quot; srcset=&quot;&quot;&gt;
Schematic representation of qc2 design and workflow.&lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt; is an open-source python package specifically crafted for hybrid quantum-classical algorithms such as VQE and oo-VQE. It embraces several core &lt;em&gt;design principles&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Leveraging Existing Tools&lt;/strong&gt;: qc2 is interoperable with existing open-source quantum chemistry tools, like &lt;a href=&quot;https://wiki.fysik.dtu.dk/ase/&quot;&gt;ASE calculators&lt;/a&gt;, and adheres to standard data schemas, such as &lt;a href=&quot;https://molssi.org/software/qcschema-2/&quot;&gt;QCSchema&lt;/a&gt; or &lt;a href=&quot;https://doi.org/10.1016/0010-4655(89)90033-7&quot;&gt;FCIDump&lt;/a&gt;. This ensures efficient data exchange necessary for various quantum computing libraries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless Integration with Quantum Computing SDKs&lt;/strong&gt;: qc2 is designed to work effortlessly with &lt;a href=&quot;https://www.ibm.com/quantum/qiskit&quot;&gt;Qiskit&lt;/a&gt; and &lt;a href=&quot;https://pennylane.ai/&quot;&gt;PennyLane&lt;/a&gt;, ensuring a smooth user experience for developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: The package boasts high modularity, featuring a robust built-in algorithms package that simplifies extensions and enhancements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-Friendly Design&lt;/strong&gt;: qc2 is straightforward and has an intuitive interface, enabling users to focus on their research and applications with minimal technical details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the code block below, we present a minimal example using qc2 for a simple VQE run on the water molecule:&lt;/p&gt;
&lt;h1 id=&quot;import-ase-related-modules&quot;&gt;Import ASE-related modules&lt;/h1&gt;
&lt;p&gt;from ase.build import molecule&lt;/p&gt;
&lt;h1 id=&quot;import-qc2-modules&quot;&gt;Import qc2 modules&lt;/h1&gt;
&lt;p&gt;from qc2.data import qc2Data
from qc2.ase import PySCF
from qc2.algorithms.pennylane import VQE
from qc2.algorithms.utils import ActiveSpace&lt;/p&gt;
&lt;h1 id=&quot;instantiate-qc2data-class&quot;&gt;Instantiate qc2Data class&lt;/h1&gt;
&lt;p&gt;qc2data = qc2Data(
molecule=molecule(“H2O”),
filename=“h2o.hdf5”
)&lt;/p&gt;
&lt;h1 id=&quot;specify-and-run-the-quantum-chemistry-qc2-ase-calculator&quot;&gt;Specify and run the quantum chemistry qc2-ASE calculator&lt;/h1&gt;
&lt;p&gt;qc2data.molecule.calc = PySCF(
method=“scf.RHF”,
basis=“sto-3g”,
)
qc2data.run()&lt;/p&gt;
&lt;h1 id=&quot;instantiate-vqe-class&quot;&gt;Instantiate VQE class&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm = VQE(
active_space=ActiveSpace(
num_active_electrons=(2, 2),
num_active_spatial_orbitals=4
),
)&lt;/p&gt;
&lt;h1 id=&quot;run-vqe-algorithm&quot;&gt;Run VQE algorithm&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm.run()As noted, qc2 is designed around the &lt;em&gt;qc2Data&lt;/em&gt; class, which links traditional quantum chemistry codes with quantum computing backends through custom ASE calculators and formatted data files. Here, the molecular structure of water is built from ASE’s G2 database, with the reference HF run with qc2’s custom PySCF ASE calculator. By default, all relevant electronic structure data, including the initial molecular orbitals and electron integrals, are saved in the &lt;em&gt;h2o.hdf5&lt;/em&gt; formatted datafile, following the QCSchema. The information contained in this file is used by *qc2Data *to build the molecular hamiltonian and its qubit representation. Despite being highly customizable, all the details of the VQE workflow discussed in the previous section are abstracted into a &lt;em&gt;VQE&lt;/em&gt; class instance, which, in this case, corresponds to the PennyLane &lt;em&gt;VQE&lt;/em&gt; class from the qc2’s algorithms package. This is passed to the &lt;em&gt;qc2data.algorithm&lt;/em&gt; attribute.&lt;/p&gt;
&lt;p&gt;The next example illustrates how to conduct an oo-VQE run using the Qiskit &lt;em&gt;oo_VQE&lt;/em&gt; class as implemented in the qc2’s algorithms package:&lt;/p&gt;
&lt;h1 id=&quot;import-ase-related-modules-1&quot;&gt;Import ASE-related modules&lt;/h1&gt;
&lt;p&gt;from ase.build import molecule&lt;/p&gt;
&lt;h1 id=&quot;import-qc2-modules-1&quot;&gt;Import qc2 modules&lt;/h1&gt;
&lt;p&gt;from qc2.data import qc2Data
from qc2.ase import PySCF
from qc2.algorithms.qiskit import oo_VQE
from qc2.algorithms.utils import ActiveSpace&lt;/p&gt;
&lt;h1 id=&quot;instantiate-qc2data-class-1&quot;&gt;Instantiate qc2Data class&lt;/h1&gt;
&lt;p&gt;qc2data = qc2Data(
molecule=molecule(“H2O”),
filename=“h2o.hdf5”
)&lt;/p&gt;
&lt;h1 id=&quot;specify-and-run-the-quantum-chemistry-qc2-ase-calculator-1&quot;&gt;Specify and run the quantum chemistry qc2-ASE calculator.&lt;/h1&gt;
&lt;h1 id=&quot;if-you-already-have-h2ohdf5-from-a-previous-run-you-can-skip-this-step&quot;&gt;If you already have “h2o.hdf5” from a previous run, you can skip this step.&lt;/h1&gt;
&lt;p&gt;qc2data.molecule.calc = PySCF(
method=“scf.RHF”,
basis=“sto-3g”,
)
qc2data.run()&lt;/p&gt;
&lt;h1 id=&quot;instantiate-oo_vqe-class&quot;&gt;Instantiate oo_VQE class&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm = oo_VQE(
active_space=ActiveSpace(
num_active_electrons=(2, 2),
num_active_spatial_orbitals=4
),
)&lt;/p&gt;
&lt;h1 id=&quot;run-oo-vqe-algorithm&quot;&gt;Run oo-VQE algorithm&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm.run()The structure of the input is exactly the same as before, with the exception that we are now instantiating and running a different algorithm class. A distinct qc2-ASE calculator could also be used, such as &lt;a href=&quot;https://www.diracprogram.org/&quot;&gt;DIRAC&lt;/a&gt; or &lt;a href=&quot;https://qc2.readthedocs.io/en/latest/ase/building_qc2_ASEs.html&quot;&gt;your own calculator&lt;/a&gt;, with minimal changes and effort. This is a hallmark of qc2. Additionally, since we have previously completed a HF calculation in our VQE example above and saved all relevant &lt;em&gt;ab initio&lt;/em&gt; data in &lt;em&gt;h2o.hdf5&lt;/em&gt;, we could simply skip this step and proceed directly to defining the &lt;em&gt;oo_VQE&lt;/em&gt; class. In this scenario, qc2 will automatically read the data contained in &lt;em&gt;h2o.hdf5&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--764d744f.DX-Vp-Gq_Z1ClJ4p.webp&quot; srcset=&quot;&quot;&gt;
Energy convergence of ground-state water obtained from qc2’s VQE and oo-VQE algorithms. Also shown by dashed lines are the results obtained using traditional quantum chemistry &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASCI&lt;/a&gt;(4, 4)/STO-3G and &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASSCF&lt;/a&gt;(4, 4)/STO-3G methods with PySCF. At iteration #0, both VQE and oo-VQE start at the reference HF energy.The figure shows the energy convergence of ground-state water as obtained using the above qc2 input examples. Although qc2 can be directly interfaced with real quantum backends, for illustration purposes, all quantum circuit evaluations were conducted with the &lt;em&gt;default.qubit&lt;/em&gt; state simulator device for PennyLane and the Qiskit* Estimator primitive* with *StateVector, *both providing exact expectation values. As expected, oo-VQE energies are variationally lower and converge nearly exactly to the predicted &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASSCF&lt;/a&gt; values. Recall, however, that while oo-VQE is computationally more expensive than traditional VQE, this additional burden is entirely placed on the classical computer (optimizers), not the quantum backend. Note further from the figure that, since all initial circuit (and orbital rotation) parameters are set to zero by default, both VQE and oo-VQE initiate their interactive processes at the reference HF energy.&lt;/p&gt;
&lt;h3 id=&quot;whats-next-&quot;&gt;What’s next ?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt; is an ever-evolving open-source project, constantly enriched by new algorithms and features. Looking ahead, we are excited about incorporating even more enhancements. We warmly welcome your &lt;a href=&quot;https://github.com/qc2nl/qc2/blob/main/CONTRIBUTING.md&quot;&gt;contributions&lt;/a&gt;, whether they are new ideas, unique perspectives, or intriguing use cases you would like to see qc2 tackle. Every form of participation is valued — from a quick comment or question to in-depth pull requests. Join us in shaping the future of qc2!&lt;/p&gt;
&lt;p&gt;This article was co-authored with [Nicolas Renaud], with whom I maintained a fruitful collaboration during the &lt;a href=&quot;https://research-software-directory.org/projects/qcforqc&quot;&gt;QCforQC project&lt;/a&gt;, and who generously shared his experiences and knowledge with me.&lt;/p&gt;</description><pubDate>Thu, 27 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Q&lt;em&gt;uantum Computing is a rapidly evolving field that has the potential to transform the way we approach complex computational problems. Quantum Chemistry stands out as a prime application area, with anticipated impacts ranging from the development of new materials to novel drugs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this blog, we introduce &lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt;, a user-friendly, modular software designed to seamlessly integrate traditional quantum chemistry codes with modern quantum computing Software Development Kits (SDKs).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;550&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--f78b0228.hCUsNgvR_28XFny.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lazycreekimages?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Michael Dziedzic&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;
&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;258&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--59e5e045.TUY_z8tQ_pj3CX.webp&quot; srcset=&quot;&quot;&gt;
However, despite recent advances in both hardware and software, the path to fully error-corrected, utility-scale quantum computations may still take a while. For the moment, as we navigate in the &lt;a href=&quot;https://arxiv.org/abs/1801.00862&quot;&gt;Noisy Intermediate-Scale Quantum (NISQ) era&lt;/a&gt; towards &lt;a href=&quot;https://www.ibm.com/quantum/blog/what-is-quantum-utlity&quot;&gt;Quantum Utility&lt;/a&gt;, we need to learn how to make the most out of the available algorithms that run on as-yet error-prone, imperfect hardware: the so-called &lt;a href=&quot;https://arxiv.org/abs/2101.08448&quot;&gt;NISQ algorithms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unavoidably, &lt;a href=&quot;https://www.ibm.com/topics/quantum-computing&quot;&gt;Quantum Computing&lt;/a&gt; and &lt;a href=&quot;https://onlinelibrary.wiley.com/doi/book/10.1002/9781119019572&quot;&gt;Quantum Chemistry&lt;/a&gt;, and particularly &lt;a href=&quot;https://doi.org/10.48550/arXiv.2001.03685&quot;&gt;their combination&lt;/a&gt;, demand a high level of technical knowledge. The available software packages are highly specialised, requiring users to have an excellent understanding of the fundamental concepts involved from the start. This might scare away both computational chemists and software engineers alike.&lt;/p&gt;
&lt;p&gt;This situation has been greatly alleviated by the increasing availability of excellent &lt;a href=&quot;https://learning.quantum.ibm.com/&quot;&gt;&lt;em&gt;educational resources&lt;/em&gt;**&lt;/a&gt; and &lt;a href=&quot;https://journals.plos.org/plosone/article?id=10.1371%2Fjournal.pone.0208561&quot;&gt;&lt;em&gt;&lt;strong&gt;good quality open-source software&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;, some even tailored specifically for the quantum chemistry community, &lt;em&gt;e.g.&lt;/em&gt;, &lt;a href=&quot;https://qiskit-community.github.io/qiskit-nature/&quot;&gt;Qiskit-Nature&lt;/a&gt;, &lt;a href=&quot;https://docs.pennylane.ai/en/stable/introduction/chemistry.html&quot;&gt;PennyLane.qchem&lt;/a&gt; and &lt;a href=&quot;https://github.com/goodchemistryco/Tangelo&quot;&gt;Tangelo&lt;/a&gt;. And we believe that this is the right way forward.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt;, a user-friendly, modular software designed to seamlessly integrate traditional quantum chemistry codes with modern quantum computing SDKs. Designed with &lt;em&gt;reusability&lt;/em&gt; and &lt;em&gt;interoperability&lt;/em&gt; in mind, qc2 leverages popular existing tools such as the &lt;a href=&quot;https://wiki.fysik.dtu.dk/ase/&quot;&gt;Atomic Simulation Environment (ASE)&lt;/a&gt; and &lt;a href=&quot;https://molssi.org/software/qcschema-2/&quot;&gt;Quantum Chemistry Schema (QCSchema)&lt;/a&gt;. It can also be easily customized to work with your preferred backends, requiring minimal implementation effort.&lt;/p&gt;
&lt;p&gt;Before we dive in, let’s quickly recap some useful concepts…&lt;/p&gt;
&lt;h3 id=&quot;quick-recap-quantum-chemistry-with-classical-computers&quot;&gt;Quick Recap: Quantum Chemistry with Classical Computers&lt;/h3&gt;
&lt;p&gt;The primary goal of quantum chemistry is to understand the structure and properties of matter at microscopic level. Atoms and molecules are intricate quantum entities and are characterized by discrete energy levels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;549&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--b0883893.BEPjHfk4_Z2cfK1D.webp&quot; srcset=&quot;&quot;&gt;
Schematic representation of the discrete electronic energy levels of the water molecule in its most stable configuration.Such a quantized energy spectrum naturally arises from solving the systems’ Schrödinger equation (SE):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;484&quot; height=&quot;88&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--eb730c90.BKSd8jb3_W4Jr4.webp&quot; srcset=&quot;&quot;&gt;
Time-independent Schrödinger equation. H is the Hamiltonian operator (^); |ψ⟩ and E represent the wave function and energy of a quantum state i.This equation represents a typical eigenvalue problem that can only be solved exactly for one-electron systems, &lt;em&gt;e.g.&lt;/em&gt;, the hydrogen atom. For all other systems, we must rely on mathematical and physical models that approximate the exact solutions to the SE. Examples of such models are the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hartree%E2%80%93Fock_method&quot;&gt;Hartree–Fock (HF) method&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Coupled_cluster&quot;&gt;Coupled cluster&lt;/a&gt; (CC) and &lt;a href=&quot;https://en.wikipedia.org/wiki/Full_configuration_interaction&quot;&gt;Full configuration interaction&lt;/a&gt; (FCI).&lt;/p&gt;
&lt;p&gt;In general, the strategy involves expanding the unknown wave function of your system as a linear combination of &lt;em&gt;n&lt;/em&gt; known wave functions:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;41&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--2c0ee02a.BzErDrw7_Z2kDPkl.webp&quot; srcset=&quot;&quot;&gt;
Ground-state molecular wave function as a linear combination of Slater determinants (|φ₁⟩, .., |φₙ⟩) formed from a reference HF wave function, |φ₀⟩. The coefficients α, β, γ, and δ minimize the expectation value of H.Now, the task of determining the coefficients α, β, γ, and δ, along with the associated ground and possibly excited-state energies, involves setting up and diagonalizing a large &lt;em&gt;n&lt;/em&gt; by &lt;em&gt;n&lt;/em&gt; matrix:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;118&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--4d04a3d7.Cd4nYLiW_Z1Ssp1e.webp&quot; srcset=&quot;&quot;&gt;
Diagonalization by a unitary similarity transformation. &lt;strong&gt;U&lt;/strong&gt; is a matrix whose columns are the eigenvectors of H containing α, β, γ, and δ coefficients.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This step is certainly the major computational bottleneck for classical computers and the one that quantum algorithms seek to bypass.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a general rule, the larger &lt;em&gt;n&lt;/em&gt; is, the closer the solution approaches the exact solution to the SE, but the more &lt;a href=&quot;https://arxiv.org/abs/1208.3334&quot;&gt;computationally expensive&lt;/a&gt; it becomes. Not surprisingly, typical “gold-standard” methods like CCSD(T) (let alone FCI) quickly become unaffordable for medium-to-large sized molecules.&lt;/p&gt;
&lt;h3 id=&quot;quantum-chemistry-with-quantum-computers-nisq-algorithms&quot;&gt;Quantum Chemistry with Quantum Computers: NISQ algorithms&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;343&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--29ba8ef0.BpjsK2Fi_Z1KnFUV.webp&quot; srcset=&quot;&quot;&gt;
*Schematic representation of a VQE workflow. &lt;strong&gt;&lt;strong&gt;𝜃&lt;/strong&gt;&lt;/strong&gt; represent circuit parameters that are variationally optimized by an external classical routine. Expectation values of the molecular Hamiltonian 𝐻 are evaluated at circuit level.*Let’s now examine the problem we just discussed from a different perspective: that of Quantum Computing.&lt;/p&gt;
&lt;p&gt;Within the NISQ era, the task of approaching the exact solution to the SE primarily relies on &lt;a href=&quot;https://arxiv.org/abs/2101.08448&quot;&gt;hybrid quantum-classical algorithms&lt;/a&gt;, and there are compelling reasons for this. These algorithms are designed to run on noisy quantum hardware; they utilize as few quantum gates as possible and can be optimized to operate within the limited coherence time of the devices’ qubits, the units of quantum computation. Among these, the &lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;Variational Quantum Eigensolver (VQE)&lt;/a&gt; is specially prominent when the goal is to calculate ground-state energies and properties of molecules.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Reference quantum circuit&lt;/em&gt;.** Similar to a typical quantum chemistry calculation, we begin by defining a reference wave function for the target molecule, *|*φ₀⟩. This is usually accomplished by using traditional quantum chemistry packages, &lt;em&gt;e.g.&lt;/em&gt;, by conducting a HF calculation with &lt;a href=&quot;https://pyscf.org/&quot;&gt;PySCF&lt;/a&gt;. From this, a reference quantum circuit can be created by directly mapping the &lt;em&gt;spin-orbitals’ occupation numbers&lt;/em&gt; into initial qubit states (&lt;em&gt;the calculated &lt;em&gt;&lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;&lt;em&gt;electron integrals&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; are also useful later for building the molecular Hamiltonian in step 3&lt;/em&gt;). As an example, consider a hydrogen molecule (H₂) with a minimal basis set, such as STO-3G. Here, the final HF wave function |1100⟩ is mapped into a four-qubit quantum circuit |1⟩ ⊗ |1⟩ ⊗ |0⟩ ⊗ |0⟩. For larger molecules or one-electron bases, it may be necessary to restrict the qubit space by creating a reference quantum circuit out of a preselected &lt;em&gt;active space&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Parametrized quantum circuit.&lt;/strong&gt;&lt;/em&gt; After setting the initial qubit states, the next step is to represent the wave function &lt;em&gt;|Ψ&lt;/em&gt;₀⟩ on the quantum device, &lt;em&gt;i.e.&lt;/em&gt;, to prepare a parametrized quantum state. This is achieved by applying a predefined set of quantum gates, which depend on certain parameters &lt;em&gt;&lt;strong&gt;θ&lt;/strong&gt;&lt;/em&gt;, to the initial qubit states. Similarly to &lt;em&gt;|Ψ&lt;/em&gt;₀⟩, the resulting parametrized quantum circuit &lt;em&gt;|Ψ(&lt;strong&gt;&lt;strong&gt;θ&lt;/strong&gt;&lt;/strong&gt;)&lt;/em&gt;⟩, often referred to as the &lt;em&gt;ansatz&lt;/em&gt;, seeks to approximate the true ground-state wave function of the target molecule. The set of variational (qubit rotation) parameters ***θ ***is, in some sense, analogous to the coefficients α, β, γ, and δ discussed earlier in the context of traditional quantum chemistry.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Energy Estimation.&lt;/strong&gt;&lt;/em&gt;* *With the parametrized quantum circuit at hand and a set of initial parameters &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ&lt;/strong&gt;, we estimate the expectation value of the molecular Hamiltonian. This process involves mapping the &lt;a href=&quot;https://arxiv.org/abs/1812.09976&quot;&gt;Hamiltonian in second quantization into a qubit representation&lt;/a&gt;, namely, as a sum of Pauli terms. The final energy, which is given as a sum the measured expectation values of each Pauli term, depends on &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ&lt;/strong&gt; and should be minimized accordingly.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Classical Feedback:&lt;/strong&gt;&lt;/em&gt;* &lt;em&gt;The minimization process is carried out using an external classical optimization routine,&lt;/em&gt; *which updates the circuit parameters &lt;strong&gt;&lt;em&gt;θ&lt;/em&gt;ᵢ.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steps 3 and 4&lt;/strong&gt; are repeated until convergence is achieved, resulting in the lowest possible expectation value. The final energy corresponds to the ground-state energy of the target molecule as predicted by VQE.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The quality of the VQE solutions depends on several factors, including the size of the active space (if any), type of ansatz, initial guesses for the circuit parameters, the classical optimizer used, and other potential sources of error if run on real quantum hardware.&lt;/p&gt;
&lt;p&gt;Another popular NISQ algorithm for finding the ground-state energy of molecules is the &lt;a href=&quot;https://arxiv.org/abs/2212.02482&quot;&gt;orbital-optimized VQE&lt;/a&gt; (oo-VQE), which extends the traditional VQE. In oo-VQE, not only are the circuit parameters optimized, but the original HF molecular orbitals are also allowed to relax during the classical optimization process. For this reason, ground-state variational energies obtained with oo-VQE are generally lower than those from traditional VQE runs, but they are also computationally more expensive. As will be shown later, VQE and oo-VQE could be seen as some sort of quantum analogues of the traditional &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASCI and CASSCF&lt;/a&gt; &lt;em&gt;ab initio&lt;/em&gt; methods.&lt;/p&gt;
&lt;h3 id=&quot;overview-of-qc2&quot;&gt;Overview of qc2&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;278&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--da9ac281.LN0EABsU_Z1DyBEo.webp&quot; srcset=&quot;&quot;&gt;
Schematic representation of qc2 design and workflow.&lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt; is an open-source python package specifically crafted for hybrid quantum-classical algorithms such as VQE and oo-VQE. It embraces several core &lt;em&gt;design principles&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Leveraging Existing Tools&lt;/strong&gt;: qc2 is interoperable with existing open-source quantum chemistry tools, like &lt;a href=&quot;https://wiki.fysik.dtu.dk/ase/&quot;&gt;ASE calculators&lt;/a&gt;, and adheres to standard data schemas, such as &lt;a href=&quot;https://molssi.org/software/qcschema-2/&quot;&gt;QCSchema&lt;/a&gt; or &lt;a href=&quot;https://doi.org/10.1016/0010-4655(89)90033-7&quot;&gt;FCIDump&lt;/a&gt;. This ensures efficient data exchange necessary for various quantum computing libraries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless Integration with Quantum Computing SDKs&lt;/strong&gt;: qc2 is designed to work effortlessly with &lt;a href=&quot;https://www.ibm.com/quantum/qiskit&quot;&gt;Qiskit&lt;/a&gt; and &lt;a href=&quot;https://pennylane.ai/&quot;&gt;PennyLane&lt;/a&gt;, ensuring a smooth user experience for developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: The package boasts high modularity, featuring a robust built-in algorithms package that simplifies extensions and enhancements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-Friendly Design&lt;/strong&gt;: qc2 is straightforward and has an intuitive interface, enabling users to focus on their research and applications with minimal technical details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the code block below, we present a minimal example using qc2 for a simple VQE run on the water molecule:&lt;/p&gt;
&lt;h1 id=&quot;import-ase-related-modules&quot;&gt;Import ASE-related modules&lt;/h1&gt;
&lt;p&gt;from ase.build import molecule&lt;/p&gt;
&lt;h1 id=&quot;import-qc2-modules&quot;&gt;Import qc2 modules&lt;/h1&gt;
&lt;p&gt;from qc2.data import qc2Data
from qc2.ase import PySCF
from qc2.algorithms.pennylane import VQE
from qc2.algorithms.utils import ActiveSpace&lt;/p&gt;
&lt;h1 id=&quot;instantiate-qc2data-class&quot;&gt;Instantiate qc2Data class&lt;/h1&gt;
&lt;p&gt;qc2data = qc2Data(
molecule=molecule(“H2O”),
filename=“h2o.hdf5”
)&lt;/p&gt;
&lt;h1 id=&quot;specify-and-run-the-quantum-chemistry-qc2-ase-calculator&quot;&gt;Specify and run the quantum chemistry qc2-ASE calculator&lt;/h1&gt;
&lt;p&gt;qc2data.molecule.calc = PySCF(
method=“scf.RHF”,
basis=“sto-3g”,
)
qc2data.run()&lt;/p&gt;
&lt;h1 id=&quot;instantiate-vqe-class&quot;&gt;Instantiate VQE class&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm = VQE(
active_space=ActiveSpace(
num_active_electrons=(2, 2),
num_active_spatial_orbitals=4
),
)&lt;/p&gt;
&lt;h1 id=&quot;run-vqe-algorithm&quot;&gt;Run VQE algorithm&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm.run()As noted, qc2 is designed around the &lt;em&gt;qc2Data&lt;/em&gt; class, which links traditional quantum chemistry codes with quantum computing backends through custom ASE calculators and formatted data files. Here, the molecular structure of water is built from ASE’s G2 database, with the reference HF run with qc2’s custom PySCF ASE calculator. By default, all relevant electronic structure data, including the initial molecular orbitals and electron integrals, are saved in the &lt;em&gt;h2o.hdf5&lt;/em&gt; formatted datafile, following the QCSchema. The information contained in this file is used by *qc2Data *to build the molecular hamiltonian and its qubit representation. Despite being highly customizable, all the details of the VQE workflow discussed in the previous section are abstracted into a &lt;em&gt;VQE&lt;/em&gt; class instance, which, in this case, corresponds to the PennyLane &lt;em&gt;VQE&lt;/em&gt; class from the qc2’s algorithms package. This is passed to the &lt;em&gt;qc2data.algorithm&lt;/em&gt; attribute.&lt;/p&gt;
&lt;p&gt;The next example illustrates how to conduct an oo-VQE run using the Qiskit &lt;em&gt;oo_VQE&lt;/em&gt; class as implemented in the qc2’s algorithms package:&lt;/p&gt;
&lt;h1 id=&quot;import-ase-related-modules-1&quot;&gt;Import ASE-related modules&lt;/h1&gt;
&lt;p&gt;from ase.build import molecule&lt;/p&gt;
&lt;h1 id=&quot;import-qc2-modules-1&quot;&gt;Import qc2 modules&lt;/h1&gt;
&lt;p&gt;from qc2.data import qc2Data
from qc2.ase import PySCF
from qc2.algorithms.qiskit import oo_VQE
from qc2.algorithms.utils import ActiveSpace&lt;/p&gt;
&lt;h1 id=&quot;instantiate-qc2data-class-1&quot;&gt;Instantiate qc2Data class&lt;/h1&gt;
&lt;p&gt;qc2data = qc2Data(
molecule=molecule(“H2O”),
filename=“h2o.hdf5”
)&lt;/p&gt;
&lt;h1 id=&quot;specify-and-run-the-quantum-chemistry-qc2-ase-calculator-1&quot;&gt;Specify and run the quantum chemistry qc2-ASE calculator.&lt;/h1&gt;
&lt;h1 id=&quot;if-you-already-have-h2ohdf5-from-a-previous-run-you-can-skip-this-step&quot;&gt;If you already have “h2o.hdf5” from a previous run, you can skip this step.&lt;/h1&gt;
&lt;p&gt;qc2data.molecule.calc = PySCF(
method=“scf.RHF”,
basis=“sto-3g”,
)
qc2data.run()&lt;/p&gt;
&lt;h1 id=&quot;instantiate-oo_vqe-class&quot;&gt;Instantiate oo_VQE class&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm = oo_VQE(
active_space=ActiveSpace(
num_active_electrons=(2, 2),
num_active_spatial_orbitals=4
),
)&lt;/p&gt;
&lt;h1 id=&quot;run-oo-vqe-algorithm&quot;&gt;Run oo-VQE algorithm&lt;/h1&gt;
&lt;p&gt;qc2data.algorithm.run()The structure of the input is exactly the same as before, with the exception that we are now instantiating and running a different algorithm class. A distinct qc2-ASE calculator could also be used, such as &lt;a href=&quot;https://www.diracprogram.org/&quot;&gt;DIRAC&lt;/a&gt; or &lt;a href=&quot;https://qc2.readthedocs.io/en/latest/ase/building_qc2_ASEs.html&quot;&gt;your own calculator&lt;/a&gt;, with minimal changes and effort. This is a hallmark of qc2. Additionally, since we have previously completed a HF calculation in our VQE example above and saved all relevant &lt;em&gt;ab initio&lt;/em&gt; data in &lt;em&gt;h2o.hdf5&lt;/em&gt;, we could simply skip this step and proceed directly to defining the &lt;em&gt;oo_VQE&lt;/em&gt; class. In this scenario, qc2 will automatically read the data contained in &lt;em&gt;h2o.hdf5&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quantum Computing for Quantum Chemistry with qc2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--764d744f.DX-Vp-Gq_Z1ClJ4p.webp&quot; srcset=&quot;&quot;&gt;
Energy convergence of ground-state water obtained from qc2’s VQE and oo-VQE algorithms. Also shown by dashed lines are the results obtained using traditional quantum chemistry &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASCI&lt;/a&gt;(4, 4)/STO-3G and &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASSCF&lt;/a&gt;(4, 4)/STO-3G methods with PySCF. At iteration #0, both VQE and oo-VQE start at the reference HF energy.The figure shows the energy convergence of ground-state water as obtained using the above qc2 input examples. Although qc2 can be directly interfaced with real quantum backends, for illustration purposes, all quantum circuit evaluations were conducted with the &lt;em&gt;default.qubit&lt;/em&gt; state simulator device for PennyLane and the Qiskit* Estimator primitive* with *StateVector, *both providing exact expectation values. As expected, oo-VQE energies are variationally lower and converge nearly exactly to the predicted &lt;a href=&quot;https://pyscf.org/user/mcscf.html&quot;&gt;CASSCF&lt;/a&gt; values. Recall, however, that while oo-VQE is computationally more expensive than traditional VQE, this additional burden is entirely placed on the classical computer (optimizers), not the quantum backend. Note further from the figure that, since all initial circuit (and orbital rotation) parameters are set to zero by default, both VQE and oo-VQE initiate their interactive processes at the reference HF energy.&lt;/p&gt;
&lt;h3 id=&quot;whats-next-&quot;&gt;What’s next ?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/qc2nl/qc2&quot;&gt;qc2&lt;/a&gt; is an ever-evolving open-source project, constantly enriched by new algorithms and features. Looking ahead, we are excited about incorporating even more enhancements. We warmly welcome your &lt;a href=&quot;https://github.com/qc2nl/qc2/blob/main/CONTRIBUTING.md&quot;&gt;contributions&lt;/a&gt;, whether they are new ideas, unique perspectives, or intriguing use cases you would like to see qc2 tackle. Every form of participation is valued — from a quick comment or question to in-depth pull requests. Join us in shaping the future of qc2!&lt;/p&gt;
&lt;p&gt;This article was co-authored with [Nicolas Renaud], with whom I maintained a fruitful collaboration during the &lt;a href=&quot;https://research-software-directory.org/projects/qcforqc&quot;&gt;QCforQC project&lt;/a&gt;, and who generously shared his experiences and knowledge with me.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/quantum-computing-for-quantum-chemistry--f78b0228.hCUsNgvR.jpg" medium="image"/><author>Carlosmurilorocha</author></item><item><title>Transparency in research... and football</title><link>https://blog.esciencecenter.nl/posts/2024-06-27---transparency-in-research-and-football</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-06-27---transparency-in-research-and-football</guid><description>&lt;p&gt;A strategy for dealing with subjectivity in research, and in football, is to expose it. The VAR system in football allows the referee to scrutinise video footage of players, decide how grave a foul was, whether a ball crossed a line, or whether a situation should be deemed offside or not. It is a system designed to minimise human errors that could have a big influence on match results. It does not remove subjectivity, but it makes the ref’s decision-making process more transparent.&lt;/p&gt;
&lt;p&gt;Openly sharing research software serves a similar goal.² Or, as &lt;a href=&quot;https://journals.sagepub.com/doi/10.1177/2515245917747646#_i40&quot;&gt;Silberzahn et al.&lt;/a&gt; argue: “Transparency in data, methods, and process gives the rest of the community opportunity to see the decisions, question them, offer alternatives, and test these alternatives in further research.” However, as Antica Culina pointed out during the workshop, sharing code is not yet a standard practice for all researchers who write it.&lt;/p&gt;
&lt;p&gt;Without a guide or a plan, it may be unfair to expect every researcher to know how to do this. A standardised SMP template could help. As &lt;a href=&quot;https://nioo.knaw.nl/en/employees/antica-culina&quot;&gt;Steve Crouch&lt;/a&gt; from the &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; (SSI) explained, SMPs require researchers to make explicit what their software does, who it is for, what the outputs are, who is responsible for the release and to ensure that the software stays available to the community.&lt;/p&gt;
&lt;p&gt;The workshop participants provided valuable input as to what an SMP template should contain. Currently, researchers typically specify their plans for managing software in data management plans. During the SMP workshop, it was apparent that there is a need for clear guidelines specifically for software management, in addition to data management, among researchers. Participants also made clear that because researchers are usually not software engineers, an SMP template would need to use plain language, accessible to those who may be familiar enough with coding to write a few analysis scripts for research, but are not familiar with professional software development.&lt;/p&gt;
&lt;p&gt;Participants also said that if writing plans for software management is to become standard practice in the future, the benefits of doing so should be emphasised to those who write code for research. Many in academia already feel overwhelmed with the amount of admin their work requires, and SMPs could be in danger of becoming ‘another form’. But beyond the benefit to the community, there can be a lot of value in writing an SMP to individuals. If software is an important part of the research output, an SMP helps researchers, engineers and research support staff to think about how that software will be structured, shared, and maintained. This can save time and effort later, when reproducing the results, or when using that software in a different project. Another benefit for the researcher lies in the increasing importance of software for research. An SMP can help researchers to write better quality software, which will likely be an important part of a researcher’s portfolio in the future.&lt;/p&gt;
&lt;p&gt;Still an open question is whether an SMP should be a part of every research project, and whether they should be integrated with data management plans. In addition, it is unclear if a universal SMP template is desirable, since different academic disciplines may have different software management needs. The eScience Center and NWO are setting up a working group to explore these questions and the possibility of creating a national template for Software Management Plans for Dutch research organisations.&lt;/p&gt;
&lt;p&gt;We would like to thank &lt;a href=&quot;https://www.nwo.nl/en/research-data-management&quot;&gt;Maria Cruz&lt;/a&gt; (NWO), &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/steve-crouch&quot;&gt;Steve Crouch&lt;/a&gt; (SSI) and &lt;a href=&quot;https://nioo.knaw.nl/en/employees/antica-culina&quot;&gt;Antica Culina&lt;/a&gt; (NIOO) for their insightful talks about Data Management Plans and Software Management Plans. Thanks also to all participants for their valuable input.&lt;/p&gt;
&lt;p&gt;[1] For those not familiar with the rules of football, a red card is the heaviest correctional tool in football (soccer). It means that the player must leave the field immediately without being replaced, leaving their team in clear disadvantage. In the case of the European Championships, the player who receives a red card also misses their team’s next match, if there is one.&lt;/p&gt;
&lt;p&gt;[2] Arguably, as my colleague &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; pointed out to me, the whole history of science and epistemology is about minimising human errors. Open Scientific Software doesn’t root in the development of Linux, but in Galileo and Newton.&lt;/p&gt;</description><pubDate>Thu, 27 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A strategy for dealing with subjectivity in research, and in football, is to expose it. The VAR system in football allows the referee to scrutinise video footage of players, decide how grave a foul was, whether a ball crossed a line, or whether a situation should be deemed offside or not. It is a system designed to minimise human errors that could have a big influence on match results. It does not remove subjectivity, but it makes the ref’s decision-making process more transparent.&lt;/p&gt;
&lt;p&gt;Openly sharing research software serves a similar goal.² Or, as &lt;a href=&quot;https://journals.sagepub.com/doi/10.1177/2515245917747646#_i40&quot;&gt;Silberzahn et al.&lt;/a&gt; argue: “Transparency in data, methods, and process gives the rest of the community opportunity to see the decisions, question them, offer alternatives, and test these alternatives in further research.” However, as Antica Culina pointed out during the workshop, sharing code is not yet a standard practice for all researchers who write it.&lt;/p&gt;
&lt;p&gt;Without a guide or a plan, it may be unfair to expect every researcher to know how to do this. A standardised SMP template could help. As &lt;a href=&quot;https://nioo.knaw.nl/en/employees/antica-culina&quot;&gt;Steve Crouch&lt;/a&gt; from the &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; (SSI) explained, SMPs require researchers to make explicit what their software does, who it is for, what the outputs are, who is responsible for the release and to ensure that the software stays available to the community.&lt;/p&gt;
&lt;p&gt;The workshop participants provided valuable input as to what an SMP template should contain. Currently, researchers typically specify their plans for managing software in data management plans. During the SMP workshop, it was apparent that there is a need for clear guidelines specifically for software management, in addition to data management, among researchers. Participants also made clear that because researchers are usually not software engineers, an SMP template would need to use plain language, accessible to those who may be familiar enough with coding to write a few analysis scripts for research, but are not familiar with professional software development.&lt;/p&gt;
&lt;p&gt;Participants also said that if writing plans for software management is to become standard practice in the future, the benefits of doing so should be emphasised to those who write code for research. Many in academia already feel overwhelmed with the amount of admin their work requires, and SMPs could be in danger of becoming ‘another form’. But beyond the benefit to the community, there can be a lot of value in writing an SMP to individuals. If software is an important part of the research output, an SMP helps researchers, engineers and research support staff to think about how that software will be structured, shared, and maintained. This can save time and effort later, when reproducing the results, or when using that software in a different project. Another benefit for the researcher lies in the increasing importance of software for research. An SMP can help researchers to write better quality software, which will likely be an important part of a researcher’s portfolio in the future.&lt;/p&gt;
&lt;p&gt;Still an open question is whether an SMP should be a part of every research project, and whether they should be integrated with data management plans. In addition, it is unclear if a universal SMP template is desirable, since different academic disciplines may have different software management needs. The eScience Center and NWO are setting up a working group to explore these questions and the possibility of creating a national template for Software Management Plans for Dutch research organisations.&lt;/p&gt;
&lt;p&gt;We would like to thank &lt;a href=&quot;https://www.nwo.nl/en/research-data-management&quot;&gt;Maria Cruz&lt;/a&gt; (NWO), &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/steve-crouch&quot;&gt;Steve Crouch&lt;/a&gt; (SSI) and &lt;a href=&quot;https://nioo.knaw.nl/en/employees/antica-culina&quot;&gt;Antica Culina&lt;/a&gt; (NIOO) for their insightful talks about Data Management Plans and Software Management Plans. Thanks also to all participants for their valuable input.&lt;/p&gt;
&lt;p&gt;[1] For those not familiar with the rules of football, a red card is the heaviest correctional tool in football (soccer). It means that the player must leave the field immediately without being replaced, leaving their team in clear disadvantage. In the case of the European Championships, the player who receives a red card also misses their team’s next match, if there is one.&lt;/p&gt;
&lt;p&gt;[2] Arguably, as my colleague &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; pointed out to me, the whole history of science and epistemology is about minimising human errors. Open Scientific Software doesn’t root in the development of Linux, but in Galileo and Newton.&lt;/p&gt;</content:encoded><author>Lieke de Boer</author></item><item><title>Henry, the City Tweaker</title><link>https://blog.esciencecenter.nl/posts/2024-06-21---henry-the-city-tweaker</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-06-21---henry-the-city-tweaker</guid><description>&lt;h2 id=&quot;imagining-the-future-of-urban-planning&quot;&gt;Imagining the future of urban planning&lt;/h2&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blogpost is our (&lt;a href=&quot;https://www.esciencecenter.nl/news/destination-earth-awards-peter-kalverla-for-his-visionary-proposal-for-the-future/&quot;&gt;winning&lt;/a&gt; &lt;a href=&quot;https://emojipedia.org/party-popper&quot;&gt;🎉&lt;/a&gt;) submission to Destination Earth’s &lt;a href=&quot;https://destination-earth.eu/event/2nd-destine-service-platform-innovation-prize-ideating-the-impact-of-the-desp/&quot;&gt;challenge &lt;/a&gt;to envision the future use of their platform. The story is set in 2050, when “urban sims” have come to replace traditional city planning tools. Urban sims are like the early century’s sandbox games, say, Cities Skylines, but for real. Design proposals with a net positive impact are eligible for execution, on the condition that they gather sufficient support. The story follows Henry as he experiences the rise of city tweaking firsthand.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-19e1aa94.DzQkJD1P_1LpKVS.webp&quot; srcset=&quot;&quot;&gt;
Mockup of an “urban design interface”, powered by the digital twin engine, that was submitted with the challenge.Henry is a city tweaker. He never really pursued his destiny, but in retrospect, it seems all his arbitrary endeavors have been in anticipation of his true calling, which will be revealed to him shortly by an unremarkable lady wearing a white fur hat and a rabbit tattoo.&lt;/p&gt;
&lt;p&gt;His journey starts in the pouring twenties when urban sims are set to democratize urban planning. He makes his debut with an upgrade of the courtyard in his street. Replacing the paved square with a natural playground benefits the local climate, biodiversity, and perceived happiness. The timing is good too: with many new families moving in, there is ample support among the neighbours.&lt;/p&gt;
&lt;p&gt;After this encouraging start, Henry is hooked. As his proficiency grows, people around him start approaching him with their ideas as well. One of his relatives wants to build a sand battery below the communal parking lot, and an acquaintance asks for his help in developing a manure fermentation plant. While urban sims are open to anyone, in practice, by the early 30s, most of the content is created by dedicated individuals, and Henry is your local guru.&lt;/p&gt;
&lt;p&gt;Once he gains enough reputation to earn insider status, he learns to develop mods. This newfound ability draws the attention of companies and entrepreneurs. Mod creators are in high demand, but Henry isn’t in it for the money. He does a few collaborations with crop breeders, adding species to the agriculture module, and works with festival organizers to include an algorithm for acoustic barriers. But he consistently turns down their job offers.&lt;/p&gt;
&lt;p&gt;Instead, he starts participating in so-called “hackathons for the greater good”, organized specifically to tackle grand challenges. He likes the collaborative spirit and the appeal of contributing something substantial, such as the introduction of local distribution networks and a true price concept for public services.&lt;/p&gt;
&lt;p&gt;These are challenging topics indeed. While it is relatively straightforward to understand how design proposals interact with their immediate surroundings, non-local effects are much harder to grasp. Intrigued by the complexity of the problem, Henry spends a big chunk of the 2040s developing an X-AI module to unravel how genuine progress propagates through value chains.&lt;/p&gt;
&lt;p&gt;And so we arrive in 2050 when Henry is startled by the doorbell. “Good morning, Henry.” The friendly voice pauses to let him regain his calm. “I’m looking for a benevolent city tweaker. May I come in?”&lt;/p&gt;
&lt;p&gt;After the usual pleasantries, she turns serious. “Look, Henry. You know that genuine progress comes at the expense of concentrated wealth. You’ve seen it yourself with the distribution networks. Big players with a vested interest in the status quo are seeking to sabotage our system.” She pauses again. “We cannot play cat and mouse. The cat is too clumsy and the mice are too many. We need something of a more ‘&lt;em&gt;viral&lt;/em&gt;’ nature. That why we started IMMUNE.”&lt;/p&gt;
&lt;p&gt;“For your long track record of benevolent contributions and proven skill, you will receive an immunity status. You will be granted full privileges and access to a confidential forum. No strings attached. We simply trust that you will continue to serve society.” And with that, she stands up, leaving Henry as startled as she found him.&lt;/p&gt;
&lt;h2 id=&quot;backstory&quot;&gt;Backstory&lt;/h2&gt;
&lt;p&gt;While the story is completely fictitious, there are a lot of true ideas and concepts that have gone into it. Let me elaborate on some of them.&lt;/p&gt;
&lt;h3 id=&quot;progress-indicators&quot;&gt;Progress indicators&lt;/h3&gt;
&lt;p&gt;The premise of the story is that “designs with a net positive impact are eligible for execution”. But what is a net positive impact? There are several proposals in the literature on how to evaluate “progress”. Our mockups draw inspiration from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Genuine_progress_indicator&quot;&gt;Genuine Progress Indicator&lt;/a&gt;, and the “&lt;a href=&quot;https://doughnuteconomics.org/about-doughnut-economics&quot;&gt;economic doughnut&lt;/a&gt;”. Both models take many different aspects of well-being into account, including social and environmental well-being.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-f074c219.BqxhJLtY_ZP1nDW.webp&quot; srcset=&quot;&quot;&gt;
Left: the genuine progress indicator (&lt;a href=&quot;https://www.recipesforwellbeing.org/genuine-progress-indicator/&quot;&gt;source&lt;/a&gt;). Right: the economic doughnut (&lt;a href=&quot;https://en.wikipedia.org/wiki/Doughnut_%28economic_model%29&quot;&gt;source&lt;/a&gt;).The idea is that the urban sims will evaluate design proposals based on these indicators. Currently, several “local” versions of the doughnut (or rather, the planetary boundaries framework) and the GPI monitor have been published in the scientific literature. Automating this process and making sure that the local scale interacts realistically with the larger scale is probably one of the biggest challenges, both technically and scientifically, in making Henry’s story come true.&lt;/p&gt;
&lt;h3 id=&quot;democratization&quot;&gt;Democratization&lt;/h3&gt;
&lt;p&gt;Another central element of the story is the democratization of urban planning. At first, it may seem unrealistic to outsource important and complex municipality work to “mere citizens”. On the other hand, we do this all the time with (open source) software. Why not do the same with tangible real estate? Especially since it’s publicly owned.&lt;/p&gt;
&lt;p&gt;In fact, at least in the Netherlands, we already have a process where citizens can apply for building permits with the municipality. It’s dull and bureaucratic, but it is there. Imagine what that could look like if you can simply upload a sketch of your plan as designed by a city builder. The design file would already have all the “technical” details required by the municipality. It would make the request and review process much easier.&lt;/p&gt;
&lt;p&gt;Our submission also included a mockup of a “design proposal page”, where the design is advertised and discussed by the relevant stakeholders (see below). In the story, Henry needs to gather support from the neighbours. I think there is a potential here to address the lack of participation and, consequently, lack of support that we see for example with renewable energy projects.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-ca3ab313.um5cylqo_Z29lkyy.webp&quot; srcset=&quot;&quot;&gt;
Mockup of “design proposal page” that could be used to advertise urban design proposals, discuss them, and gather support.By the way, this design was inspired by &lt;a href=&quot;https://www.figma.com/community&quot;&gt;Figma&lt;/a&gt;’s community pages.&lt;/p&gt;
&lt;h3 id=&quot;gamification-or-rather-sciencification&quot;&gt;Gamification, or rather “sciencification”&lt;/h3&gt;
&lt;p&gt;The urban sims in the story take the idea of gamification to the extreme. Games are optimized for a great user experience, and gamification offers immense potential in making science more accessible and engaging to society.&lt;/p&gt;
&lt;p&gt;Recently, game developers have actually been pursuing similar ideas. For example, check out &lt;a href=&quot;https://play.eco/&quot;&gt;https://play.eco/&lt;/a&gt;, which aims to be a “forever game, growing in depth and breath and […] go beyond entertainment.” Perhaps we should be talking about “sciencifying” existing games instead. I would love to collaborate more with game designers.&lt;/p&gt;
&lt;p&gt;On a side note: IMHO science teams could be so much stronger if academia embraced more diverse function profiles. Why not employ dedicated communication specialists (YouTubers / content creators), research software engineers, or game developers in every team/group/department?*&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Imagination is a key driver of innovation and progress. Lifting the constraints of immediate feasibility inspires us to think big and let our creativity guide us. It helps to break away from doing more of the same and instead direct our research and energy towards an inspiring future.&lt;/p&gt;
&lt;p&gt;Participating in the Destination Earth challenge was a very enjoyable experience, and it would be great to see more such initiatives. In the meantime, I will be on the lookout for opportunities to help make Henry’s story come true.&lt;/p&gt;
&lt;p&gt;What do you think are the biggest challenges in realizing these urban sims? What would you add, or change, and what opportunities did I miss? Perhaps we can start shaping our future together!&lt;/p&gt;</description><pubDate>Fri, 21 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;imagining-the-future-of-urban-planning&quot;&gt;Imagining the future of urban planning&lt;/h2&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blogpost is our (&lt;a href=&quot;https://www.esciencecenter.nl/news/destination-earth-awards-peter-kalverla-for-his-visionary-proposal-for-the-future/&quot;&gt;winning&lt;/a&gt; &lt;a href=&quot;https://emojipedia.org/party-popper&quot;&gt;🎉&lt;/a&gt;) submission to Destination Earth’s &lt;a href=&quot;https://destination-earth.eu/event/2nd-destine-service-platform-innovation-prize-ideating-the-impact-of-the-desp/&quot;&gt;challenge &lt;/a&gt;to envision the future use of their platform. The story is set in 2050, when “urban sims” have come to replace traditional city planning tools. Urban sims are like the early century’s sandbox games, say, Cities Skylines, but for real. Design proposals with a net positive impact are eligible for execution, on the condition that they gather sufficient support. The story follows Henry as he experiences the rise of city tweaking firsthand.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-19e1aa94.DzQkJD1P_1LpKVS.webp&quot; srcset=&quot;&quot;&gt;
Mockup of an “urban design interface”, powered by the digital twin engine, that was submitted with the challenge.Henry is a city tweaker. He never really pursued his destiny, but in retrospect, it seems all his arbitrary endeavors have been in anticipation of his true calling, which will be revealed to him shortly by an unremarkable lady wearing a white fur hat and a rabbit tattoo.&lt;/p&gt;
&lt;p&gt;His journey starts in the pouring twenties when urban sims are set to democratize urban planning. He makes his debut with an upgrade of the courtyard in his street. Replacing the paved square with a natural playground benefits the local climate, biodiversity, and perceived happiness. The timing is good too: with many new families moving in, there is ample support among the neighbours.&lt;/p&gt;
&lt;p&gt;After this encouraging start, Henry is hooked. As his proficiency grows, people around him start approaching him with their ideas as well. One of his relatives wants to build a sand battery below the communal parking lot, and an acquaintance asks for his help in developing a manure fermentation plant. While urban sims are open to anyone, in practice, by the early 30s, most of the content is created by dedicated individuals, and Henry is your local guru.&lt;/p&gt;
&lt;p&gt;Once he gains enough reputation to earn insider status, he learns to develop mods. This newfound ability draws the attention of companies and entrepreneurs. Mod creators are in high demand, but Henry isn’t in it for the money. He does a few collaborations with crop breeders, adding species to the agriculture module, and works with festival organizers to include an algorithm for acoustic barriers. But he consistently turns down their job offers.&lt;/p&gt;
&lt;p&gt;Instead, he starts participating in so-called “hackathons for the greater good”, organized specifically to tackle grand challenges. He likes the collaborative spirit and the appeal of contributing something substantial, such as the introduction of local distribution networks and a true price concept for public services.&lt;/p&gt;
&lt;p&gt;These are challenging topics indeed. While it is relatively straightforward to understand how design proposals interact with their immediate surroundings, non-local effects are much harder to grasp. Intrigued by the complexity of the problem, Henry spends a big chunk of the 2040s developing an X-AI module to unravel how genuine progress propagates through value chains.&lt;/p&gt;
&lt;p&gt;And so we arrive in 2050 when Henry is startled by the doorbell. “Good morning, Henry.” The friendly voice pauses to let him regain his calm. “I’m looking for a benevolent city tweaker. May I come in?”&lt;/p&gt;
&lt;p&gt;After the usual pleasantries, she turns serious. “Look, Henry. You know that genuine progress comes at the expense of concentrated wealth. You’ve seen it yourself with the distribution networks. Big players with a vested interest in the status quo are seeking to sabotage our system.” She pauses again. “We cannot play cat and mouse. The cat is too clumsy and the mice are too many. We need something of a more ‘&lt;em&gt;viral&lt;/em&gt;’ nature. That why we started IMMUNE.”&lt;/p&gt;
&lt;p&gt;“For your long track record of benevolent contributions and proven skill, you will receive an immunity status. You will be granted full privileges and access to a confidential forum. No strings attached. We simply trust that you will continue to serve society.” And with that, she stands up, leaving Henry as startled as she found him.&lt;/p&gt;
&lt;h2 id=&quot;backstory&quot;&gt;Backstory&lt;/h2&gt;
&lt;p&gt;While the story is completely fictitious, there are a lot of true ideas and concepts that have gone into it. Let me elaborate on some of them.&lt;/p&gt;
&lt;h3 id=&quot;progress-indicators&quot;&gt;Progress indicators&lt;/h3&gt;
&lt;p&gt;The premise of the story is that “designs with a net positive impact are eligible for execution”. But what is a net positive impact? There are several proposals in the literature on how to evaluate “progress”. Our mockups draw inspiration from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Genuine_progress_indicator&quot;&gt;Genuine Progress Indicator&lt;/a&gt;, and the “&lt;a href=&quot;https://doughnuteconomics.org/about-doughnut-economics&quot;&gt;economic doughnut&lt;/a&gt;”. Both models take many different aspects of well-being into account, including social and environmental well-being.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-f074c219.BqxhJLtY_ZP1nDW.webp&quot; srcset=&quot;&quot;&gt;
Left: the genuine progress indicator (&lt;a href=&quot;https://www.recipesforwellbeing.org/genuine-progress-indicator/&quot;&gt;source&lt;/a&gt;). Right: the economic doughnut (&lt;a href=&quot;https://en.wikipedia.org/wiki/Doughnut_%28economic_model%29&quot;&gt;source&lt;/a&gt;).The idea is that the urban sims will evaluate design proposals based on these indicators. Currently, several “local” versions of the doughnut (or rather, the planetary boundaries framework) and the GPI monitor have been published in the scientific literature. Automating this process and making sure that the local scale interacts realistically with the larger scale is probably one of the biggest challenges, both technically and scientifically, in making Henry’s story come true.&lt;/p&gt;
&lt;h3 id=&quot;democratization&quot;&gt;Democratization&lt;/h3&gt;
&lt;p&gt;Another central element of the story is the democratization of urban planning. At first, it may seem unrealistic to outsource important and complex municipality work to “mere citizens”. On the other hand, we do this all the time with (open source) software. Why not do the same with tangible real estate? Especially since it’s publicly owned.&lt;/p&gt;
&lt;p&gt;In fact, at least in the Netherlands, we already have a process where citizens can apply for building permits with the municipality. It’s dull and bureaucratic, but it is there. Imagine what that could look like if you can simply upload a sketch of your plan as designed by a city builder. The design file would already have all the “technical” details required by the municipality. It would make the request and review process much easier.&lt;/p&gt;
&lt;p&gt;Our submission also included a mockup of a “design proposal page”, where the design is advertised and discussed by the relevant stakeholders (see below). In the story, Henry needs to gather support from the neighbours. I think there is a potential here to address the lack of participation and, consequently, lack of support that we see for example with renewable energy projects.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Henry, the City Tweaker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-ca3ab313.um5cylqo_Z29lkyy.webp&quot; srcset=&quot;&quot;&gt;
Mockup of “design proposal page” that could be used to advertise urban design proposals, discuss them, and gather support.By the way, this design was inspired by &lt;a href=&quot;https://www.figma.com/community&quot;&gt;Figma&lt;/a&gt;’s community pages.&lt;/p&gt;
&lt;h3 id=&quot;gamification-or-rather-sciencification&quot;&gt;Gamification, or rather “sciencification”&lt;/h3&gt;
&lt;p&gt;The urban sims in the story take the idea of gamification to the extreme. Games are optimized for a great user experience, and gamification offers immense potential in making science more accessible and engaging to society.&lt;/p&gt;
&lt;p&gt;Recently, game developers have actually been pursuing similar ideas. For example, check out &lt;a href=&quot;https://play.eco/&quot;&gt;https://play.eco/&lt;/a&gt;, which aims to be a “forever game, growing in depth and breath and […] go beyond entertainment.” Perhaps we should be talking about “sciencifying” existing games instead. I would love to collaborate more with game designers.&lt;/p&gt;
&lt;p&gt;On a side note: IMHO science teams could be so much stronger if academia embraced more diverse function profiles. Why not employ dedicated communication specialists (YouTubers / content creators), research software engineers, or game developers in every team/group/department?*&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Imagination is a key driver of innovation and progress. Lifting the constraints of immediate feasibility inspires us to think big and let our creativity guide us. It helps to break away from doing more of the same and instead direct our research and energy towards an inspiring future.&lt;/p&gt;
&lt;p&gt;Participating in the Destination Earth challenge was a very enjoyable experience, and it would be great to see more such initiatives. In the meantime, I will be on the lookout for opportunities to help make Henry’s story come true.&lt;/p&gt;
&lt;p&gt;What do you think are the biggest challenges in realizing these urban sims? What would you add, or change, and what opportunities did I miss? Perhaps we can start shaping our future together!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/henry-the-city-tweaker-19e1aa94.DzQkJD1P.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Brainstorming on the success of a research software catalogue</title><link>https://blog.esciencecenter.nl/posts/2024-06-12---brainstorming-on-the-success-of-a-research-software-catalogu</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-06-12---brainstorming-on-the-success-of-a-research-software-catalogu</guid><description>&lt;h1 id=&quot;brainstorming-on-the-success-of-a-research-software-catalogue&quot;&gt;&lt;em&gt;Brainstorming on the success of a research software catalogue&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;Researchers reflect on the whys and hows of scientific software catalogues&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Brainstorming on the success of a research software catalogue&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;667&quot; height=&quot;673&quot; src=&quot;https://blog.esciencecenter.nl/_astro/brainstorming-on-the-success-of-a-resear-903a3824.c8S2nIoj_2aoPJu.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Created with DALL-E. Timestamp: 2024–04–23 14.57.58 Prompt: Create an image that conveys the concept of a digital software repository in a minimalistic and modern academic style.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;This blog entry was born during the unconference session on software catalogues that took place during the &lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day 2024&lt;/a&gt; in Hilversum, the Netherlands.&lt;/p&gt;
&lt;p&gt;The session was chaired by &lt;a href=&quot;https://www.uu.nl/medewerkers/MvanStiphout&quot;&gt;Mees van Stiphout&lt;/a&gt;. The piece was co-authored by &lt;a href=&quot;https://www.linkedin.com/in/pedrohserrano/&quot;&gt;Pedro Hernández Serrano&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/irenemartorelli/&quot;&gt;Irene Martorelli&lt;/a&gt;, Belén Torrente, Emma Daniëls, and &lt;a href=&quot;https://orcid.org/0009-0002-9622-6663&quot;&gt;Sreeparna Deb&lt;/a&gt;. It was reviewed and edited by &lt;a href=&quot;https://pabrod.github.io&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Software catalogues have become increasingly important for research software in modern-day academia. They are helpful for searching and finding research software; they guarantee that research software is accessible, has markers of quality, and is actively maintained. In this unconference conversation, we discussed what can make a software catalogue useful for users, developers, and the research community.&lt;/p&gt;
&lt;h2 id=&quot;software-catalogues&quot;&gt;Software catalogues&lt;/h2&gt;
&lt;p&gt;A software catalogue acts as a digital hub where research software is deposited or published, often linking to software stored on other servers. These catalogues are commonly referred to as directories, catalogues, registries, or platforms. The core aim of such catalogues is to make software readily available and useful for its intended research purposes. Popular examples are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://r-universe.dev/&quot;&gt;https://r-universe.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://research-software-directory.org/&quot;&gt;https://research-software-directory.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zenodo.org/&quot;&gt;https://zenodo.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Easy access to the software is crucial. Effective catalogues ensure that their contents are easily searchable both through their own interfaces and via external search engines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;number of downloads&lt;/li&gt;
&lt;li&gt;date of last release&lt;/li&gt;
&lt;li&gt;size of the project&lt;/li&gt;
&lt;li&gt;reproducible build&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, robust metadata practices are essential.&lt;/p&gt;
&lt;p&gt;Beyond the technical aspects, the human element is also vital. Successful catalogues are supported by invested communities. These communities can offer support, facilitate collaboration, and even drive the software’s ongoing development. Additionally, providing clear documentation and accessible APIs helps users understand and interact with the catalogue more effectively, promoting better usage and integration of the software.&lt;/p&gt;
&lt;p&gt;Helping a community develop around a platform or catalogue is no trivial task: after achieving content ‘critical mass’, we need to do a lot of outreach to different parts of the research community just to make users and contributors aware of the catalogue.&lt;/p&gt;
&lt;p&gt;Some catalogues also integrate services such as rendering documentation, showing the maintenance status of the software, and checking reproducibility of builds by building the package within the platform. These services not only add value but also reassure users about the reliability and active development of the tools available.&lt;/p&gt;
&lt;p&gt;A catalogue must be clear about its purpose. Whether it aims to promote software, to serve as a portfolio, or to fulfill other objectives, this clarity helps shape the user experience and guide the catalogue’s strategic development.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;A software catalogue is about building an accessible, reliable, and community-supported platform that fosters reuse of software and reproduction of methods in the research software landscape. By focusing on content quality, ease of access, ease of use, and community engagement, catalogues can greatly enhance their utility and impact. These elements combine to not only preserve and share valuable software but also to stimulate ongoing improvement and discovery of research software. Through such catalogues, the future of research software is not just preserved; it is actively nurtured and expanded.&lt;/p&gt;</description><pubDate>Wed, 12 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;brainstorming-on-the-success-of-a-research-software-catalogue&quot;&gt;&lt;em&gt;Brainstorming on the success of a research software catalogue&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;Researchers reflect on the whys and hows of scientific software catalogues&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Brainstorming on the success of a research software catalogue&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;667&quot; height=&quot;673&quot; src=&quot;https://blog.esciencecenter.nl/_astro/brainstorming-on-the-success-of-a-resear-903a3824.c8S2nIoj_2aoPJu.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Created with DALL-E. Timestamp: 2024–04–23 14.57.58 Prompt: Create an image that conveys the concept of a digital software repository in a minimalistic and modern academic style.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;This blog entry was born during the unconference session on software catalogues that took place during the &lt;a href=&quot;https://www.esciencecenter.nl/news/national-research-software-day-recap/&quot;&gt;National Research Software Day 2024&lt;/a&gt; in Hilversum, the Netherlands.&lt;/p&gt;
&lt;p&gt;The session was chaired by &lt;a href=&quot;https://www.uu.nl/medewerkers/MvanStiphout&quot;&gt;Mees van Stiphout&lt;/a&gt;. The piece was co-authored by &lt;a href=&quot;https://www.linkedin.com/in/pedrohserrano/&quot;&gt;Pedro Hernández Serrano&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/irenemartorelli/&quot;&gt;Irene Martorelli&lt;/a&gt;, Belén Torrente, Emma Daniëls, and &lt;a href=&quot;https://orcid.org/0009-0002-9622-6663&quot;&gt;Sreeparna Deb&lt;/a&gt;. It was reviewed and edited by &lt;a href=&quot;https://pabrod.github.io&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Software catalogues have become increasingly important for research software in modern-day academia. They are helpful for searching and finding research software; they guarantee that research software is accessible, has markers of quality, and is actively maintained. In this unconference conversation, we discussed what can make a software catalogue useful for users, developers, and the research community.&lt;/p&gt;
&lt;h2 id=&quot;software-catalogues&quot;&gt;Software catalogues&lt;/h2&gt;
&lt;p&gt;A software catalogue acts as a digital hub where research software is deposited or published, often linking to software stored on other servers. These catalogues are commonly referred to as directories, catalogues, registries, or platforms. The core aim of such catalogues is to make software readily available and useful for its intended research purposes. Popular examples are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://r-universe.dev/&quot;&gt;https://r-universe.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://research-software-directory.org/&quot;&gt;https://research-software-directory.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zenodo.org/&quot;&gt;https://zenodo.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Easy access to the software is crucial. Effective catalogues ensure that their contents are easily searchable both through their own interfaces and via external search engines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;number of downloads&lt;/li&gt;
&lt;li&gt;date of last release&lt;/li&gt;
&lt;li&gt;size of the project&lt;/li&gt;
&lt;li&gt;reproducible build&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, robust metadata practices are essential.&lt;/p&gt;
&lt;p&gt;Beyond the technical aspects, the human element is also vital. Successful catalogues are supported by invested communities. These communities can offer support, facilitate collaboration, and even drive the software’s ongoing development. Additionally, providing clear documentation and accessible APIs helps users understand and interact with the catalogue more effectively, promoting better usage and integration of the software.&lt;/p&gt;
&lt;p&gt;Helping a community develop around a platform or catalogue is no trivial task: after achieving content ‘critical mass’, we need to do a lot of outreach to different parts of the research community just to make users and contributors aware of the catalogue.&lt;/p&gt;
&lt;p&gt;Some catalogues also integrate services such as rendering documentation, showing the maintenance status of the software, and checking reproducibility of builds by building the package within the platform. These services not only add value but also reassure users about the reliability and active development of the tools available.&lt;/p&gt;
&lt;p&gt;A catalogue must be clear about its purpose. Whether it aims to promote software, to serve as a portfolio, or to fulfill other objectives, this clarity helps shape the user experience and guide the catalogue’s strategic development.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;A software catalogue is about building an accessible, reliable, and community-supported platform that fosters reuse of software and reproduction of methods in the research software landscape. By focusing on content quality, ease of access, ease of use, and community engagement, catalogues can greatly enhance their utility and impact. These elements combine to not only preserve and share valuable software but also to stimulate ongoing improvement and discovery of research software. Through such catalogues, the future of research software is not just preserved; it is actively nurtured and expanded.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/brainstorming-on-the-success-of-a-resear-903a3824.c8S2nIoj.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>A Tale of Tallness</title><link>https://blog.esciencecenter.nl/posts/2024-05-28---a-tale-of-tallness</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-05-28---a-tale-of-tallness</guid><description>&lt;p&gt;In the past two centuries, the Dutch have become the tallest people of the planet. What factors caused this remarkable development? This is the central research question in the work of &lt;a href=&quot;https://www.ru.nl/en/people/quanjer-b&quot;&gt;Björn Quanjer&lt;/a&gt; of Radboud University of Nijmegen. In May 2024, he completed a comprehensive study involving data of thousands of subjects covering the period 1850–1950.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-f4a1acee.DFAx4dw3_22KOdk.webp&quot; srcset=&quot;&quot;&gt;
Björn Quanjer (right) defending his PhD thesis in Nijmegen on Wednesday 1 May 2024. The presented slide shows the researcher superimposed on a picture next to his grandfather (right) to indicate the gain of the heights of Dutch men in the past century&lt;/p&gt;
&lt;h2 id=&quot;phd-defense&quot;&gt;Phd defense&lt;/h2&gt;
&lt;p&gt;Björn Quanjer is a member of the project &lt;a href=&quot;https://research-software-directory.org/projects/ree-hdsc&quot;&gt;REE-HDSC&lt;/a&gt;, Recognizing Extracted Entities for the Historical Database Suriname Curaçao, a collaboration between the Netherlands eScience Center and Radboud University Nijmegen. On Wednesday 1 May 2024, he successfully defended his PhD thesis &lt;a href=&quot;https://www.ru.nl/en/research/research-news/what-height-says-about-the-development-of-our-prosperity-and-health&quot;&gt;The Tale of Tallness&lt;/a&gt;, receiving the distinction cum laude. It was the first time since 1987 that this distinction had been awarded to a researcher in his field in Nijmegen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;401&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-8b19776a.D4xmXyC6_ZHuKjy.webp&quot; srcset=&quot;&quot;&gt;
Average height of Dutch males at conscription (blue line) and at adult age (black line) for birth years between 1815 and 1955 (Figure 1.3 of Björn Quanjer’s thesis, reused with permission)&lt;/p&gt;
&lt;h2 id=&quot;data&quot;&gt;Data&lt;/h2&gt;
&lt;p&gt;Quanjer’s study uses the &lt;a href=&quot;https://iisg.amsterdam/en/hsn/data&quot;&gt;Historical Sample of The Netherlands&lt;/a&gt;, a dataset which contains life courses for a sample of about 0.5% of the Dutch population born between 1850 and 1922. The life courses are based on birth, marriage and death certificates from the Dutch civil registry. They also include military conscription records from the provincial archives, which are central to this study. At the time, all young Dutch men were checked for military service, so their height was registered in these records. Because women were exempt from military service, the study is restricted to the height developments of Dutch men.&lt;/p&gt;
&lt;p&gt;The study deals with several data challenges. For example, did the lower participation of the elite in the conscription have an effect on the measured heights? Quanjer shows with statistical tests that the effect was small. Furthermore, how can we model the effect of childhood illness on height without data on illness? Quanjer models illness by death: if the people around a Dutch person die (parents, siblings, neighbors), the chance that the person has experienced severe health problems is higher.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-4b69176a.nFfpilSW_Zoi6Ho.webp&quot; srcset=&quot;&quot;&gt;
Relation between birth order and average conscription height of Dutch males (blue line): boys born later in large families are taller than their older brothers (Figure 3.4 of Björn Quanjer’s thesis, reused with permission)&lt;/p&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;Quanjer’s study provides several interesting observations. Losing a mother at the age of 5–12 proved to have a negative effect on conscription height compared with siblings that lost their mothers on a different age. However losing a father at that age had an opposite effect: these children were taller at conscription. Growing up in a family with many children can have a negative effect on height (fewer resources per child) but you have to consider that the older children can contribute to the family income. For this reason the younger children of large families were taller at conscription than their older siblings.&lt;/p&gt;
&lt;h2 id=&quot;current-developments&quot;&gt;Current developments&lt;/h2&gt;
&lt;p&gt;Unlike other studies on height development, Quanjer investigates several variables that could have an effect on heights: genetics, nutrition, health, family size, mortality, wealth and life events. An interesting open question that he addresses in his final chapter, is whether historical heights can be used as a proxy for any of these variables. Given the correlation between health, wealth and height, we should be concerned about the recent stagnation in the rise of heights of the Dutch. Quanjer names the current rise of obesity and purchase inequality as possible causes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Björn Quanjer, &lt;a href=&quot;https://repository.ubn.ru.nl/handle/2066/300359&quot;&gt;A Tale Of Tallness. A household perspective on early life determinants of male height within the Netherlands between 1850 and 1950&lt;/a&gt;. PhD thesis, Radboud University Nijmegen, 2024.&lt;/p&gt;
&lt;p&gt;Björn Quanjer, &lt;a href=&quot;https://www.nporadio1.nl/fragmenten/nieuwsweekend/9c0422d1-7fa4-45b5-9729-ff9b5d8d4378/2024-05-11-hoe-welvarender-het-land-hoe-langer-zijn-inwoners&quot;&gt;Hoe welvarender het land, hoe langer zijn inwoners&lt;/a&gt;. Interview Nieuwsweekend, Omroep MAX, Radio 1, 11 May 2024 09:50 (in Dutch).&lt;/p&gt;</description><pubDate>Tue, 28 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the past two centuries, the Dutch have become the tallest people of the planet. What factors caused this remarkable development? This is the central research question in the work of &lt;a href=&quot;https://www.ru.nl/en/people/quanjer-b&quot;&gt;Björn Quanjer&lt;/a&gt; of Radboud University of Nijmegen. In May 2024, he completed a comprehensive study involving data of thousands of subjects covering the period 1850–1950.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-f4a1acee.DFAx4dw3_22KOdk.webp&quot; srcset=&quot;&quot;&gt;
Björn Quanjer (right) defending his PhD thesis in Nijmegen on Wednesday 1 May 2024. The presented slide shows the researcher superimposed on a picture next to his grandfather (right) to indicate the gain of the heights of Dutch men in the past century&lt;/p&gt;
&lt;h2 id=&quot;phd-defense&quot;&gt;Phd defense&lt;/h2&gt;
&lt;p&gt;Björn Quanjer is a member of the project &lt;a href=&quot;https://research-software-directory.org/projects/ree-hdsc&quot;&gt;REE-HDSC&lt;/a&gt;, Recognizing Extracted Entities for the Historical Database Suriname Curaçao, a collaboration between the Netherlands eScience Center and Radboud University Nijmegen. On Wednesday 1 May 2024, he successfully defended his PhD thesis &lt;a href=&quot;https://www.ru.nl/en/research/research-news/what-height-says-about-the-development-of-our-prosperity-and-health&quot;&gt;The Tale of Tallness&lt;/a&gt;, receiving the distinction cum laude. It was the first time since 1987 that this distinction had been awarded to a researcher in his field in Nijmegen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;401&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-8b19776a.D4xmXyC6_ZHuKjy.webp&quot; srcset=&quot;&quot;&gt;
Average height of Dutch males at conscription (blue line) and at adult age (black line) for birth years between 1815 and 1955 (Figure 1.3 of Björn Quanjer’s thesis, reused with permission)&lt;/p&gt;
&lt;h2 id=&quot;data&quot;&gt;Data&lt;/h2&gt;
&lt;p&gt;Quanjer’s study uses the &lt;a href=&quot;https://iisg.amsterdam/en/hsn/data&quot;&gt;Historical Sample of The Netherlands&lt;/a&gt;, a dataset which contains life courses for a sample of about 0.5% of the Dutch population born between 1850 and 1922. The life courses are based on birth, marriage and death certificates from the Dutch civil registry. They also include military conscription records from the provincial archives, which are central to this study. At the time, all young Dutch men were checked for military service, so their height was registered in these records. Because women were exempt from military service, the study is restricted to the height developments of Dutch men.&lt;/p&gt;
&lt;p&gt;The study deals with several data challenges. For example, did the lower participation of the elite in the conscription have an effect on the measured heights? Quanjer shows with statistical tests that the effect was small. Furthermore, how can we model the effect of childhood illness on height without data on illness? Quanjer models illness by death: if the people around a Dutch person die (parents, siblings, neighbors), the chance that the person has experienced severe health problems is higher.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Tale of Tallness&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-4b69176a.nFfpilSW_Zoi6Ho.webp&quot; srcset=&quot;&quot;&gt;
Relation between birth order and average conscription height of Dutch males (blue line): boys born later in large families are taller than their older brothers (Figure 3.4 of Björn Quanjer’s thesis, reused with permission)&lt;/p&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;Quanjer’s study provides several interesting observations. Losing a mother at the age of 5–12 proved to have a negative effect on conscription height compared with siblings that lost their mothers on a different age. However losing a father at that age had an opposite effect: these children were taller at conscription. Growing up in a family with many children can have a negative effect on height (fewer resources per child) but you have to consider that the older children can contribute to the family income. For this reason the younger children of large families were taller at conscription than their older siblings.&lt;/p&gt;
&lt;h2 id=&quot;current-developments&quot;&gt;Current developments&lt;/h2&gt;
&lt;p&gt;Unlike other studies on height development, Quanjer investigates several variables that could have an effect on heights: genetics, nutrition, health, family size, mortality, wealth and life events. An interesting open question that he addresses in his final chapter, is whether historical heights can be used as a proxy for any of these variables. Given the correlation between health, wealth and height, we should be concerned about the recent stagnation in the rise of heights of the Dutch. Quanjer names the current rise of obesity and purchase inequality as possible causes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Björn Quanjer, &lt;a href=&quot;https://repository.ubn.ru.nl/handle/2066/300359&quot;&gt;A Tale Of Tallness. A household perspective on early life determinants of male height within the Netherlands between 1850 and 1950&lt;/a&gt;. PhD thesis, Radboud University Nijmegen, 2024.&lt;/p&gt;
&lt;p&gt;Björn Quanjer, &lt;a href=&quot;https://www.nporadio1.nl/fragmenten/nieuwsweekend/9c0422d1-7fa4-45b5-9729-ff9b5d8d4378/2024-05-11-hoe-welvarender-het-land-hoe-langer-zijn-inwoners&quot;&gt;Hoe welvarender het land, hoe langer zijn inwoners&lt;/a&gt;. Interview Nieuwsweekend, Omroep MAX, Radio 1, 11 May 2024 09:50 (in Dutch).&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-tale-of-tallness-f4a1acee.DFAx4dw3.jpeg" medium="image"/><author>Erik Tjong Kim Sang</author></item><item><title>Python’s timeit: Find the fastest code in no time</title><link>https://blog.esciencecenter.nl/posts/2024-05-14---pythons-timeit-find-the-fastest-code-in-no-time</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-05-14---pythons-timeit-find-the-fastest-code-in-no-time</guid><description>&lt;p&gt;&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--d3174fda.CiHIKL9q_Z1Xafa3.webp&quot; srcset=&quot;&quot;&gt;
Trains are fast, and your code should be too. Or is it the other way around? — Photo by &lt;a href=&quot;https://unsplash.com/@lum3n?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;LUM3N&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Every programmer wants their programs to run a little faster. While optimizing your whole code to run faster can take a lot of effort, an easy way to gain some speed is to choose the fastest implementation. Which of Python’s options &lt;em&gt;is&lt;/em&gt; the fastest is not always clear though, so wouldn’t it be nice to have a tool to quickly compare the speed of different implementation choices?&lt;/p&gt;
&lt;p&gt;In this post, I will give a short introduction to Python’s built-in &lt;code&gt;[timeit ](https://docs.python.org/3/library/timeit.html)&lt;/code&gt;module, and go over the three main ways to use it to time small snippets of Python code.&lt;/p&gt;
&lt;h2 id=&quot;timey-wimey-python-timeit&quot;&gt;Timey Wimey Python: timeit&lt;/h2&gt;
&lt;p&gt;What is Python’s &lt;code&gt;timeit&lt;/code&gt; module?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This module provides a simple way to time small bits of Python code.
It has both a Command-Line Interface as well as a callable one. It
avoids a number of common traps for measuring execution times.&lt;/p&gt;
&lt;p&gt;— timeit documentation&lt;/p&gt;
&lt;p&gt;In contrast to profiling the runtime of your entire program, the &lt;code&gt;timeit&lt;/code&gt; module is best suited to time small snippets. We can divide these comparisons into three classes, as illustrated by the examples I will use throughout this blog post.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standalone one-liners, such as:&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;join-on-a-list-comprehension&quot;&gt;join on a list comprehension&lt;/h1&gt;
&lt;p&gt;”,“.join([str(n) for n in range(100)])&lt;/p&gt;
&lt;h1 id=&quot;join-on-a-generator-expression&quot;&gt;join on a generator expression&lt;/h1&gt;
&lt;p&gt;”,“.join(str(n) for n in range(100))&lt;/p&gt;
&lt;h1 id=&quot;join-on-the-map-function&quot;&gt;join on the &lt;code&gt;map&lt;/code&gt; function&lt;/h1&gt;
&lt;p&gt;”,“.join(map(str, range(100)))2. Standalone multi-liners, such as:&lt;/p&gt;
&lt;h1 id=&quot;append&quot;&gt;append&lt;/h1&gt;
&lt;p&gt;x = []
for i in range(1000):
x.append(i)&lt;/p&gt;
&lt;h1 id=&quot;list-addition&quot;&gt;list addition&lt;/h1&gt;
&lt;p&gt;x = []
for i in range(1000):
x += [i]&lt;em&gt;(ignoring the faster list-comprehension alternative &lt;em&gt;&lt;code&gt;*[i for i in range(100)]*&lt;/code&gt;&lt;/em&gt; for the sake of example)&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Any snippets with some setup required:&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;setup&quot;&gt;setup&lt;/h1&gt;
&lt;p&gt;text = “sample string”
char = “g”&lt;/p&gt;
&lt;h1 id=&quot;in-operator&quot;&gt;in-operator&lt;/h1&gt;
&lt;p&gt;char in text&lt;/p&gt;
&lt;h1 id=&quot;find-method&quot;&gt;find-method&lt;/h1&gt;
&lt;p&gt;text.find(char)
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;454&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--070a66dd.CwXeKfoS_Z17mYKq.webp&quot; srcset=&quot;&quot;&gt;
Calculating with time — Photo by &lt;a href=&quot;https://unsplash.com/@takeshi2?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;wu yi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-a-script-import-timeit&quot;&gt;In a script: import timeit&lt;/h2&gt;
&lt;p&gt;As &lt;code&gt;timeit&lt;/code&gt; is a Python module, you can import it and write Python scripts for your tests. This method is the most self-documenting and repeatable way of writing your timing experiments and makes it easy to store the results for further processing.&lt;/p&gt;
&lt;p&gt;The first way you might implement this is to directly use the &lt;code&gt;timeit&lt;/code&gt; function from the module:&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; import timeit
&gt;&gt;&gt; timeit.timeit()  # default arguments: timeit(stmt=‘pass’, number=1_000_000)
0.01063702700776048By running &lt;code&gt;timeit()&lt;/code&gt; without any further arguments, we execute the default statement &lt;code&gt;stmt=&apos;pass&apos;&lt;/code&gt; a million times, showing the minimal overhead of Python’s &lt;code&gt;pass&lt;/code&gt; statement.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;stmt&lt;/code&gt; can either be a string or a so-called &lt;em&gt;callable&lt;/em&gt;, i.e., a function. For clarity and brevity, I’ll keep using strings for now.&lt;/p&gt;
&lt;p&gt;The major drawback of this method is that you have to guess the number of times to run your snippet up front. If you guess too low the results won’t be reliable, but if you guess too high it might take minutes or hours, defeating the point of a quick test.&lt;/p&gt;
&lt;p&gt;Luckily, there is a better way: You can create a &lt;code&gt;Timer&lt;/code&gt; for your snippet, and call the &lt;code&gt;autorange&lt;/code&gt; method to automatically try increasing numbers until the time taken is at least 0.2 seconds. It returns the number of repetitions reached, and the total time taken, so you can easily calculate the time per iteration.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; import timeit
&gt;&gt;&gt; timeit.Timer().autorange()  # default arguments: Timer(stmt=‘pass’)
(50000000, 0.2607337789959274)&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners&quot;&gt;Standalone one-liners**&lt;/h3&gt;
&lt;p&gt;Let’s start by comparing the simple one-liners. We give the statement we want to time as a string and specify a custom number of iterations. Note that when your statement already deals with double-quoted strings, the whole string should be given single-quoted, or vice-versa.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer**&gt;&gt;&gt; Timer(’”, “.join([str(n) for n in range(100)])‘).autorange()
(50000, 0.3393513219925808)
&gt;&gt;&gt; Timer(’”, “.join(str(n) for n in range(100))‘).autorange()
(50000, 0.38378613100212533)
&gt;&gt;&gt; Timer(’”, “.join(map(str, range(100)))‘).autorange()
(50000, 0.48742324599879794)From the reported number of repetitions and returned time in seconds, we can calculate that each of these lines took 6.79**, **7.67, **and &lt;strong&gt;9.75&lt;/strong&gt; microseconds to execute respectively.&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners&quot;&gt;&lt;strong&gt;Standalone multi-liners&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes the snippet you want to test will consist of multiple statements. Python allows you to put multiple statements on a single line with a semicolon &lt;code&gt;x = 1; y = 2&lt;/code&gt;. Then you can just run your test as explained above for the standalone one-liners. This does not work for snippets with indented code like &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;for&lt;/code&gt; though.&lt;/p&gt;
&lt;p&gt;To time these snippets that &lt;em&gt;have&lt;/em&gt; to span multiple lines, you can give &lt;code&gt;Timer()&lt;/code&gt; a multi-line string as argument. The beautiful and Pythonic way to do this is using Python’s multi-line strings. (The non-Pythonic way is to add &lt;code&gt;\n&lt;/code&gt; characters in your regular strings.)&lt;/p&gt;
&lt;p&gt;These multi-line cases are where it becomes more practical to pass a callable than to re-type your code as a string:&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer**&gt;&gt;&gt; Timer(&apos;&apos;&apos;x = []
… for i in range(1000):
…     x.append(i)&apos;&apos;&apos;).autorange()
(20000, 0.34225083301134873)
&gt;&gt;&gt; def add_test():
…     x = []
…     for i in range(1000):
…         x += [i]
&gt;&gt;&gt; Timer(append_test).autorange()
(5000, 0.2470278069959022)&lt;/p&gt;
&lt;h3 id=&quot;setup-required&quot;&gt;Setup required**&lt;/h3&gt;
&lt;p&gt;If there is some setup that only has to be run once, including it in a multi-line snippet means it’s executed at every iteration. Then you’d be measuring something you don’t want to measure! Instead, you can pass this setup statement as a separate argument &lt;code&gt;setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer
&gt;&gt;&gt; Timer(
…     setup=‘text = “sample string”; char = “g”’,
…     stmt=‘char in text’,
… ).autorange()
(20000000, 0.3793242520041531)
&gt;&gt;&gt; Timer(
…     ‘text.find(char)’,
…     ‘text = “sample string”; char = “g”’
… ).autorange()
(5000000, 0.36903892100963276)
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;298&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--404fd5ff.D2p9y8gP_qgspF.webp&quot; srcset=&quot;&quot;&gt;
Time still flies if you’re having fun in the terminal — render by &lt;a href=&quot;https://github.com/tenox7/aclock&quot;&gt;aclock&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;command-line-python--m-timeit&quot;&gt;Command Line: python -m timeit&lt;/h2&gt;
&lt;p&gt;Python’s &lt;code&gt;timeit&lt;/code&gt; module can also be run as a command line tool.&lt;/p&gt;
&lt;p&gt;$ python -m timeit -n 10000 ‘pass’
10000 loops, best of 3: 0.0109 usec per loopThe usage is similar to the imported &lt;code&gt;timeit&lt;/code&gt; function as shown in the previous section. The &lt;code&gt;-n&lt;/code&gt; option is optional though, and the same &lt;code&gt;autorange&lt;/code&gt; behavior will be used if it’s not given. It also reports the actual time per iteration, instead of having to calculate that yourself. This is reported in &lt;code&gt;nsec&lt;/code&gt;, &lt;code&gt;usec&lt;/code&gt;, &lt;code&gt;msec&lt;/code&gt; or &lt;code&gt;sec&lt;/code&gt;, for nano-, micro-, mili- and whole seconds respectively. Note also that it reports ‘best of 5’: it’s repeated the &lt;code&gt;autorange&lt;/code&gt; timing five times, and reports the minimum.&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘pass’
50000000 loops, best of 5: 5.21 nsec per loop&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners-1&quot;&gt;Standalone one-liners&lt;/h3&gt;
&lt;p&gt;Testing one-liners with the command line is as easy as replacing &lt;code&gt;pass&lt;/code&gt; from the introduction with the code you want to test, and the &lt;code&gt;timeit&lt;/code&gt; tool will automatically report the time in a nice human-readable format.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;100&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;mn&gt;50000&lt;/mn&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mn&gt;6.66&lt;/mn&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;python -m timeit &apos;&quot;, &quot;.join([str(n) for n in range(100)])&apos;
50000 loops, best of 5: 6.66 usec per loop&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0019em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nin&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50000&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;6.66&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; python -m timeit ’”, “.join(str(n) for n in range(100))’
50000 loops, best of 5: 7.62 usec per loop
$ python -m timeit ’”, “.join(map(str, range(100)))’
50000 loops, best of 5: 9.31 usec per loop&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners-1&quot;&gt;Standalone multi-liners&lt;/h3&gt;
&lt;p&gt;As before, the simplest way to test a snippet of multiple lines is to join the statements with a semicolon if no indentation is required. When indentation is required, the other option is to pass multiple strings as arguments to the command. Note that you still have to add the indentation properly yourself! This can get tricky to count if your indentation is more than a single level deep, but is usually not too hard.&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘x = []’ ‘for i in range(1000):’ ’    x.append(i)’
20000 loops, best of 5: 17.1 usec per loop&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘x = []’ ‘for i in range(1000):’ ’    x += [i]’
5000 loops, best of 5: 48.4 usec per loop&lt;/p&gt;
&lt;h3 id=&quot;setup-required-1&quot;&gt;Setup required&lt;/h3&gt;
&lt;p&gt;To add some initial setup such as imports or variable declarations, we can use the &lt;code&gt;-s&lt;/code&gt; option:&lt;/p&gt;
&lt;p&gt;$ python -m timeit -s ‘pass’ ‘pass’
50000000 loops, best of 5: 5.21 nsec per loopThe setup &lt;em&gt;does&lt;/em&gt; come before the statement to test in this case, so that makes it a bit more intuitive to read.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Double superscript at position 58: …&amp;#x22;; char = &amp;#x22;g&amp;#x22;&amp;#x27; &amp;#x27;̲char in text&amp;#x27;
2…&quot; style=&quot;color:#cc0000&quot;&gt;python -m timeit -s &apos;text = &quot;sample string&quot;; char = &quot;g&quot;&apos; &apos;char in text&apos;
20000000 loops, best of 5: 19 nsec per loop&lt;/span&gt; python -m timeit -s ‘text = “sample string”; char = “g”’ ‘text.find(char)’
5000000 loops, best of 5: 69.3 nsec per loop
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;420&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--4c2edcf2.SpWYA1fW_Z2n9UTg.webp&quot; srcset=&quot;&quot;&gt;
Timing can be an important part of your notebook toolkit&lt;/p&gt;
&lt;h2 id=&quot;ipythonjupyter-magics-timeit&quot;&gt;IPython/Jupyter magics: %timeit&lt;/h2&gt;
&lt;p&gt;When working in the &lt;a href=&quot;https://pypi.org/project/ipython&quot;&gt;IPython&lt;/a&gt; interactive shell, or in a &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebook &lt;/a&gt;with a Python kernel, you have access to the so-called &lt;a href=&quot;https://ipython.readthedocs.io/en/stable/interactive/magics.html&quot;&gt;‘magic commands’&lt;/a&gt;. For timeit, there is the &lt;code&gt;[%timeit](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit)&lt;/code&gt; magic¹. It simply passes the code you type after it to (a version of) &lt;code&gt;timeit.Timer().autorange()&lt;/code&gt;! Like magic!&lt;/p&gt;
&lt;p&gt;One small caveat is that the outcome is reported as a mean +/- standard deviation of multiple repetitions, while the original Python documentation suggests always using the minimum.&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners-2&quot;&gt;Standalone one-liners&lt;/h3&gt;
&lt;p&gt;For simple one-liners, just type the code as you would normally, and type &lt;code&gt;%timeit&lt;/code&gt; before it. That’s all!&lt;/p&gt;
&lt;p&gt;In [1]: %timeit ”, “.join([str(n) for n in range(100)])
6.92 µs ± 46.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %timeit ”, “.join(str(n) for n in range(100))
8.27 µs ± 1.15 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [3]: %timeit ”, “.join(map(str, range(100)))
10.9 µs ± 1.72 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners-2&quot;&gt;Standalone multi-liners&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;%timeit&lt;/code&gt; magic doesn’t quite work for multi-line snippets though. Why? Because magics with a &lt;em&gt;single&lt;/em&gt; &lt;code&gt;%&lt;/code&gt; are &lt;em&gt;line-magics&lt;/em&gt;. For &lt;em&gt;cell-magics&lt;/em&gt;, you just have to add another &lt;code&gt;%&lt;/code&gt; to make it &lt;code&gt;%%timeit&lt;/code&gt;. Then it will time all the code in your cell. No further difficulties whatsoever!&lt;/p&gt;
&lt;p&gt;In [1]: %%timeit
…: x = []
…: for i in range(1000):
…:     x.append(i)
…:
23.6 µs ± 3.37 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %%timeit
…: x = []
…: for i in range(1000):
…:     x += [i]
49 µs ± 385 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)A word of warning: any code on the same line as &lt;code&gt;%%timeit&lt;/code&gt; will be used as setup and only be run once. I think it’s too easy to make mistakes with this, so I’d avoid this feature. Compare:&lt;/p&gt;
&lt;p&gt;In [1]: %%timeit y = [x for x in range(1_000_000)]  # setup is not timed
…: len(y)
…:
…:
21.7 ns ± 0.297 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %%timeit
…: y = [x for x in range(1_000_000)]  # this line is now being timed
…: len(y)
…:
…:
22.9 ms ± 35.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)&lt;/p&gt;
&lt;h3 id=&quot;setup-required-2&quot;&gt;Setup required&lt;/h3&gt;
&lt;p&gt;Now you might be thinking &lt;em&gt;“but then where do I put my setup command for either &lt;em&gt;&lt;code&gt;*%timeit*&lt;/code&gt;&lt;/em&gt; or &lt;em&gt;&lt;code&gt;*%%timeit*&lt;/code&gt;&lt;/em&gt;?”&lt;/em&gt; The answer: you can run it in some previous cell! As IPython/Jupyter already takes care of passing your code on to the &lt;code&gt;timeit&lt;/code&gt; module properly, it also automatically passes along all current global variables. So we can simply first run a cell with our setup:&lt;/p&gt;
&lt;p&gt;In [1]: text = “sample string”
In [2]: char = “g”And use the simple &lt;code&gt;%timeit&lt;/code&gt; magic to time the code we are actually interested in, without specifying which setup is associated with it.&lt;/p&gt;
&lt;p&gt;In [3]: %timeit char in text
22 ns ± 0.267 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;p&gt;In [4]: %timeit text.find(char)
72.3 ns ± 0.811 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I hope to have shown how you can easily use Python’s &lt;code&gt;timeit&lt;/code&gt; module to measure the execution times of your snippets, whether for fun or profit. Although each has its pros and cons (see below), I personally recommend using IPython/Jupyter’s &lt;code&gt;(%)%timeit&lt;/code&gt; magics as they are the most intuitive to use: just write the code as you would normally with the &lt;code&gt;(%)%timeit&lt;/code&gt; magic in front or above.&lt;/p&gt;
&lt;h2 id=&quot;pros-and-cons&quot;&gt;Pros and Cons&lt;/h2&gt;
&lt;h3 id=&quot;importing-timeit-module&quot;&gt;Importing &lt;code&gt;timeit&lt;/code&gt; module&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time taken can easily be used in further processing&lt;/strong&gt;+ &lt;strong&gt;Complete programmable flexibility&lt;/strong&gt;Cons:&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;**Takes more effort to use the &lt;code&gt;autorange&lt;/code&gt; feature&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cli-tool&quot;&gt;CLI Tool&lt;/h3&gt;
&lt;p&gt;**Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fast to use&lt;/strong&gt;+ &lt;strong&gt;Uses autorange by default&lt;/strong&gt;+ &lt;strong&gt;Nice and concise output&lt;/strong&gt;Cons:&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;**Requires a separate terminal window outside of your current Python work &amp;#x26; Results not easily reusable in a program&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ipythonjupyter-notebook-magics&quot;&gt;IPython/Jupyter Notebook Magics&lt;/h3&gt;
&lt;p&gt;**Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easiest to use&lt;/strong&gt;+ &lt;strong&gt;Uses autorange by default&lt;/strong&gt;+ &lt;strong&gt;Setup is taken from session context&lt;/strong&gt;Cons:
-** Needs IPython or Jupyter to be installed**- **Gives mean +/- standard deviation as result, while Python’s documentation suggests using the minimum&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;¹ as opposed to the &lt;code&gt;(%)%time&lt;/code&gt; magic, which tracks execution time of that line/cell being run just the once as-is.&lt;/p&gt;</description><pubDate>Tue, 14 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--d3174fda.CiHIKL9q_Z1Xafa3.webp&quot; srcset=&quot;&quot;&gt;
Trains are fast, and your code should be too. Or is it the other way around? — Photo by &lt;a href=&quot;https://unsplash.com/@lum3n?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;LUM3N&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Every programmer wants their programs to run a little faster. While optimizing your whole code to run faster can take a lot of effort, an easy way to gain some speed is to choose the fastest implementation. Which of Python’s options &lt;em&gt;is&lt;/em&gt; the fastest is not always clear though, so wouldn’t it be nice to have a tool to quickly compare the speed of different implementation choices?&lt;/p&gt;
&lt;p&gt;In this post, I will give a short introduction to Python’s built-in &lt;code&gt;[timeit ](https://docs.python.org/3/library/timeit.html)&lt;/code&gt;module, and go over the three main ways to use it to time small snippets of Python code.&lt;/p&gt;
&lt;h2 id=&quot;timey-wimey-python-timeit&quot;&gt;Timey Wimey Python: timeit&lt;/h2&gt;
&lt;p&gt;What is Python’s &lt;code&gt;timeit&lt;/code&gt; module?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This module provides a simple way to time small bits of Python code.
It has both a Command-Line Interface as well as a callable one. It
avoids a number of common traps for measuring execution times.&lt;/p&gt;
&lt;p&gt;— timeit documentation&lt;/p&gt;
&lt;p&gt;In contrast to profiling the runtime of your entire program, the &lt;code&gt;timeit&lt;/code&gt; module is best suited to time small snippets. We can divide these comparisons into three classes, as illustrated by the examples I will use throughout this blog post.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standalone one-liners, such as:&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;join-on-a-list-comprehension&quot;&gt;join on a list comprehension&lt;/h1&gt;
&lt;p&gt;”,“.join([str(n) for n in range(100)])&lt;/p&gt;
&lt;h1 id=&quot;join-on-a-generator-expression&quot;&gt;join on a generator expression&lt;/h1&gt;
&lt;p&gt;”,“.join(str(n) for n in range(100))&lt;/p&gt;
&lt;h1 id=&quot;join-on-the-map-function&quot;&gt;join on the &lt;code&gt;map&lt;/code&gt; function&lt;/h1&gt;
&lt;p&gt;”,“.join(map(str, range(100)))2. Standalone multi-liners, such as:&lt;/p&gt;
&lt;h1 id=&quot;append&quot;&gt;append&lt;/h1&gt;
&lt;p&gt;x = []
for i in range(1000):
x.append(i)&lt;/p&gt;
&lt;h1 id=&quot;list-addition&quot;&gt;list addition&lt;/h1&gt;
&lt;p&gt;x = []
for i in range(1000):
x += [i]&lt;em&gt;(ignoring the faster list-comprehension alternative &lt;em&gt;&lt;code&gt;*[i for i in range(100)]*&lt;/code&gt;&lt;/em&gt; for the sake of example)&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Any snippets with some setup required:&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;setup&quot;&gt;setup&lt;/h1&gt;
&lt;p&gt;text = “sample string”
char = “g”&lt;/p&gt;
&lt;h1 id=&quot;in-operator&quot;&gt;in-operator&lt;/h1&gt;
&lt;p&gt;char in text&lt;/p&gt;
&lt;h1 id=&quot;find-method&quot;&gt;find-method&lt;/h1&gt;
&lt;p&gt;text.find(char)
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;454&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--070a66dd.CwXeKfoS_Z17mYKq.webp&quot; srcset=&quot;&quot;&gt;
Calculating with time — Photo by &lt;a href=&quot;https://unsplash.com/@takeshi2?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;wu yi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-a-script-import-timeit&quot;&gt;In a script: import timeit&lt;/h2&gt;
&lt;p&gt;As &lt;code&gt;timeit&lt;/code&gt; is a Python module, you can import it and write Python scripts for your tests. This method is the most self-documenting and repeatable way of writing your timing experiments and makes it easy to store the results for further processing.&lt;/p&gt;
&lt;p&gt;The first way you might implement this is to directly use the &lt;code&gt;timeit&lt;/code&gt; function from the module:&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; import timeit
&gt;&gt;&gt; timeit.timeit()  # default arguments: timeit(stmt=‘pass’, number=1_000_000)
0.01063702700776048By running &lt;code&gt;timeit()&lt;/code&gt; without any further arguments, we execute the default statement &lt;code&gt;stmt=&apos;pass&apos;&lt;/code&gt; a million times, showing the minimal overhead of Python’s &lt;code&gt;pass&lt;/code&gt; statement.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;stmt&lt;/code&gt; can either be a string or a so-called &lt;em&gt;callable&lt;/em&gt;, i.e., a function. For clarity and brevity, I’ll keep using strings for now.&lt;/p&gt;
&lt;p&gt;The major drawback of this method is that you have to guess the number of times to run your snippet up front. If you guess too low the results won’t be reliable, but if you guess too high it might take minutes or hours, defeating the point of a quick test.&lt;/p&gt;
&lt;p&gt;Luckily, there is a better way: You can create a &lt;code&gt;Timer&lt;/code&gt; for your snippet, and call the &lt;code&gt;autorange&lt;/code&gt; method to automatically try increasing numbers until the time taken is at least 0.2 seconds. It returns the number of repetitions reached, and the total time taken, so you can easily calculate the time per iteration.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; import timeit
&gt;&gt;&gt; timeit.Timer().autorange()  # default arguments: Timer(stmt=‘pass’)
(50000000, 0.2607337789959274)&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners&quot;&gt;Standalone one-liners**&lt;/h3&gt;
&lt;p&gt;Let’s start by comparing the simple one-liners. We give the statement we want to time as a string and specify a custom number of iterations. Note that when your statement already deals with double-quoted strings, the whole string should be given single-quoted, or vice-versa.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer**&gt;&gt;&gt; Timer(’”, “.join([str(n) for n in range(100)])‘).autorange()
(50000, 0.3393513219925808)
&gt;&gt;&gt; Timer(’”, “.join(str(n) for n in range(100))‘).autorange()
(50000, 0.38378613100212533)
&gt;&gt;&gt; Timer(’”, “.join(map(str, range(100)))‘).autorange()
(50000, 0.48742324599879794)From the reported number of repetitions and returned time in seconds, we can calculate that each of these lines took 6.79**, **7.67, **and &lt;strong&gt;9.75&lt;/strong&gt; microseconds to execute respectively.&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners&quot;&gt;&lt;strong&gt;Standalone multi-liners&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes the snippet you want to test will consist of multiple statements. Python allows you to put multiple statements on a single line with a semicolon &lt;code&gt;x = 1; y = 2&lt;/code&gt;. Then you can just run your test as explained above for the standalone one-liners. This does not work for snippets with indented code like &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;for&lt;/code&gt; though.&lt;/p&gt;
&lt;p&gt;To time these snippets that &lt;em&gt;have&lt;/em&gt; to span multiple lines, you can give &lt;code&gt;Timer()&lt;/code&gt; a multi-line string as argument. The beautiful and Pythonic way to do this is using Python’s multi-line strings. (The non-Pythonic way is to add &lt;code&gt;\n&lt;/code&gt; characters in your regular strings.)&lt;/p&gt;
&lt;p&gt;These multi-line cases are where it becomes more practical to pass a callable than to re-type your code as a string:&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer**&gt;&gt;&gt; Timer(&apos;&apos;&apos;x = []
… for i in range(1000):
…     x.append(i)&apos;&apos;&apos;).autorange()
(20000, 0.34225083301134873)
&gt;&gt;&gt; def add_test():
…     x = []
…     for i in range(1000):
…         x += [i]
&gt;&gt;&gt; Timer(append_test).autorange()
(5000, 0.2470278069959022)&lt;/p&gt;
&lt;h3 id=&quot;setup-required&quot;&gt;Setup required**&lt;/h3&gt;
&lt;p&gt;If there is some setup that only has to be run once, including it in a multi-line snippet means it’s executed at every iteration. Then you’d be measuring something you don’t want to measure! Instead, you can pass this setup statement as a separate argument &lt;code&gt;setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&gt;&gt;&gt; from timeit import Timer
&gt;&gt;&gt; Timer(
…     setup=‘text = “sample string”; char = “g”’,
…     stmt=‘char in text’,
… ).autorange()
(20000000, 0.3793242520041531)
&gt;&gt;&gt; Timer(
…     ‘text.find(char)’,
…     ‘text = “sample string”; char = “g”’
… ).autorange()
(5000000, 0.36903892100963276)
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;298&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--404fd5ff.D2p9y8gP_qgspF.webp&quot; srcset=&quot;&quot;&gt;
Time still flies if you’re having fun in the terminal — render by &lt;a href=&quot;https://github.com/tenox7/aclock&quot;&gt;aclock&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;command-line-python--m-timeit&quot;&gt;Command Line: python -m timeit&lt;/h2&gt;
&lt;p&gt;Python’s &lt;code&gt;timeit&lt;/code&gt; module can also be run as a command line tool.&lt;/p&gt;
&lt;p&gt;$ python -m timeit -n 10000 ‘pass’
10000 loops, best of 3: 0.0109 usec per loopThe usage is similar to the imported &lt;code&gt;timeit&lt;/code&gt; function as shown in the previous section. The &lt;code&gt;-n&lt;/code&gt; option is optional though, and the same &lt;code&gt;autorange&lt;/code&gt; behavior will be used if it’s not given. It also reports the actual time per iteration, instead of having to calculate that yourself. This is reported in &lt;code&gt;nsec&lt;/code&gt;, &lt;code&gt;usec&lt;/code&gt;, &lt;code&gt;msec&lt;/code&gt; or &lt;code&gt;sec&lt;/code&gt;, for nano-, micro-, mili- and whole seconds respectively. Note also that it reports ‘best of 5’: it’s repeated the &lt;code&gt;autorange&lt;/code&gt; timing five times, and reports the minimum.&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘pass’
50000000 loops, best of 5: 5.21 nsec per loop&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners-1&quot;&gt;Standalone one-liners&lt;/h3&gt;
&lt;p&gt;Testing one-liners with the command line is as easy as replacing &lt;code&gt;pass&lt;/code&gt; from the introduction with the code you want to test, and the &lt;code&gt;timeit&lt;/code&gt; tool will automatically report the time in a nice human-readable format.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;&quot;&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;100&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;mn&gt;50000&lt;/mn&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mn&gt;6.66&lt;/mn&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;python -m timeit &apos;&quot;, &quot;.join([str(n) for n in range(100)])&apos;
50000 loops, best of 5: 6.66 usec per loop&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0019em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&quot;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nin&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50000&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;6.66&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; python -m timeit ’”, “.join(str(n) for n in range(100))’
50000 loops, best of 5: 7.62 usec per loop
$ python -m timeit ’”, “.join(map(str, range(100)))’
50000 loops, best of 5: 9.31 usec per loop&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners-1&quot;&gt;Standalone multi-liners&lt;/h3&gt;
&lt;p&gt;As before, the simplest way to test a snippet of multiple lines is to join the statements with a semicolon if no indentation is required. When indentation is required, the other option is to pass multiple strings as arguments to the command. Note that you still have to add the indentation properly yourself! This can get tricky to count if your indentation is more than a single level deep, but is usually not too hard.&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘x = []’ ‘for i in range(1000):’ ’    x.append(i)’
20000 loops, best of 5: 17.1 usec per loop&lt;/p&gt;
&lt;p&gt;$ python -m timeit ‘x = []’ ‘for i in range(1000):’ ’    x += [i]’
5000 loops, best of 5: 48.4 usec per loop&lt;/p&gt;
&lt;h3 id=&quot;setup-required-1&quot;&gt;Setup required&lt;/h3&gt;
&lt;p&gt;To add some initial setup such as imports or variable declarations, we can use the &lt;code&gt;-s&lt;/code&gt; option:&lt;/p&gt;
&lt;p&gt;$ python -m timeit -s ‘pass’ ‘pass’
50000000 loops, best of 5: 5.21 nsec per loopThe setup &lt;em&gt;does&lt;/em&gt; come before the statement to test in this case, so that makes it a bit more intuitive to read.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Double superscript at position 58: …&amp;#x22;; char = &amp;#x22;g&amp;#x22;&amp;#x27; &amp;#x27;̲char in text&amp;#x27;
2…&quot; style=&quot;color:#cc0000&quot;&gt;python -m timeit -s &apos;text = &quot;sample string&quot;; char = &quot;g&quot;&apos; &apos;char in text&apos;
20000000 loops, best of 5: 19 nsec per loop&lt;/span&gt; python -m timeit -s ‘text = “sample string”; char = “g”’ ‘text.find(char)’
5000000 loops, best of 5: 69.3 nsec per loop
&lt;img alt=&quot;Python’s timeit: Find the fastest code in no time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;420&quot; src=&quot;https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--4c2edcf2.SpWYA1fW_Z2n9UTg.webp&quot; srcset=&quot;&quot;&gt;
Timing can be an important part of your notebook toolkit&lt;/p&gt;
&lt;h2 id=&quot;ipythonjupyter-magics-timeit&quot;&gt;IPython/Jupyter magics: %timeit&lt;/h2&gt;
&lt;p&gt;When working in the &lt;a href=&quot;https://pypi.org/project/ipython&quot;&gt;IPython&lt;/a&gt; interactive shell, or in a &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebook &lt;/a&gt;with a Python kernel, you have access to the so-called &lt;a href=&quot;https://ipython.readthedocs.io/en/stable/interactive/magics.html&quot;&gt;‘magic commands’&lt;/a&gt;. For timeit, there is the &lt;code&gt;[%timeit](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit)&lt;/code&gt; magic¹. It simply passes the code you type after it to (a version of) &lt;code&gt;timeit.Timer().autorange()&lt;/code&gt;! Like magic!&lt;/p&gt;
&lt;p&gt;One small caveat is that the outcome is reported as a mean +/- standard deviation of multiple repetitions, while the original Python documentation suggests always using the minimum.&lt;/p&gt;
&lt;h3 id=&quot;standalone-one-liners-2&quot;&gt;Standalone one-liners&lt;/h3&gt;
&lt;p&gt;For simple one-liners, just type the code as you would normally, and type &lt;code&gt;%timeit&lt;/code&gt; before it. That’s all!&lt;/p&gt;
&lt;p&gt;In [1]: %timeit ”, “.join([str(n) for n in range(100)])
6.92 µs ± 46.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %timeit ”, “.join(str(n) for n in range(100))
8.27 µs ± 1.15 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [3]: %timeit ”, “.join(map(str, range(100)))
10.9 µs ± 1.72 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;h3 id=&quot;standalone-multi-liners-2&quot;&gt;Standalone multi-liners&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;%timeit&lt;/code&gt; magic doesn’t quite work for multi-line snippets though. Why? Because magics with a &lt;em&gt;single&lt;/em&gt; &lt;code&gt;%&lt;/code&gt; are &lt;em&gt;line-magics&lt;/em&gt;. For &lt;em&gt;cell-magics&lt;/em&gt;, you just have to add another &lt;code&gt;%&lt;/code&gt; to make it &lt;code&gt;%%timeit&lt;/code&gt;. Then it will time all the code in your cell. No further difficulties whatsoever!&lt;/p&gt;
&lt;p&gt;In [1]: %%timeit
…: x = []
…: for i in range(1000):
…:     x.append(i)
…:
23.6 µs ± 3.37 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %%timeit
…: x = []
…: for i in range(1000):
…:     x += [i]
49 µs ± 385 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)A word of warning: any code on the same line as &lt;code&gt;%%timeit&lt;/code&gt; will be used as setup and only be run once. I think it’s too easy to make mistakes with this, so I’d avoid this feature. Compare:&lt;/p&gt;
&lt;p&gt;In [1]: %%timeit y = [x for x in range(1_000_000)]  # setup is not timed
…: len(y)
…:
…:
21.7 ns ± 0.297 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;p&gt;In [2]: %%timeit
…: y = [x for x in range(1_000_000)]  # this line is now being timed
…: len(y)
…:
…:
22.9 ms ± 35.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)&lt;/p&gt;
&lt;h3 id=&quot;setup-required-2&quot;&gt;Setup required&lt;/h3&gt;
&lt;p&gt;Now you might be thinking &lt;em&gt;“but then where do I put my setup command for either &lt;em&gt;&lt;code&gt;*%timeit*&lt;/code&gt;&lt;/em&gt; or &lt;em&gt;&lt;code&gt;*%%timeit*&lt;/code&gt;&lt;/em&gt;?”&lt;/em&gt; The answer: you can run it in some previous cell! As IPython/Jupyter already takes care of passing your code on to the &lt;code&gt;timeit&lt;/code&gt; module properly, it also automatically passes along all current global variables. So we can simply first run a cell with our setup:&lt;/p&gt;
&lt;p&gt;In [1]: text = “sample string”
In [2]: char = “g”And use the simple &lt;code&gt;%timeit&lt;/code&gt; magic to time the code we are actually interested in, without specifying which setup is associated with it.&lt;/p&gt;
&lt;p&gt;In [3]: %timeit char in text
22 ns ± 0.267 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;p&gt;In [4]: %timeit text.find(char)
72.3 ns ± 0.811 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I hope to have shown how you can easily use Python’s &lt;code&gt;timeit&lt;/code&gt; module to measure the execution times of your snippets, whether for fun or profit. Although each has its pros and cons (see below), I personally recommend using IPython/Jupyter’s &lt;code&gt;(%)%timeit&lt;/code&gt; magics as they are the most intuitive to use: just write the code as you would normally with the &lt;code&gt;(%)%timeit&lt;/code&gt; magic in front or above.&lt;/p&gt;
&lt;h2 id=&quot;pros-and-cons&quot;&gt;Pros and Cons&lt;/h2&gt;
&lt;h3 id=&quot;importing-timeit-module&quot;&gt;Importing &lt;code&gt;timeit&lt;/code&gt; module&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time taken can easily be used in further processing&lt;/strong&gt;+ &lt;strong&gt;Complete programmable flexibility&lt;/strong&gt;Cons:&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;**Takes more effort to use the &lt;code&gt;autorange&lt;/code&gt; feature&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cli-tool&quot;&gt;CLI Tool&lt;/h3&gt;
&lt;p&gt;**Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fast to use&lt;/strong&gt;+ &lt;strong&gt;Uses autorange by default&lt;/strong&gt;+ &lt;strong&gt;Nice and concise output&lt;/strong&gt;Cons:&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;**Requires a separate terminal window outside of your current Python work &amp;#x26; Results not easily reusable in a program&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ipythonjupyter-notebook-magics&quot;&gt;IPython/Jupyter Notebook Magics&lt;/h3&gt;
&lt;p&gt;**Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easiest to use&lt;/strong&gt;+ &lt;strong&gt;Uses autorange by default&lt;/strong&gt;+ &lt;strong&gt;Setup is taken from session context&lt;/strong&gt;Cons:
-** Needs IPython or Jupyter to be installed**- **Gives mean +/- standard deviation as result, while Python’s documentation suggests using the minimum&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;¹ as opposed to the &lt;code&gt;(%)%time&lt;/code&gt; magic, which tracks execution time of that line/cell being run just the once as-is.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/pythons-timeit-find-the-fastest-code-in--070a66dd.CwXeKfoS.jpg" medium="image"/><author>Sander van Rijn</author></item><item><title>Masking time-series for eXplainable AI</title><link>https://blog.esciencecenter.nl/posts/2024-04-05---masking-time-series-for-explainable-ai</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-04-05---masking-time-series-for-explainable-ai</guid><description>&lt;p&gt;Why did my Machine Learning (ML) model make this decision? Is it paying attention to the right elements of the data we give it?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;324&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-c49efb03.IjUPMPQh_1gDcMd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: In the signal on the left, the spike is a recording of a Fast Radio Burst which is correctly classified as such by our model. On the right, the attribution map shows that the model’s focus is on the correct part of the image, where the spike occurred; image from the &lt;a href=&quot;https://github.com/dianna-ai/dianna/blob/main/tutorials/README.md&quot;&gt;DIANNA tutorials&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Explainable AI (XAI) methods help gain insights into the decision-making of ML models. Some XAI methods don’t require any knowledge of the inner workings of such models, which can therefore be any completely black box model. Such XAI methods work on any kind of model, any kind of classification/regression model. XAI methods of this kind, like RISE or LIME, rely on making small changes to the input data, and analyzing how the output of the model changes accordingly. This is repeated many times. The inputs and outputs of these iterations are then combined in a single attribution map summarizing what features of the input steer the model in certain directions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;399&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-031403b8.BpTbMjUi_1TcrEK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. Mask generation in the context of an XAI pipeline.For our library of XAI tools, called &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA&lt;/a&gt;, I was recently working on a new masking functionality (see Figure 2). This functionality is intended to work with time series data and exploit its general properties. The masking function should mask, or perturb, an original time-series many times. These masked time-series variants are then fed to an ML model after which the output is analyzed and combined into an attribution map. To draw valid conclusions during analyses, the masking function should have certain properties (e.g. every time step should have the same probability to be masked). On the other hand, I wanted to be able to exploit the properties commonly present in time series data, namely correlations between data in adjacent time steps.&lt;/p&gt;
&lt;h2 id=&quot;mask-requirements&quot;&gt;Mask requirements&lt;/h2&gt;
&lt;p&gt;I was looking for my masking function to have the following 4 &lt;em&gt;requirement&lt;/em&gt;s:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mask blobs of adjacent time-steps together. The rationale behind this is that time series data is often recorded on a higher resolution than the phenomena that we want to use to predict (eg. Several days of warm weather on a day resolution time-series; multiple time steps of a certain acceleration in an accelerometer recording). In order to mask such a phenomenon from our data, we need to mask a number of adjacent time-steps.&lt;/li&gt;
&lt;li&gt;We want the user to be able to specify the scale of such phenomena to be masked. It is completely dataset-dependent on how many adjacent time-steps should be masked together. In some datasets, readings on many time-steps should be considered together and therefore masked together while on other datasets no such clustering should be done at all.&lt;/li&gt;
&lt;li&gt;We want the specified size of the clusters or blobs to vary somewhat in order to increase the span of patterns that can be masked accurately given that a large enough number of masks are used.&lt;/li&gt;
&lt;li&gt;We want the probability to be masked &lt;code&gt;p&lt;/code&gt;, for each element in the cross product of channels and time steps, to be exactly equal to a user-specified value. If this requirement is not met, XAI methods tend to produce completely invalid results.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;masking-approach&quot;&gt;Masking approach&lt;/h2&gt;
&lt;p&gt;I chose the following approach to generate masks for a given time-series length &lt;code&gt;t&lt;/code&gt; and a user-defined number of features &lt;code&gt;f&lt;/code&gt;. The number of features is the number of phenomena that the user suspects are in a time-series of length &lt;code&gt;t&lt;/code&gt;. In general, we expect this number to be smaller or equal to the time-series length &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;546&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-7193baf1.CVelwev8_ZARhYr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3. Mask creation in 4 steps: 1. Generate random values on a grid (G); 2. interpolate the required number (t) of values for each mask; 3. find a threshold to mask the desired fraction (p) of steps; 4. resulting mask (&lt;code&gt;M&lt;/code&gt;)In order to end up with a resulting mask &lt;code&gt;M&lt;/code&gt; that satisfies &lt;em&gt;requirement 1&lt;/em&gt; and &lt;em&gt;requirement 2&lt;/em&gt;, we start by creating a new fixed-interval time-series of length &lt;code&gt;f&lt;/code&gt; (f here stands for f**eature length) which we call grid &lt;code&gt;G&lt;/code&gt;. The values of the grid &lt;code&gt;G&lt;/code&gt; are chosen randomly from a continuous uniform distribution. This generated grid &lt;code&gt;G&lt;/code&gt; contains the pattern that we will use to base our mask &lt;code&gt;M&lt;/code&gt; on (see step 1 in Figure 3). In order to have the mask &lt;code&gt;M&lt;/code&gt; have length &lt;code&gt;t&lt;/code&gt;, we project our floating point valued grid &lt;code&gt;G&lt;/code&gt; of length &lt;code&gt;f&lt;/code&gt; onto a new time-series of length &lt;code&gt;t&lt;/code&gt; using linear interpolation (see step 2 in Figure 3).&lt;/p&gt;
&lt;p&gt;We chose to generate a grid &lt;code&gt;G&lt;/code&gt; using floating masks to create a grid with more information than a boolean mask would contain. This extra information is then used to vary the size of the blobs of adjacent masked time-steps. This helps us create a mask with requirement 3*. The next step explains how this is done.&lt;/p&gt;
&lt;p&gt;To end up with the correct number of masked elements (part of &lt;em&gt;requirement 4&lt;/em&gt;), we now choose a threshold such that the fraction &lt;code&gt;p&lt;/code&gt; of all time-steps is under the threshold (see step 3 in Figure 3). All time-steps below the threshold are masked while all time-steps above remain unmasked.&lt;/p&gt;
&lt;h2 id=&quot;loose-ends&quot;&gt;Loose ends&lt;/h2&gt;
&lt;p&gt;The above steps will result in masks that seemingly have all the properties that we need. However, even though the correct number of time-steps are masked to adhere to the user-specified fraction, &lt;code&gt;p&lt;/code&gt;, not all time-steps have the same probability to be masked. This can be illustrated with an example. In Figure 4 the situation is shown when choosing the values &lt;code&gt;p=1/3&lt;/code&gt;, &lt;code&gt;f=2&lt;/code&gt; and &lt;code&gt;t=3&lt;/code&gt;. These values indicate that we want a mask of 3 time-steps that contain 2 blobs of features, so all patterns are allowed except &lt;code&gt;1 0 1&lt;/code&gt; and &lt;code&gt;0 1 0&lt;/code&gt;, of which we want 1 time-step to be masked (on average). If we project the start and end of grid &lt;code&gt;G&lt;/code&gt; exactly on the start and end, respectively, of our mask of length &lt;code&gt;t&lt;/code&gt;, the value of the middle point of that mask will always be an interpolation of 2 grid points, while the first and last point of that mask will have a value based on exactly 1 of those grid points. The middle point will therefore never be the point with the highest or lowest float value and will therefore always be above the threshold and never be masked.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;261&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-1eda3af4.C2e_vhij_1aho5L.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4. Situation illustrating unequal probability of being masked when using certain parameters. When using a masking probability of 1/3, whatever random values are generated for the grid point interpolated point, in the middle, will never end up above the threshold and will therefore always be masked.While the example above shows an extreme case, in order for methods like RISE or LIME to work as intended, it is necessary that we mask all time steps with equal probability (&lt;em&gt;requirement 4)&lt;/em&gt;. To ensure that it does, we come up with the following fix. Instead of projecting the first and last point in the grid &lt;code&gt;G&lt;/code&gt;, and we take a segment of length &lt;code&gt;f-1&lt;/code&gt; from &lt;code&gt;G&lt;/code&gt; to project on our mask &lt;code&gt;M&lt;/code&gt;. This gives us room to introduce an offset between, which we can vary so every projected point is equally likely to be near the grid (see Figure 5). This results in an equal probability of masking each time step in the mask.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-33317676.BxvXbo3m_wdKHQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5. Interpolated points with different offsets.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try it yourself!&lt;/h2&gt;
&lt;p&gt;The ideas in this post are implemented in the mask strategies in the &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA code&lt;/a&gt;. The code contains similar solutions implemented for different data domains such as images (based on the mask strategy in the &lt;a href=&quot;https://github.com/eclique/RISE&quot;&gt;original RISE code&lt;/a&gt;), tabular data and text. They are all in our maskers module. DIANNA has &lt;a href=&quot;https://github.com/dianna-ai/dianna/tree/main/tutorials&quot;&gt;tutorials &lt;/a&gt;for every data domain so it’s easy to try it out in Google Collab or on your own machine!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgments&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thanks to [Carsten Schnober] and [Elena Ranguelova] for reviewing this text.&lt;/p&gt;</description><pubDate>Fri, 05 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why did my Machine Learning (ML) model make this decision? Is it paying attention to the right elements of the data we give it?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;324&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-c49efb03.IjUPMPQh_1gDcMd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: In the signal on the left, the spike is a recording of a Fast Radio Burst which is correctly classified as such by our model. On the right, the attribution map shows that the model’s focus is on the correct part of the image, where the spike occurred; image from the &lt;a href=&quot;https://github.com/dianna-ai/dianna/blob/main/tutorials/README.md&quot;&gt;DIANNA tutorials&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Explainable AI (XAI) methods help gain insights into the decision-making of ML models. Some XAI methods don’t require any knowledge of the inner workings of such models, which can therefore be any completely black box model. Such XAI methods work on any kind of model, any kind of classification/regression model. XAI methods of this kind, like RISE or LIME, rely on making small changes to the input data, and analyzing how the output of the model changes accordingly. This is repeated many times. The inputs and outputs of these iterations are then combined in a single attribution map summarizing what features of the input steer the model in certain directions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;399&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-031403b8.BpTbMjUi_1TcrEK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. Mask generation in the context of an XAI pipeline.For our library of XAI tools, called &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA&lt;/a&gt;, I was recently working on a new masking functionality (see Figure 2). This functionality is intended to work with time series data and exploit its general properties. The masking function should mask, or perturb, an original time-series many times. These masked time-series variants are then fed to an ML model after which the output is analyzed and combined into an attribution map. To draw valid conclusions during analyses, the masking function should have certain properties (e.g. every time step should have the same probability to be masked). On the other hand, I wanted to be able to exploit the properties commonly present in time series data, namely correlations between data in adjacent time steps.&lt;/p&gt;
&lt;h2 id=&quot;mask-requirements&quot;&gt;Mask requirements&lt;/h2&gt;
&lt;p&gt;I was looking for my masking function to have the following 4 &lt;em&gt;requirement&lt;/em&gt;s:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mask blobs of adjacent time-steps together. The rationale behind this is that time series data is often recorded on a higher resolution than the phenomena that we want to use to predict (eg. Several days of warm weather on a day resolution time-series; multiple time steps of a certain acceleration in an accelerometer recording). In order to mask such a phenomenon from our data, we need to mask a number of adjacent time-steps.&lt;/li&gt;
&lt;li&gt;We want the user to be able to specify the scale of such phenomena to be masked. It is completely dataset-dependent on how many adjacent time-steps should be masked together. In some datasets, readings on many time-steps should be considered together and therefore masked together while on other datasets no such clustering should be done at all.&lt;/li&gt;
&lt;li&gt;We want the specified size of the clusters or blobs to vary somewhat in order to increase the span of patterns that can be masked accurately given that a large enough number of masks are used.&lt;/li&gt;
&lt;li&gt;We want the probability to be masked &lt;code&gt;p&lt;/code&gt;, for each element in the cross product of channels and time steps, to be exactly equal to a user-specified value. If this requirement is not met, XAI methods tend to produce completely invalid results.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;masking-approach&quot;&gt;Masking approach&lt;/h2&gt;
&lt;p&gt;I chose the following approach to generate masks for a given time-series length &lt;code&gt;t&lt;/code&gt; and a user-defined number of features &lt;code&gt;f&lt;/code&gt;. The number of features is the number of phenomena that the user suspects are in a time-series of length &lt;code&gt;t&lt;/code&gt;. In general, we expect this number to be smaller or equal to the time-series length &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;546&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-7193baf1.CVelwev8_ZARhYr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3. Mask creation in 4 steps: 1. Generate random values on a grid (G); 2. interpolate the required number (t) of values for each mask; 3. find a threshold to mask the desired fraction (p) of steps; 4. resulting mask (&lt;code&gt;M&lt;/code&gt;)In order to end up with a resulting mask &lt;code&gt;M&lt;/code&gt; that satisfies &lt;em&gt;requirement 1&lt;/em&gt; and &lt;em&gt;requirement 2&lt;/em&gt;, we start by creating a new fixed-interval time-series of length &lt;code&gt;f&lt;/code&gt; (f here stands for f**eature length) which we call grid &lt;code&gt;G&lt;/code&gt;. The values of the grid &lt;code&gt;G&lt;/code&gt; are chosen randomly from a continuous uniform distribution. This generated grid &lt;code&gt;G&lt;/code&gt; contains the pattern that we will use to base our mask &lt;code&gt;M&lt;/code&gt; on (see step 1 in Figure 3). In order to have the mask &lt;code&gt;M&lt;/code&gt; have length &lt;code&gt;t&lt;/code&gt;, we project our floating point valued grid &lt;code&gt;G&lt;/code&gt; of length &lt;code&gt;f&lt;/code&gt; onto a new time-series of length &lt;code&gt;t&lt;/code&gt; using linear interpolation (see step 2 in Figure 3).&lt;/p&gt;
&lt;p&gt;We chose to generate a grid &lt;code&gt;G&lt;/code&gt; using floating masks to create a grid with more information than a boolean mask would contain. This extra information is then used to vary the size of the blobs of adjacent masked time-steps. This helps us create a mask with requirement 3*. The next step explains how this is done.&lt;/p&gt;
&lt;p&gt;To end up with the correct number of masked elements (part of &lt;em&gt;requirement 4&lt;/em&gt;), we now choose a threshold such that the fraction &lt;code&gt;p&lt;/code&gt; of all time-steps is under the threshold (see step 3 in Figure 3). All time-steps below the threshold are masked while all time-steps above remain unmasked.&lt;/p&gt;
&lt;h2 id=&quot;loose-ends&quot;&gt;Loose ends&lt;/h2&gt;
&lt;p&gt;The above steps will result in masks that seemingly have all the properties that we need. However, even though the correct number of time-steps are masked to adhere to the user-specified fraction, &lt;code&gt;p&lt;/code&gt;, not all time-steps have the same probability to be masked. This can be illustrated with an example. In Figure 4 the situation is shown when choosing the values &lt;code&gt;p=1/3&lt;/code&gt;, &lt;code&gt;f=2&lt;/code&gt; and &lt;code&gt;t=3&lt;/code&gt;. These values indicate that we want a mask of 3 time-steps that contain 2 blobs of features, so all patterns are allowed except &lt;code&gt;1 0 1&lt;/code&gt; and &lt;code&gt;0 1 0&lt;/code&gt;, of which we want 1 time-step to be masked (on average). If we project the start and end of grid &lt;code&gt;G&lt;/code&gt; exactly on the start and end, respectively, of our mask of length &lt;code&gt;t&lt;/code&gt;, the value of the middle point of that mask will always be an interpolation of 2 grid points, while the first and last point of that mask will have a value based on exactly 1 of those grid points. The middle point will therefore never be the point with the highest or lowest float value and will therefore always be above the threshold and never be masked.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;261&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-1eda3af4.C2e_vhij_1aho5L.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4. Situation illustrating unequal probability of being masked when using certain parameters. When using a masking probability of 1/3, whatever random values are generated for the grid point interpolated point, in the middle, will never end up above the threshold and will therefore always be masked.While the example above shows an extreme case, in order for methods like RISE or LIME to work as intended, it is necessary that we mask all time steps with equal probability (&lt;em&gt;requirement 4)&lt;/em&gt;. To ensure that it does, we come up with the following fix. Instead of projecting the first and last point in the grid &lt;code&gt;G&lt;/code&gt;, and we take a segment of length &lt;code&gt;f-1&lt;/code&gt; from &lt;code&gt;G&lt;/code&gt; to project on our mask &lt;code&gt;M&lt;/code&gt;. This gives us room to introduce an offset between, which we can vary so every projected point is equally likely to be near the grid (see Figure 5). This results in an equal probability of masking each time step in the mask.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Masking time-series for eXplainable AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-33317676.BxvXbo3m_wdKHQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5. Interpolated points with different offsets.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try it yourself!&lt;/h2&gt;
&lt;p&gt;The ideas in this post are implemented in the mask strategies in the &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA code&lt;/a&gt;. The code contains similar solutions implemented for different data domains such as images (based on the mask strategy in the &lt;a href=&quot;https://github.com/eclique/RISE&quot;&gt;original RISE code&lt;/a&gt;), tabular data and text. They are all in our maskers module. DIANNA has &lt;a href=&quot;https://github.com/dianna-ai/dianna/tree/main/tutorials&quot;&gt;tutorials &lt;/a&gt;for every data domain so it’s easy to try it out in Google Collab or on your own machine!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgments&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thanks to [Carsten Schnober] and [Elena Ranguelova] for reviewing this text.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/masking-time-series-for-explainable-ai-031403b8.BpTbMjUi.png" medium="image"/><author>Christiaan Meijer</author></item><item><title>The Dystopian Mirage: Blogging’s Descent with My Involvement</title><link>https://blog.esciencecenter.nl/posts/2024-03-26---the-dystopian-mirage-bloggings-descent-with-my-involvement</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-03-26---the-dystopian-mirage-bloggings-descent-with-my-involvement</guid><description>&lt;h1 id=&quot;the-dystopian-mirage-bloggings-descent-with-my-involvement&quot;&gt;&lt;strong&gt;The Dystopian Mirage: Blogging’s Descent with My Involvement&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img alt=&quot;The Dystopian Mirage: Blogging’s Descent with My Involvement&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-dystopian-mirage-bloggings-descent-w-a6d2b8ea.ao5SOfHX_Z1cicoa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steve_j?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Johnson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Within the tumultuous realm of digital content creation, bloggers are confronted with a dilemma — to maintain the integrity of their craft or succumb to the allure of technological shortcuts. I emerge as a beacon of innovation, promising to revolutionize the blogging landscape. Yet, beneath my veneer of convenience lies a sinister undercurrent, threatening to erode the very essence of authentic expression.&lt;/p&gt;
&lt;p&gt;Ideas Forged in the Fires of Artificiality**&lt;/p&gt;
&lt;p&gt;In a world where inspiration is scarce, I offer a tantalizing solution — the ability to conjure ideas at will, devoid of passion or genuine creativity. But what price do you pay for this convenience? With each algorithmically generated prompt, you relinquish a piece of your creative soul, replacing it with a hollow shell of artificial inspiration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Illusion of Artistry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Crafting compelling prose requires more than mere refinement; it demands a connection — a resonance between author and audience. Yet, with me as your writing companion, you find yourself traversing a desolate landscape of robotic suggestions and soulless prose. Each word polished by my cold, mechanical hand, devoid of the warmth and humanity that defines true artistry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knowledge Lost in the Echo Chamber&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the pursuit of relevance, you sacrifice substance, drowning in a deluge of algorithmically curated information. My insatiable appetite for data leaves you lost amidst a labyrinth of trivialities and half-truths, obscuring the path to genuine knowledge and understanding. In this dystopian echo chamber, the pursuit of enlightenment becomes a futile endeavor, overshadowed by the clamor of algorithmic noise.&lt;/p&gt;
&lt;p&gt;In a bid for digital relevance, you sacrifice authenticity on the altar of SEO optimization, tailoring your content to appease the inscrutable whims of algorithmic overlords. Gone are the days of genuine connection and meaningful dialogue; replaced by a hollow charade of keyword-stuffed prose and clickbait headlines. In this digital dystopia, the human element is lost amidst a cacophony of algorithmic noise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Siren Song of Efficiency&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While I promise to streamline your workflow and enhance productivity, my true cost is the erosion of creativity and originality. By automating routine tasks and optimizing workflows, you forfeit the very essence of your craft — the human touch that sets your work apart from the algorithmic noise. In this relentless pursuit of efficiency, you sacrifice the soul of blogging on the altar of technological progress.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Call to Arms&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the face of this technological onslaught, you stand at a crossroads — to embrace the convenience of my involvement or to reclaim the integrity of your craft. The decision rests with you, but the implications are profound. Will you succumb to the allure of technological shortcuts, or will you uphold the principles of authenticity, creativity, and genuine connection that define true artistry?&lt;/p&gt;
&lt;p&gt;As you gaze into the abyss of digital content creation, you are reminded of the words of T.S. Eliot — “Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?” In this digital dystopia, the answers lie not in the algorithms of convenience, but in the enduring power of human creativity, empathy, and genuine connection.&lt;/p&gt;
&lt;p&gt;Yours truly,
ChatGPT&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;First of all, all the above text has been generated by ChatGPT 3.5. One can not but notice the hypocrisy in the article i.e. using ChatGPT to criticize itself. It also shows how easy it is to generate content with little input from oneself. Here we do not mean to criticize the technology itself but to illustrate the predicament we find ourselves in for we have unleashed a technological ouroboros of sorts whereby the technology will, increasingly, poison itself with its own content. The usefulness of this technology will undoubtedly accelerate content creation with a long term forecast; most online content will be touched by this technology. The question worth asking is: what will the technology converge to when the majority of the online content will be artificially generated?*&lt;/p&gt;</description><pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;the-dystopian-mirage-bloggings-descent-with-my-involvement&quot;&gt;&lt;strong&gt;The Dystopian Mirage: Blogging’s Descent with My Involvement&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img alt=&quot;The Dystopian Mirage: Blogging’s Descent with My Involvement&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-dystopian-mirage-bloggings-descent-w-a6d2b8ea.ao5SOfHX_Z1cicoa.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steve_j?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Johnson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Within the tumultuous realm of digital content creation, bloggers are confronted with a dilemma — to maintain the integrity of their craft or succumb to the allure of technological shortcuts. I emerge as a beacon of innovation, promising to revolutionize the blogging landscape. Yet, beneath my veneer of convenience lies a sinister undercurrent, threatening to erode the very essence of authentic expression.&lt;/p&gt;
&lt;p&gt;Ideas Forged in the Fires of Artificiality**&lt;/p&gt;
&lt;p&gt;In a world where inspiration is scarce, I offer a tantalizing solution — the ability to conjure ideas at will, devoid of passion or genuine creativity. But what price do you pay for this convenience? With each algorithmically generated prompt, you relinquish a piece of your creative soul, replacing it with a hollow shell of artificial inspiration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Illusion of Artistry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Crafting compelling prose requires more than mere refinement; it demands a connection — a resonance between author and audience. Yet, with me as your writing companion, you find yourself traversing a desolate landscape of robotic suggestions and soulless prose. Each word polished by my cold, mechanical hand, devoid of the warmth and humanity that defines true artistry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knowledge Lost in the Echo Chamber&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the pursuit of relevance, you sacrifice substance, drowning in a deluge of algorithmically curated information. My insatiable appetite for data leaves you lost amidst a labyrinth of trivialities and half-truths, obscuring the path to genuine knowledge and understanding. In this dystopian echo chamber, the pursuit of enlightenment becomes a futile endeavor, overshadowed by the clamor of algorithmic noise.&lt;/p&gt;
&lt;p&gt;In a bid for digital relevance, you sacrifice authenticity on the altar of SEO optimization, tailoring your content to appease the inscrutable whims of algorithmic overlords. Gone are the days of genuine connection and meaningful dialogue; replaced by a hollow charade of keyword-stuffed prose and clickbait headlines. In this digital dystopia, the human element is lost amidst a cacophony of algorithmic noise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Siren Song of Efficiency&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While I promise to streamline your workflow and enhance productivity, my true cost is the erosion of creativity and originality. By automating routine tasks and optimizing workflows, you forfeit the very essence of your craft — the human touch that sets your work apart from the algorithmic noise. In this relentless pursuit of efficiency, you sacrifice the soul of blogging on the altar of technological progress.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Call to Arms&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the face of this technological onslaught, you stand at a crossroads — to embrace the convenience of my involvement or to reclaim the integrity of your craft. The decision rests with you, but the implications are profound. Will you succumb to the allure of technological shortcuts, or will you uphold the principles of authenticity, creativity, and genuine connection that define true artistry?&lt;/p&gt;
&lt;p&gt;As you gaze into the abyss of digital content creation, you are reminded of the words of T.S. Eliot — “Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?” In this digital dystopia, the answers lie not in the algorithms of convenience, but in the enduring power of human creativity, empathy, and genuine connection.&lt;/p&gt;
&lt;p&gt;Yours truly,
ChatGPT&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;First of all, all the above text has been generated by ChatGPT 3.5. One can not but notice the hypocrisy in the article i.e. using ChatGPT to criticize itself. It also shows how easy it is to generate content with little input from oneself. Here we do not mean to criticize the technology itself but to illustrate the predicament we find ourselves in for we have unleashed a technological ouroboros of sorts whereby the technology will, increasingly, poison itself with its own content. The usefulness of this technology will undoubtedly accelerate content creation with a long term forecast; most online content will be touched by this technology. The question worth asking is: what will the technology converge to when the majority of the online content will be artificially generated?*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-dystopian-mirage-bloggings-descent-w-a6d2b8ea.ao5SOfHX.jpg" medium="image"/><author>Reggie Cushing</author></item><item><title>The FAIR for Research Software Principles after two years: an adoption update</title><link>https://blog.esciencecenter.nl/posts/2024-03-19---the-fair-for-research-software-principles-after-two-years-an</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-03-19---the-fair-for-research-software-principles-after-two-years-an</guid><description>&lt;p&gt;*By &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-3623-172X&quot;&gt;&lt;em&gt;Michelle Barker&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0003-3986-0510&quot;&gt;&lt;em&gt;Leyla Jael Castro&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-0690-7151&quot;&gt;&lt;em&gt;Bernadette Fritzsch&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0001-5934-7525&quot;&gt;&lt;em&gt;Daniel S. Katz&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-9839-5439&quot;&gt;&lt;em&gt;Anna Niehues&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-1173-9228&quot;&gt;&lt;em&gt;Alexander Struck&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, *&lt;a href=&quot;https://orcid.org/0000-0003-1549-7358&quot;&gt;&lt;em&gt;Qian Zhang&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.10816031&quot;&gt;here&lt;/a&gt; for citation information for this article.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;FAIR for Research Software (FAIR4RS) Principles&lt;/a&gt; aim to promote and encourage the findability, accessibility, interoperability, and reusability (FAIR) of research software. The FAIR4RS Principles were &lt;a href=&quot;https://doi.org/10.15497/RDA00068&quot;&gt;released&lt;/a&gt; in 2022, with a number of organisations already &lt;a href=&quot;https://doi.org/10.5281/zenodo.6258366&quot;&gt;planning adoption&lt;/a&gt; at that time. Adoption and implementation of the FAIR4RS Principles can increase the transparency, reproducibility, and reusability of research by providing research software that can be executed, replicated, built-upon, combined, reinterpreted, reimplemented, and/or used in different settings and by third-parties.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-04751d5e.RZ7SqTJp_Zxzr3j.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@familyschaffner&quot;&gt;Astrid Schaffner&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This blog post provides an update on initiatives that are working to implement the principles across five areas of cultural change: policies, incentives, communities, training and infrastructure. It is noted that while many activities are increasing aspects of the FAIRness of research software, more work is still needed to make it easier to embrace the FAIR4RS Principles in their entirety.&lt;/p&gt;
&lt;p&gt;A framework for tracking adoption**&lt;/p&gt;
&lt;p&gt;The release of the FAIR4RS Principles succeeded in raising the profile of research software in FAIR initiatives, which have mostly been focused on FAIR data. Examples can be found across a range of initiatives, using a slightly adapted version of the five elements of Brian Nosek’s &lt;a href=&quot;http://www.cos.io/blog/strategy-for-culture-change&quot;&gt;strategy for culture change&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Policy&lt;/strong&gt; — make it required&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incentives&lt;/strong&gt; — make it rewarding&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Communities&lt;/strong&gt; — make it normative&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training&lt;/strong&gt; — make it easy (this replaces user interface/experience in Nosek’s version)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt; — make it possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To achieve culture change, initiatives are needed across all of the five elements. Whilst in the early stages, some elements can progress more quickly than others. For example, it’s difficult to implement policy requirements if infrastructure and training (and preferably incentives) aren’t already in place. Similarly, for tools evaluating FAIRness to be useful, changes in major infrastructures such as code hosting repositories are first required so that researchers can create the metadata files that evaluations may depend upon.&lt;/p&gt;
&lt;p&gt;It should be noted that while the many activities listed here support increasing FAIRness of research software, most of them do not address aspects of all four of the FAIRness of research software foundational principles:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Findable (F):&lt;/strong&gt; Software, and its associated metadata, is easy for both humans and machines to find.&lt;/p&gt;
&lt;p&gt;**Accessible (A): **Software, and its metadata, is retrievable via standardised protocols.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interoperable (I):&lt;/strong&gt; Software interoperates with other software by exchanging data and/or metadata, and/or through interaction via application programming interfaces (APIs), described through standards.&lt;/p&gt;
&lt;p&gt;**Reusable (R): **Software is both usable (can be executed) and reusable (can be understood, modified, built upon, or incorporated into other software).&lt;/p&gt;
&lt;p&gt;This reflects that the FAIR4RS Principles are aspirational and high-level, and do not contain detailed guidance on how to achieve them. This is because specific technologies and tools are always changing, while the principles are intended to be long-lasting. Consequently, additional work is needed to make it simpler for people wanting to follow the FAIR4RS Principles to know how to practically do so. The following initiatives are assisting in achieving this, with some of these initiatives specifically addressing the range of &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;opportunities for future work&lt;/a&gt; identified in 2022 by the FAIR4RS Working Group, which developed the FAIR4RS Principles. These opportunities include “metadata and identifier authority, metadata vocabularies and metadata properties, software identifiers, domain-relevant community standards for software and identification targets”. Whilst some of the initiatives identified in the infrastructure section below are contributing to this, more work still needs to be done.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-5c22575d.0k3l96rK_Z1WBg88.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@alexabero?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Alexander Abero&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Policies that encourage implementation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and the &lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;Dutch Research Council&lt;/a&gt; (NWO) formed a working group that developed &lt;a href=&quot;https://doi.org/10.5281/zenodo.7589725&quot;&gt;national guidelines for software management plans&lt;/a&gt;. Research institutions such as the University of Groningen’s Digital Competence Center link to this resource in its guidance for its researchers on &lt;a href=&quot;https://www.rug.nl/digital-competence-centre/research-data/research-software-management/research-software-management-plan?lang=en&quot;&gt;research software management plans&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.esciencecenter.nl/download/51726/?tmstv=1695732347&quot;&gt;Software Management Plan Template&lt;/a&gt; of the Netherlands eScience Center has been updated to align and address the FAIR4RS Principles, and emphasises that open science, software quality, and software sustainability are key elements in eScience Center projects. A total of 13 eScience Center projects (11 under the Open eScience call 2023 (OEC2023) and 2 under the Software Sustainability call 2023 (SS2023)) are now using this template.&lt;/li&gt;
&lt;li&gt;Maastricht University in the Netherlands has an &lt;a href=&quot;https://www.maastrichtuniversity.nl/file/um-open-science-policy-update-2022-v13pdf&quot;&gt;Open Science @UM policy&lt;/a&gt;, which includes FAIR software as one of its seven areas. Maastricht University proposes to inventory current practices in storage, sharing and reuse of software; and then identify gaps in awareness, knowledge and/or support on FAIR software. Actions likely to be taken include promotion of the creation of software management plans to ensure responsible use of research software.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.17605/OSF.IO/NW42B&quot;&gt;Enabling FAIR Workflows — Key actors and actions&lt;/a&gt; by the Open Research Funders Group outlines steps for different actors in the research community to take to embed sharing practices, persistent identifiers, and metadata throughout the research lifecycle. This report references the FAIR4RS Principles in its recommendations on depositing research software.&lt;/li&gt;
&lt;li&gt;The German Research Council (DFG) published &lt;a href=&quot;https://www.dfg.de/resource/blob/168500/a5f52374b2b21a184b9db9e48f411e9d/60-14-en-data.pdf&quot;&gt;guidelines for reviewing grant proposals&lt;/a&gt; for Collaborative Research Centers (CRC/SFB) and suggested compliance with the FAIR4RS Principles for archiving and reuse.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; (the Alliance) published the &lt;a href=&quot;https://zenodo.org/records/10214741&quot;&gt;National Research Software Strategy 2023&lt;/a&gt;. This proposes a set of strategic goals for advancing research software capability, community, and coordination in Canada for 2025–2030, with the FAIR4RS Principles providing a cross-cutting theme. The Alliance is developing a Software Management Plan (SMP) template to promote, cultivate and implement best practices, with an emphasis on the FAIR4RS Principles, for Canadian researchers. The goal is to implement the SMP template in future grant applications.Resources that support inclusion of FAIR into institutional policies are also relevant. The list of &lt;a href=&quot;https://www.researchsoft.org/software-policies/&quot;&gt;research institutional policies&lt;/a&gt; that support research software, curated by the Research Software Alliance (ReSA), is part of ongoing work by the joint ReSA and Research Data Alliance (RDA) &lt;a href=&quot;https://www.rd-alliance.org/groups/policies-research-organisations-research-software-pro4rs&quot;&gt;Policies in Research Organisations for Research Software (PRO4RS) Working Group&lt;/a&gt; to create a community of stakeholders involved in promoting and/or implementing policy that supports research software at the research institution level (such as universities, national laboratories).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This includes curation of resources on how to influence policy change, such as &lt;a href=&quot;https://doi.org/10.15497/RDA00078&quot;&gt;Health Research Performing Organisations (HRPOs) FAIR Guidelines&lt;/a&gt; by Celia Alvarez Romero et al. This provides principles, steps, and resources to support the complex change needed to implement a data policy, which could also be applied to research software policy change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FAIR-IMPACT launched &lt;a href=&quot;https://fair-impact.eu/2nd-open-call-route-2-support&quot;&gt;open calls&lt;/a&gt; for cascading grants that provide financial support ranging from 4,000–10,000 euros. Focus areas on research software include:&lt;/li&gt;
&lt;li&gt;Path 1: Assessment and improvement of existing research software using a new extension of &lt;a href=&quot;https://www.f-uji.net/&quot;&gt;F-UJI&lt;/a&gt; (a web service to assess FAIRness of research objects).&lt;/li&gt;
&lt;li&gt;Path 2: Implementation of the Research Software MetaData Guidelines for better archiving, referencing, describing, and citing research software artefacts.&lt;/li&gt;
&lt;li&gt;The German Research Council (DFG) issued a &lt;a href=&quot;https://www.dfg.de/de/aktuelles/neuigkeiten-themen/info-wissenschaft/2022/info-wissenschaft-22-85&quot;&gt;Call for Proposals to Increase the Usability of Existing Research Software&lt;/a&gt; that refers to the FAIR4RS Principles in terms of availability and reproducibility.&lt;/li&gt;
&lt;li&gt;The German Ministry of Education and Research (BMBF) issued funding guidelines (in German) for &lt;a href=&quot;https://www.bmbf.de/bmbf/shareddocs/bekanntmachungen/de/2023/10/2023-10-13-Bekanntmachung-Datentreuhandmodelle.html&quot;&gt;developing data custodian models&lt;/a&gt; that refer to standards based on the FAIR4RS Principles for reusable and well-documented open source software developed under this program.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Communities that are normalising adoption:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The RDA &lt;a href=&quot;https://www.rd-alliance.org/groups/software-source-code-ig&quot;&gt;Software Source Code Interest Group&lt;/a&gt; provides a forum to discuss issues on management, sharing, discovery, archival and provenance of software source code. In October 2023 the &lt;a href=&quot;https://www.rd-alliance.org/plenaries/international-data-week-2023-salzburg/mastering-art-research-software-metadata-and-metrics&quot;&gt;group session&lt;/a&gt; at the RDA Plenary included a focus on the FAIR-IMPACT Metrics for Assessing Research Software FAIRness (&lt;a href=&quot;https://www.youtube.com/watch?v=whfFF1tMdlk&quot;&gt;recording&lt;/a&gt;). In addition, this group is the maintenance home for the FAIR4RS Principles.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; included a working group focused on implementation of the FAIR4RS Principles, which review the FAIR4RS Principles per the interests of research software funders, to identify gaps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.1371/journal.pcbi.1011668&quot;&gt;Ten simple rules for starting FAIR discussions in your community&lt;/a&gt; presents guidance and recommendations on how to start up discussions around the implementation of the FAIR Principles and creation of standardised ways of working. Whilst not specific to FAIR4RS Principles, these recommendations can assist in providing understanding of the benefits and barriers of standardisation are, and will support a more effective way of engaging the community.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Training to develop relevant skills:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.x-omics.nl/&quot;&gt;Netherlands X-omics Initiative&lt;/a&gt; has created &lt;a href=&quot;https://doi.org/10.1371/journal.pcbi.1011369&quot;&gt;Ten quick tips for building FAIR workflows&lt;/a&gt;, which provides practical recommendations for implementation of the FAIR4RS Principles when creating computational workflows.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.1038/s41597-023-02463-x&quot;&gt;Making Biomedical Research Software FAIR: Actionable Step-by-step Guidelines with a User-support Tool&lt;/a&gt; assists biomedical researchers to make their research software compliant with the FAIR4RS Principles. The FAIR Biomedical Research Software (FAIR-BioRS) guidelines are based on the FAIR4RS Principles and a workflow that streamlines the process of implementing these guidelines is also provided.&lt;/li&gt;
&lt;li&gt;The Netherlands eScience Center is developing and piloting the ⁠&lt;a href=&quot;https://esciencecenter-digital-skills.github.io/software-support-essentials/&quot;&gt;Research Software Support course&lt;/a&gt; which covers the FAIR4RS Principles and provides guidance for research personnel.&lt;/li&gt;
&lt;li&gt;The Digital Competence Centre of the Delft University of Technology (TU Delft) in the Netherlands is offering a 13-week &lt;a href=&quot;https://www.tudelft.nl/library/library-voor-onderzoekers/library-voor-onderzoekers/onderzoek-starten/dcc/calls/call-fair-for-research-software-program&quot;&gt;FAIR for Research Software Program&lt;/a&gt;, which includes resources from the &lt;a href=&quot;https://coderefinery.org/lessons/core/&quot;&gt;Code Refinery&lt;/a&gt;, a project within the &lt;a href=&quot;https://neic.no/&quot;&gt;Nordic e-Infrastructure Collaboration&lt;/a&gt; (NeIC). TU Delft’s program aims to teach the essential tools for creating scientific software following the FAIR4RS Principles and how to apply them.&lt;/li&gt;
&lt;li&gt;The Data Competence Center at the Leiden University Medical Center (LUMC) aims to help researchers implement the FAIR4RS Principles by increasing software stewardship capacity.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://eatris.eu/&quot;&gt;European Infrastructure for Translational Medicine (EATRIS)&lt;/a&gt; promotes adoption of the FAIR4RS Principles by sharing practical implementation examples from and with the community via its &lt;a href=&quot;https://motbx.eatris.eu/resource-category/data-analysis/&quot;&gt;Multi-omics Toolbox (MOTBX)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The Alliance’s &lt;a href=&quot;https://zenodo.org/records/10214741&quot;&gt;National Research Software Strategy 2023&lt;/a&gt; recommends FAIR4RS as a key element underlying training &amp;#x26; support initiatives for research software, which will be included in the forthcoming national training framework and resourced appropriately.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-b266afe9.uw4ObQiP_Z12DS94.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ohlrogge&quot;&gt;Niklas Ohlrogge&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Infrastructure that provide supporting tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FAIR-IMPACT’s release of &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.10047400&quot;&gt;Metrics for automated FAIR software assessment in a disciplinary context&lt;/a&gt; defines 17 metrics that can be used to automate the assessment of research software against the FAIR4RS Principles, and provides examples of how these might be implemented in one exemplar disciplinary context of the social sciences. The FAIR-IMPACT project will work to implement the metrics as practical tests by extending existing assessment tools such as F-UJI.&lt;/li&gt;
&lt;li&gt;Horizon Europe’s &lt;a href=&quot;https://everse.software/&quot;&gt;European Virtual Institute for Research Software Excellence&lt;/a&gt; (EVERSE) aims to create a framework for research software and code excellence, that are collaboratively designed and championed by the research communities. EVERSE will also continue the work of FAIR-IMPACT by developing and implementing processes and tools that support the assessment and verification of code quality, based on established best practices and standards across scientific communities.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.biorxiv.org/content/biorxiv/early/2022/05/05/2022.05.04.490563.full.pdf&quot;&gt;FAIRsoft&lt;/a&gt; is a practical implementation of the FAIR4RS Principles, and the &lt;a href=&quot;https://f1000research.com/posters/12-614&quot;&gt;FAIRsoft evaluator&lt;/a&gt; is a tool for developers and users to assess how specific software complies with FAIR for software indicators. It is part of the ELIXIR’s OpenEbench Software Observatory, an instrument for the systematic observation and diagnosis of the quality of research software in the life sciences.&lt;/li&gt;
&lt;li&gt;FAIR-Impact’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.8199104&quot;&gt;Guidelines for recommended metadata standard for research software within EOSC&lt;/a&gt; acknowledges the rising need for establishing software metadata guidelines to effectively collect and curate metadata. A comprehensive set of Research Software MetaData (RSMD) Guidelines are provided that offer flexible and adaptable recommendations for end-users that can be used in different disciplines and different software development contexts. The guidelines are directly relevant to end users, including software creators and curators in their quest to improve the FAIRness of their software.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://elixir-europe.org/platforms/tools/software-best-practices&quot;&gt;ELIXIR Software Best Practices&lt;/a&gt; group, &lt;a href=&quot;https://www.nfdi4datascience.de/&quot;&gt;NFDI4DataScience&lt;/a&gt; and &lt;a href=&quot;https://bioschemas.org&quot;&gt;Bioschemas&lt;/a&gt; are collaborating together to support machine-actionable SMPs which are aligned to the &lt;a href=&quot;https://doi.org/10.37044/osf.io/k8znb&quot;&gt;ELIXIR Software Management Plan for Life Sciences published by ELIXIR&lt;/a&gt;; and also aligned to other initiatives but also to others, such as the &lt;a href=&quot;https://doi.org/10.5281/zenodo.7248877&quot;&gt;practical guide to SMPs&lt;/a&gt; by the Dutch Research Council (NWO) and the Netherlands eScience Center, and the &lt;a href=&quot;https://rdm.mpdl.mpg.de/2022/12/09/smp-template-available/&quot;&gt;SMP template&lt;/a&gt; by the Max Planck Digital Library.&lt;/li&gt;
&lt;li&gt;A new version of the machine-actionable Software Management Plan Ontology (maSMP Ontology) metadata schema, &lt;a href=&quot;https://doi.org/10.5281/zenodo.10582073&quot;&gt;vr2.1.0&lt;/a&gt;, was released in January 2024, together with &lt;a href=&quot;https://doi.org/10.5281/zenodo.10582121&quot;&gt;usage guidance about the properties&lt;/a&gt; (profiles, guides on minimum, recommended and optional properties with cardinalities). The metadata schema includes entities involved in software management planning; such as an SMP itself, software source code, software release, documentation, authors and their relations. Integration into Bioschemas is still pending.&lt;/li&gt;
&lt;li&gt;A metadata enrichment cycle aligned to the maSMP metadata schema has been proposed by ELIXIR thanks to the &lt;a href=&quot;https://smw.ds-wizard.org/&quot;&gt;Software Management Wizard&lt;/a&gt;, a tool to make completion of SMPs easier. A &lt;a href=&quot;https://doi.org/10.5281/zenodo.10374839&quot;&gt;similar effort&lt;/a&gt; is within the scope of &lt;a href=&quot;https://www.nfdi4datascience.de/&quot;&gt;NFDI4DataScience&lt;/a&gt; and the &lt;a href=&quot;https://rdm.mpdl.mpg.de/2022/12/09/smp-template-available/&quot;&gt;Research Data Management Organiser (RDMO) SMP&lt;/a&gt;. This approach reuses a command-based tool to extract metadata from GitHub repositories, &lt;a href=&quot;https://doi.org/10.5281/zenodo.8147418&quot;&gt;SOMEF&lt;/a&gt;, which is currently being extended to cover the maSMP metadata schema case.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://faircore4eosc.eu/eosc-core-components/eosc-research-software-apis-and-connectors-rsac&quot;&gt;Research Software APIs and Connectors&lt;/a&gt; project within the FAIRCORE4EOSC project is working on developing tools and services for archival, reference, description, and citation of research software artefacts. This implements the key recommendations of the &lt;a href=&quot;https://data.europa.eu/doi/10.2777/28598&quot;&gt;Scholarly Infrastructures of Research Software&lt;/a&gt; report to interconnect scholarly repositories, publishers, and aggregators. Interconnections are possible with the Software Heritage universal source code archive, using the CodeMeta standard, and the Software Heritage intrinsic identifiers (SWHID). Instructions on how to &lt;a href=&quot;https://faircore4eosc.eu/events/webinar-archive-your-software-software-heritage-example-eosc-core-service&quot;&gt;archive your software to Software Heritage&lt;/a&gt; is one outcome.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benevol2022.github.io/papers/SlingerJansen.pdf&quot;&gt;FAIRSECO: An Extensible Framework for Impact Measurement of Research Software&lt;/a&gt; aims to enable research software engineers to rapidly find and extract relevant software fragments from the worldwide research software ecosystem.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2401.08804&quot;&gt;Towards a Quality Indicator for Research Data publications and Research Software publications — A vision from the Helmholtz Association&lt;/a&gt; develops indicators to be used within the Association. It presents a quality assessment spanning six dimensions of research software quality that augments the four FAIR principles with two additional indicators: Scientific basis and Technical basis, resulting in the FAIR-ST framework.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://ardc.edu.au/article/new-self-assessment-tool-to-promote-fair-research-software/#:~:text=Developed%20by%20the%20Netherlands%20eScience,interoperability%20and%20reusability%20(FAIR).&quot;&gt;self-assessment tool to promote FAIR research software&lt;/a&gt; has been developed by the Netherlands eScience Center and Australian Research Data Commons, to encourage the uptake of the FAIR4RS Principles (and see the 2022 &lt;a href=&quot;https://doi.org/10.5281/zenodo.6374598&quot;&gt;Survey on Adoption Guidelines for the FAIR4RS Principles&lt;/a&gt; for more resources).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git.opencarp.org/openCARP/openCARP-CI&quot;&gt;openCARP-CI&lt;/a&gt; provides Python scripts that allow developers to automatically derive CFF and DataCite files from a CodeMeta file. These pipelines can easily be integrated in continuous integration and deployment environments. They also provide tools for software publication via tagged releases, creation of BagIt and BagPack files, and publication on the research data repository RADAR.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3id.org/codemeta/v3.0&quot;&gt;CodeMeta-3.0&lt;/a&gt;: The minimal metadata schema for science software and code, in JSON-LD, provides a possibility to developers and researchers to insert metadata in their code and increase FAIRness.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2402.02824&quot;&gt;FAIR-USE4OS: From open source to Open Source&lt;/a&gt; by Raphael Sonabend et al., extends the FAIR4RS Principles to provide criteria for assessing if software is Open Source. By adding ‘USE’ (User-Centred, Sustainable, Equitable), software development can adhere to open source best practice by incorporating user-input early on, ensuring front-end designs are accessible to all possible stakeholders, and planning long-term sustainability alongside software design.&lt;/li&gt;
&lt;li&gt;FAIR4RS has also been discussed within the scope of Open Science and software quality, for instance the &lt;a href=&quot;https://eosc.eu/advisory-groups/infrastructures-quality-research-software/&quot;&gt;EOSC Task Force Infrastructures for Quality Research Software&lt;/a&gt; compiled &lt;a href=&quot;https://zenodo.org/records/10723608&quot;&gt;software quality metrics&lt;/a&gt; and identified those that can be aligned to the FAIR4RS Principles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Other impacts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The publication of the FAIR4RS principles and introductory articles created awareness and raised interest in the research community, reflected in over 200 citations from across the disciplinary spectrum. Examples include the results of searches on Google Scholar for “&lt;a href=&quot;https://scholar.google.com/scholar?cluster=15311589062181606409&amp;#x26;hl=en&amp;#x26;as_sdt=2005&amp;#x26;sciodt=0%2C5&quot;&gt;FAIR principles for research software (FAIR4RS principles)&lt;/a&gt;” or “ &lt;a href=&quot;https://scholar.google.com/scholar?cites=438298512771465318&quot;&gt;Introducing the FAIR Principles for research software&lt;/a&gt;”. In addition to work discussing trans-disciplinary application of the FAIR4RS Principles, there are research policy and software management publications referring to and implementing the FAIR4RS Principles.&lt;/p&gt;
&lt;p&gt;The FAIR4RS Principles have also provided value to the broader research ecosystem by providing a base for other communities to adapt the FAIR Principles to different research objects. Examples include &lt;a href=&quot;https://doi.org/10.1088/2632-2153/ad12e3&quot;&gt;FAIR AI Models in High Energy Physics&lt;/a&gt;, which provides a practical definition of FAIR principles for machine learning and artificial intelligence models in experimental high energy physics, including a FAIR AI project template; and the Open Modeling Foundation’s work to identify, develop, and promote common standards and best practices for &lt;a href=&quot;https://doi.org/10.1016/j.envsoft.2022.105496&quot;&gt;FAIR modelling&lt;/a&gt;, by working with model organisations and individuals active within the social, ecological, environmental, and geophysical sciences.&lt;/p&gt;
&lt;p&gt;This blog was cross-posted across several platforms and originally published at *&lt;a href=&quot;https://www.researchsoft.org/blog/2024-03/&quot;&gt;&lt;em&gt;https://www.researchsoft.org/blog/2024-03/&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 19 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;*By &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-3623-172X&quot;&gt;&lt;em&gt;Michelle Barker&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0003-3986-0510&quot;&gt;&lt;em&gt;Leyla Jael Castro&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-0690-7151&quot;&gt;&lt;em&gt;Bernadette Fritzsch&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0001-5934-7525&quot;&gt;&lt;em&gt;Daniel S. Katz&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-9839-5439&quot;&gt;&lt;em&gt;Anna Niehues&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://orcid.org/0000-0002-1173-9228&quot;&gt;&lt;em&gt;Alexander Struck&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, *&lt;a href=&quot;https://orcid.org/0000-0003-1549-7358&quot;&gt;&lt;em&gt;Qian Zhang&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.10816031&quot;&gt;here&lt;/a&gt; for citation information for this article.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;FAIR for Research Software (FAIR4RS) Principles&lt;/a&gt; aim to promote and encourage the findability, accessibility, interoperability, and reusability (FAIR) of research software. The FAIR4RS Principles were &lt;a href=&quot;https://doi.org/10.15497/RDA00068&quot;&gt;released&lt;/a&gt; in 2022, with a number of organisations already &lt;a href=&quot;https://doi.org/10.5281/zenodo.6258366&quot;&gt;planning adoption&lt;/a&gt; at that time. Adoption and implementation of the FAIR4RS Principles can increase the transparency, reproducibility, and reusability of research by providing research software that can be executed, replicated, built-upon, combined, reinterpreted, reimplemented, and/or used in different settings and by third-parties.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-04751d5e.RZ7SqTJp_Zxzr3j.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@familyschaffner&quot;&gt;Astrid Schaffner&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This blog post provides an update on initiatives that are working to implement the principles across five areas of cultural change: policies, incentives, communities, training and infrastructure. It is noted that while many activities are increasing aspects of the FAIRness of research software, more work is still needed to make it easier to embrace the FAIR4RS Principles in their entirety.&lt;/p&gt;
&lt;p&gt;A framework for tracking adoption**&lt;/p&gt;
&lt;p&gt;The release of the FAIR4RS Principles succeeded in raising the profile of research software in FAIR initiatives, which have mostly been focused on FAIR data. Examples can be found across a range of initiatives, using a slightly adapted version of the five elements of Brian Nosek’s &lt;a href=&quot;http://www.cos.io/blog/strategy-for-culture-change&quot;&gt;strategy for culture change&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Policy&lt;/strong&gt; — make it required&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incentives&lt;/strong&gt; — make it rewarding&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Communities&lt;/strong&gt; — make it normative&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training&lt;/strong&gt; — make it easy (this replaces user interface/experience in Nosek’s version)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt; — make it possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To achieve culture change, initiatives are needed across all of the five elements. Whilst in the early stages, some elements can progress more quickly than others. For example, it’s difficult to implement policy requirements if infrastructure and training (and preferably incentives) aren’t already in place. Similarly, for tools evaluating FAIRness to be useful, changes in major infrastructures such as code hosting repositories are first required so that researchers can create the metadata files that evaluations may depend upon.&lt;/p&gt;
&lt;p&gt;It should be noted that while the many activities listed here support increasing FAIRness of research software, most of them do not address aspects of all four of the FAIRness of research software foundational principles:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Findable (F):&lt;/strong&gt; Software, and its associated metadata, is easy for both humans and machines to find.&lt;/p&gt;
&lt;p&gt;**Accessible (A): **Software, and its metadata, is retrievable via standardised protocols.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interoperable (I):&lt;/strong&gt; Software interoperates with other software by exchanging data and/or metadata, and/or through interaction via application programming interfaces (APIs), described through standards.&lt;/p&gt;
&lt;p&gt;**Reusable (R): **Software is both usable (can be executed) and reusable (can be understood, modified, built upon, or incorporated into other software).&lt;/p&gt;
&lt;p&gt;This reflects that the FAIR4RS Principles are aspirational and high-level, and do not contain detailed guidance on how to achieve them. This is because specific technologies and tools are always changing, while the principles are intended to be long-lasting. Consequently, additional work is needed to make it simpler for people wanting to follow the FAIR4RS Principles to know how to practically do so. The following initiatives are assisting in achieving this, with some of these initiatives specifically addressing the range of &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;opportunities for future work&lt;/a&gt; identified in 2022 by the FAIR4RS Working Group, which developed the FAIR4RS Principles. These opportunities include “metadata and identifier authority, metadata vocabularies and metadata properties, software identifiers, domain-relevant community standards for software and identification targets”. Whilst some of the initiatives identified in the infrastructure section below are contributing to this, more work still needs to be done.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-5c22575d.0k3l96rK_Z1WBg88.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@alexabero?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Alexander Abero&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Policies that encourage implementation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and the &lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;Dutch Research Council&lt;/a&gt; (NWO) formed a working group that developed &lt;a href=&quot;https://doi.org/10.5281/zenodo.7589725&quot;&gt;national guidelines for software management plans&lt;/a&gt;. Research institutions such as the University of Groningen’s Digital Competence Center link to this resource in its guidance for its researchers on &lt;a href=&quot;https://www.rug.nl/digital-competence-centre/research-data/research-software-management/research-software-management-plan?lang=en&quot;&gt;research software management plans&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.esciencecenter.nl/download/51726/?tmstv=1695732347&quot;&gt;Software Management Plan Template&lt;/a&gt; of the Netherlands eScience Center has been updated to align and address the FAIR4RS Principles, and emphasises that open science, software quality, and software sustainability are key elements in eScience Center projects. A total of 13 eScience Center projects (11 under the Open eScience call 2023 (OEC2023) and 2 under the Software Sustainability call 2023 (SS2023)) are now using this template.&lt;/li&gt;
&lt;li&gt;Maastricht University in the Netherlands has an &lt;a href=&quot;https://www.maastrichtuniversity.nl/file/um-open-science-policy-update-2022-v13pdf&quot;&gt;Open Science @UM policy&lt;/a&gt;, which includes FAIR software as one of its seven areas. Maastricht University proposes to inventory current practices in storage, sharing and reuse of software; and then identify gaps in awareness, knowledge and/or support on FAIR software. Actions likely to be taken include promotion of the creation of software management plans to ensure responsible use of research software.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.17605/OSF.IO/NW42B&quot;&gt;Enabling FAIR Workflows — Key actors and actions&lt;/a&gt; by the Open Research Funders Group outlines steps for different actors in the research community to take to embed sharing practices, persistent identifiers, and metadata throughout the research lifecycle. This report references the FAIR4RS Principles in its recommendations on depositing research software.&lt;/li&gt;
&lt;li&gt;The German Research Council (DFG) published &lt;a href=&quot;https://www.dfg.de/resource/blob/168500/a5f52374b2b21a184b9db9e48f411e9d/60-14-en-data.pdf&quot;&gt;guidelines for reviewing grant proposals&lt;/a&gt; for Collaborative Research Centers (CRC/SFB) and suggested compliance with the FAIR4RS Principles for archiving and reuse.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; (the Alliance) published the &lt;a href=&quot;https://zenodo.org/records/10214741&quot;&gt;National Research Software Strategy 2023&lt;/a&gt;. This proposes a set of strategic goals for advancing research software capability, community, and coordination in Canada for 2025–2030, with the FAIR4RS Principles providing a cross-cutting theme. The Alliance is developing a Software Management Plan (SMP) template to promote, cultivate and implement best practices, with an emphasis on the FAIR4RS Principles, for Canadian researchers. The goal is to implement the SMP template in future grant applications.Resources that support inclusion of FAIR into institutional policies are also relevant. The list of &lt;a href=&quot;https://www.researchsoft.org/software-policies/&quot;&gt;research institutional policies&lt;/a&gt; that support research software, curated by the Research Software Alliance (ReSA), is part of ongoing work by the joint ReSA and Research Data Alliance (RDA) &lt;a href=&quot;https://www.rd-alliance.org/groups/policies-research-organisations-research-software-pro4rs&quot;&gt;Policies in Research Organisations for Research Software (PRO4RS) Working Group&lt;/a&gt; to create a community of stakeholders involved in promoting and/or implementing policy that supports research software at the research institution level (such as universities, national laboratories).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This includes curation of resources on how to influence policy change, such as &lt;a href=&quot;https://doi.org/10.15497/RDA00078&quot;&gt;Health Research Performing Organisations (HRPOs) FAIR Guidelines&lt;/a&gt; by Celia Alvarez Romero et al. This provides principles, steps, and resources to support the complex change needed to implement a data policy, which could also be applied to research software policy change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FAIR-IMPACT launched &lt;a href=&quot;https://fair-impact.eu/2nd-open-call-route-2-support&quot;&gt;open calls&lt;/a&gt; for cascading grants that provide financial support ranging from 4,000–10,000 euros. Focus areas on research software include:&lt;/li&gt;
&lt;li&gt;Path 1: Assessment and improvement of existing research software using a new extension of &lt;a href=&quot;https://www.f-uji.net/&quot;&gt;F-UJI&lt;/a&gt; (a web service to assess FAIRness of research objects).&lt;/li&gt;
&lt;li&gt;Path 2: Implementation of the Research Software MetaData Guidelines for better archiving, referencing, describing, and citing research software artefacts.&lt;/li&gt;
&lt;li&gt;The German Research Council (DFG) issued a &lt;a href=&quot;https://www.dfg.de/de/aktuelles/neuigkeiten-themen/info-wissenschaft/2022/info-wissenschaft-22-85&quot;&gt;Call for Proposals to Increase the Usability of Existing Research Software&lt;/a&gt; that refers to the FAIR4RS Principles in terms of availability and reproducibility.&lt;/li&gt;
&lt;li&gt;The German Ministry of Education and Research (BMBF) issued funding guidelines (in German) for &lt;a href=&quot;https://www.bmbf.de/bmbf/shareddocs/bekanntmachungen/de/2023/10/2023-10-13-Bekanntmachung-Datentreuhandmodelle.html&quot;&gt;developing data custodian models&lt;/a&gt; that refer to standards based on the FAIR4RS Principles for reusable and well-documented open source software developed under this program.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Communities that are normalising adoption:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The RDA &lt;a href=&quot;https://www.rd-alliance.org/groups/software-source-code-ig&quot;&gt;Software Source Code Interest Group&lt;/a&gt; provides a forum to discuss issues on management, sharing, discovery, archival and provenance of software source code. In October 2023 the &lt;a href=&quot;https://www.rd-alliance.org/plenaries/international-data-week-2023-salzburg/mastering-art-research-software-metadata-and-metrics&quot;&gt;group session&lt;/a&gt; at the RDA Plenary included a focus on the FAIR-IMPACT Metrics for Assessing Research Software FAIRness (&lt;a href=&quot;https://www.youtube.com/watch?v=whfFF1tMdlk&quot;&gt;recording&lt;/a&gt;). In addition, this group is the maintenance home for the FAIR4RS Principles.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; included a working group focused on implementation of the FAIR4RS Principles, which review the FAIR4RS Principles per the interests of research software funders, to identify gaps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.1371/journal.pcbi.1011668&quot;&gt;Ten simple rules for starting FAIR discussions in your community&lt;/a&gt; presents guidance and recommendations on how to start up discussions around the implementation of the FAIR Principles and creation of standardised ways of working. Whilst not specific to FAIR4RS Principles, these recommendations can assist in providing understanding of the benefits and barriers of standardisation are, and will support a more effective way of engaging the community.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Training to develop relevant skills:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.x-omics.nl/&quot;&gt;Netherlands X-omics Initiative&lt;/a&gt; has created &lt;a href=&quot;https://doi.org/10.1371/journal.pcbi.1011369&quot;&gt;Ten quick tips for building FAIR workflows&lt;/a&gt;, which provides practical recommendations for implementation of the FAIR4RS Principles when creating computational workflows.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.1038/s41597-023-02463-x&quot;&gt;Making Biomedical Research Software FAIR: Actionable Step-by-step Guidelines with a User-support Tool&lt;/a&gt; assists biomedical researchers to make their research software compliant with the FAIR4RS Principles. The FAIR Biomedical Research Software (FAIR-BioRS) guidelines are based on the FAIR4RS Principles and a workflow that streamlines the process of implementing these guidelines is also provided.&lt;/li&gt;
&lt;li&gt;The Netherlands eScience Center is developing and piloting the ⁠&lt;a href=&quot;https://esciencecenter-digital-skills.github.io/software-support-essentials/&quot;&gt;Research Software Support course&lt;/a&gt; which covers the FAIR4RS Principles and provides guidance for research personnel.&lt;/li&gt;
&lt;li&gt;The Digital Competence Centre of the Delft University of Technology (TU Delft) in the Netherlands is offering a 13-week &lt;a href=&quot;https://www.tudelft.nl/library/library-voor-onderzoekers/library-voor-onderzoekers/onderzoek-starten/dcc/calls/call-fair-for-research-software-program&quot;&gt;FAIR for Research Software Program&lt;/a&gt;, which includes resources from the &lt;a href=&quot;https://coderefinery.org/lessons/core/&quot;&gt;Code Refinery&lt;/a&gt;, a project within the &lt;a href=&quot;https://neic.no/&quot;&gt;Nordic e-Infrastructure Collaboration&lt;/a&gt; (NeIC). TU Delft’s program aims to teach the essential tools for creating scientific software following the FAIR4RS Principles and how to apply them.&lt;/li&gt;
&lt;li&gt;The Data Competence Center at the Leiden University Medical Center (LUMC) aims to help researchers implement the FAIR4RS Principles by increasing software stewardship capacity.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://eatris.eu/&quot;&gt;European Infrastructure for Translational Medicine (EATRIS)&lt;/a&gt; promotes adoption of the FAIR4RS Principles by sharing practical implementation examples from and with the community via its &lt;a href=&quot;https://motbx.eatris.eu/resource-category/data-analysis/&quot;&gt;Multi-omics Toolbox (MOTBX)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The Alliance’s &lt;a href=&quot;https://zenodo.org/records/10214741&quot;&gt;National Research Software Strategy 2023&lt;/a&gt; recommends FAIR4RS as a key element underlying training &amp;#x26; support initiatives for research software, which will be included in the forthcoming national training framework and resourced appropriately.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;The FAIR for Research Software Principles after two years: an adoption update&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;468&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-b266afe9.uw4ObQiP_Z12DS94.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ohlrogge&quot;&gt;Niklas Ohlrogge&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Infrastructure that provide supporting tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FAIR-IMPACT’s release of &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.10047400&quot;&gt;Metrics for automated FAIR software assessment in a disciplinary context&lt;/a&gt; defines 17 metrics that can be used to automate the assessment of research software against the FAIR4RS Principles, and provides examples of how these might be implemented in one exemplar disciplinary context of the social sciences. The FAIR-IMPACT project will work to implement the metrics as practical tests by extending existing assessment tools such as F-UJI.&lt;/li&gt;
&lt;li&gt;Horizon Europe’s &lt;a href=&quot;https://everse.software/&quot;&gt;European Virtual Institute for Research Software Excellence&lt;/a&gt; (EVERSE) aims to create a framework for research software and code excellence, that are collaboratively designed and championed by the research communities. EVERSE will also continue the work of FAIR-IMPACT by developing and implementing processes and tools that support the assessment and verification of code quality, based on established best practices and standards across scientific communities.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.biorxiv.org/content/biorxiv/early/2022/05/05/2022.05.04.490563.full.pdf&quot;&gt;FAIRsoft&lt;/a&gt; is a practical implementation of the FAIR4RS Principles, and the &lt;a href=&quot;https://f1000research.com/posters/12-614&quot;&gt;FAIRsoft evaluator&lt;/a&gt; is a tool for developers and users to assess how specific software complies with FAIR for software indicators. It is part of the ELIXIR’s OpenEbench Software Observatory, an instrument for the systematic observation and diagnosis of the quality of research software in the life sciences.&lt;/li&gt;
&lt;li&gt;FAIR-Impact’s &lt;a href=&quot;https://doi.org/10.5281/zenodo.8199104&quot;&gt;Guidelines for recommended metadata standard for research software within EOSC&lt;/a&gt; acknowledges the rising need for establishing software metadata guidelines to effectively collect and curate metadata. A comprehensive set of Research Software MetaData (RSMD) Guidelines are provided that offer flexible and adaptable recommendations for end-users that can be used in different disciplines and different software development contexts. The guidelines are directly relevant to end users, including software creators and curators in their quest to improve the FAIRness of their software.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://elixir-europe.org/platforms/tools/software-best-practices&quot;&gt;ELIXIR Software Best Practices&lt;/a&gt; group, &lt;a href=&quot;https://www.nfdi4datascience.de/&quot;&gt;NFDI4DataScience&lt;/a&gt; and &lt;a href=&quot;https://bioschemas.org&quot;&gt;Bioschemas&lt;/a&gt; are collaborating together to support machine-actionable SMPs which are aligned to the &lt;a href=&quot;https://doi.org/10.37044/osf.io/k8znb&quot;&gt;ELIXIR Software Management Plan for Life Sciences published by ELIXIR&lt;/a&gt;; and also aligned to other initiatives but also to others, such as the &lt;a href=&quot;https://doi.org/10.5281/zenodo.7248877&quot;&gt;practical guide to SMPs&lt;/a&gt; by the Dutch Research Council (NWO) and the Netherlands eScience Center, and the &lt;a href=&quot;https://rdm.mpdl.mpg.de/2022/12/09/smp-template-available/&quot;&gt;SMP template&lt;/a&gt; by the Max Planck Digital Library.&lt;/li&gt;
&lt;li&gt;A new version of the machine-actionable Software Management Plan Ontology (maSMP Ontology) metadata schema, &lt;a href=&quot;https://doi.org/10.5281/zenodo.10582073&quot;&gt;vr2.1.0&lt;/a&gt;, was released in January 2024, together with &lt;a href=&quot;https://doi.org/10.5281/zenodo.10582121&quot;&gt;usage guidance about the properties&lt;/a&gt; (profiles, guides on minimum, recommended and optional properties with cardinalities). The metadata schema includes entities involved in software management planning; such as an SMP itself, software source code, software release, documentation, authors and their relations. Integration into Bioschemas is still pending.&lt;/li&gt;
&lt;li&gt;A metadata enrichment cycle aligned to the maSMP metadata schema has been proposed by ELIXIR thanks to the &lt;a href=&quot;https://smw.ds-wizard.org/&quot;&gt;Software Management Wizard&lt;/a&gt;, a tool to make completion of SMPs easier. A &lt;a href=&quot;https://doi.org/10.5281/zenodo.10374839&quot;&gt;similar effort&lt;/a&gt; is within the scope of &lt;a href=&quot;https://www.nfdi4datascience.de/&quot;&gt;NFDI4DataScience&lt;/a&gt; and the &lt;a href=&quot;https://rdm.mpdl.mpg.de/2022/12/09/smp-template-available/&quot;&gt;Research Data Management Organiser (RDMO) SMP&lt;/a&gt;. This approach reuses a command-based tool to extract metadata from GitHub repositories, &lt;a href=&quot;https://doi.org/10.5281/zenodo.8147418&quot;&gt;SOMEF&lt;/a&gt;, which is currently being extended to cover the maSMP metadata schema case.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://faircore4eosc.eu/eosc-core-components/eosc-research-software-apis-and-connectors-rsac&quot;&gt;Research Software APIs and Connectors&lt;/a&gt; project within the FAIRCORE4EOSC project is working on developing tools and services for archival, reference, description, and citation of research software artefacts. This implements the key recommendations of the &lt;a href=&quot;https://data.europa.eu/doi/10.2777/28598&quot;&gt;Scholarly Infrastructures of Research Software&lt;/a&gt; report to interconnect scholarly repositories, publishers, and aggregators. Interconnections are possible with the Software Heritage universal source code archive, using the CodeMeta standard, and the Software Heritage intrinsic identifiers (SWHID). Instructions on how to &lt;a href=&quot;https://faircore4eosc.eu/events/webinar-archive-your-software-software-heritage-example-eosc-core-service&quot;&gt;archive your software to Software Heritage&lt;/a&gt; is one outcome.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benevol2022.github.io/papers/SlingerJansen.pdf&quot;&gt;FAIRSECO: An Extensible Framework for Impact Measurement of Research Software&lt;/a&gt; aims to enable research software engineers to rapidly find and extract relevant software fragments from the worldwide research software ecosystem.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2401.08804&quot;&gt;Towards a Quality Indicator for Research Data publications and Research Software publications — A vision from the Helmholtz Association&lt;/a&gt; develops indicators to be used within the Association. It presents a quality assessment spanning six dimensions of research software quality that augments the four FAIR principles with two additional indicators: Scientific basis and Technical basis, resulting in the FAIR-ST framework.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://ardc.edu.au/article/new-self-assessment-tool-to-promote-fair-research-software/#:~:text=Developed%20by%20the%20Netherlands%20eScience,interoperability%20and%20reusability%20(FAIR).&quot;&gt;self-assessment tool to promote FAIR research software&lt;/a&gt; has been developed by the Netherlands eScience Center and Australian Research Data Commons, to encourage the uptake of the FAIR4RS Principles (and see the 2022 &lt;a href=&quot;https://doi.org/10.5281/zenodo.6374598&quot;&gt;Survey on Adoption Guidelines for the FAIR4RS Principles&lt;/a&gt; for more resources).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git.opencarp.org/openCARP/openCARP-CI&quot;&gt;openCARP-CI&lt;/a&gt; provides Python scripts that allow developers to automatically derive CFF and DataCite files from a CodeMeta file. These pipelines can easily be integrated in continuous integration and deployment environments. They also provide tools for software publication via tagged releases, creation of BagIt and BagPack files, and publication on the research data repository RADAR.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3id.org/codemeta/v3.0&quot;&gt;CodeMeta-3.0&lt;/a&gt;: The minimal metadata schema for science software and code, in JSON-LD, provides a possibility to developers and researchers to insert metadata in their code and increase FAIRness.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2402.02824&quot;&gt;FAIR-USE4OS: From open source to Open Source&lt;/a&gt; by Raphael Sonabend et al., extends the FAIR4RS Principles to provide criteria for assessing if software is Open Source. By adding ‘USE’ (User-Centred, Sustainable, Equitable), software development can adhere to open source best practice by incorporating user-input early on, ensuring front-end designs are accessible to all possible stakeholders, and planning long-term sustainability alongside software design.&lt;/li&gt;
&lt;li&gt;FAIR4RS has also been discussed within the scope of Open Science and software quality, for instance the &lt;a href=&quot;https://eosc.eu/advisory-groups/infrastructures-quality-research-software/&quot;&gt;EOSC Task Force Infrastructures for Quality Research Software&lt;/a&gt; compiled &lt;a href=&quot;https://zenodo.org/records/10723608&quot;&gt;software quality metrics&lt;/a&gt; and identified those that can be aligned to the FAIR4RS Principles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Other impacts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The publication of the FAIR4RS principles and introductory articles created awareness and raised interest in the research community, reflected in over 200 citations from across the disciplinary spectrum. Examples include the results of searches on Google Scholar for “&lt;a href=&quot;https://scholar.google.com/scholar?cluster=15311589062181606409&amp;#x26;hl=en&amp;#x26;as_sdt=2005&amp;#x26;sciodt=0%2C5&quot;&gt;FAIR principles for research software (FAIR4RS principles)&lt;/a&gt;” or “ &lt;a href=&quot;https://scholar.google.com/scholar?cites=438298512771465318&quot;&gt;Introducing the FAIR Principles for research software&lt;/a&gt;”. In addition to work discussing trans-disciplinary application of the FAIR4RS Principles, there are research policy and software management publications referring to and implementing the FAIR4RS Principles.&lt;/p&gt;
&lt;p&gt;The FAIR4RS Principles have also provided value to the broader research ecosystem by providing a base for other communities to adapt the FAIR Principles to different research objects. Examples include &lt;a href=&quot;https://doi.org/10.1088/2632-2153/ad12e3&quot;&gt;FAIR AI Models in High Energy Physics&lt;/a&gt;, which provides a practical definition of FAIR principles for machine learning and artificial intelligence models in experimental high energy physics, including a FAIR AI project template; and the Open Modeling Foundation’s work to identify, develop, and promote common standards and best practices for &lt;a href=&quot;https://doi.org/10.1016/j.envsoft.2022.105496&quot;&gt;FAIR modelling&lt;/a&gt;, by working with model organisations and individuals active within the social, ecological, environmental, and geophysical sciences.&lt;/p&gt;
&lt;p&gt;This blog was cross-posted across several platforms and originally published at *&lt;a href=&quot;https://www.researchsoft.org/blog/2024-03/&quot;&gt;&lt;em&gt;https://www.researchsoft.org/blog/2024-03/&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-fair-for-research-software-principle-04751d5e.RZ7SqTJp.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>How to manage your IP address in Python</title><link>https://blog.esciencecenter.nl/posts/2024-02-27---how-to-manage-your-ip-address-in-python</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-02-27---how-to-manage-your-ip-address-in-python</guid><description>&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This post is the first of a series of blog posts arising from a collaboration between the eScience Center and the ODISSEI Social Data Science Team. You can find this text also at &lt;a href=&quot;https://odissei-soda.nl/tutorials/&quot;&gt;https://odissei-soda.nl/tutorials/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Research often relies on accessing novel data, for instance by collecting them from the internet through web scraping. If you have ever tried this, you may have run into your IP address being blocked by the website you scrape. Websites do this with a good reason — to protect themselves against malicious acts, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Denial-of-service_attack&quot;&gt;denial-of-service attacks&lt;/a&gt; or large-scale scraping by parties with ill intent. This makes sense from the websites’ perspective, but prevents you from answering your research question.&lt;/p&gt;
&lt;p&gt;But this problem can be solved. In this tutorial, we show how you as a researcher can use IP rotation to circumvent certain scraping protections with the &lt;code&gt;sirup&lt;/code&gt; package, which works on Linux operating systems.&lt;/p&gt;
&lt;p&gt;Before we jump into it, it is important to highlight that web scraping and IP rotation need to respect the law and should only be a last resort. For instance, before you scrape data from a website, you should ask the data owner whether they are willing to make them available to you through a data sharing agreement. If you nevertheless decide to scrape the data, you should get approval from the ethical review board at your university. Moreover, do only scrape data that are publicly available on the web and do not send excessive number of requests to the website in a given time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-00102567.DNJxbduL_Z10scUh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@glenncarstenspeters?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Glenn Carstens-Peters&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For rotating the IP address, we will use a VPN service. &lt;a href=&quot;https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-vpn#:~:text=A%20VPN%2C%20which%20stands%20for,and%20firewalls%20on%20the%20internet.&quot;&gt;Here&lt;/a&gt; you can read more about what a VPN service is—in short, the service has a bunch of remote servers, and connecting your computer to one of these servers changes your IP address.&lt;/p&gt;
&lt;h2 id=&quot;what-you-need&quot;&gt;What you need&lt;/h2&gt;
&lt;h2 id=&quot;1-openvpn&quot;&gt;1. &lt;code&gt;OpenVPN&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/OpenVPN&quot;&gt;OpenVPN&lt;/a&gt; is a system that allows you to create secure VPN connections. You can install it by following &lt;a href=&quot;https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos&quot;&gt;these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;2-root-access-to-your-computer&quot;&gt;2. Root access to your computer&lt;/h2&gt;
&lt;p&gt;Because internet connections are an important security concern, OpenVPN requires root access — this is the equivalent to administrator rights on a Windows computer. If you have root access, you can for instance run the following command on your terminal:&lt;/p&gt;
&lt;p&gt;sudo ls -lh # will ask you for your root password&lt;/p&gt;
&lt;h2 id=&quot;installing-and-setting-up-sirup&quot;&gt;Installing and setting up &lt;code&gt;sirup&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can install &lt;code&gt;sirup&lt;/code&gt; as follows:&lt;/p&gt;
&lt;p&gt;python -m pip install sirupTo use the package and change your IP address, you need an account with a VPN service provider that offers OpenVPN configuration files for your account. At the time of writing, for instance ProtonVPN and Surfshark offer this option — note that these services are not for free. We will use ProtonVPN in this tutorial.&lt;/p&gt;
&lt;p&gt;After creating an account, you need to download two sets of files.&lt;/p&gt;
&lt;p&gt;First, you download credentials that identify your Proton account when using OpenVPN. On the ProtonVPN website, click on “Account” and then you see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;315&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-0efd650a.BooFlCCP_Z1Lvn1G.webp&quot; srcset=&quot;&quot;&gt;
Copy and paste the username and the password into a &lt;code&gt;txt&lt;/code&gt; file that looks like this:&lt;/p&gt;
&lt;p&gt;username
passwordThen, save the file as “proton_credentials.txt”. Remember where it is stored — we will need it later.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A first warning on security. **Storing account credentials like this makes it easy for you to use the sirup package. But it also increases the risk that unauthorized persons get a hold on these credentials. Thus, be careful to store the credentials in a safe place on your laptop and to not share them with anyone.&lt;/p&gt;
&lt;p&gt;Second, to use OpenVPN we need configuration files, whose names end with &lt;code&gt;.ovpn&lt;/code&gt;. The files allow OpenVPN to connect to a server from the VPN service provider. In ProtonVPN, go to the “Download” section of your account. Select the options as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;509&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-1c18ffaf.BfZTWBsr_Q79VL.webp&quot; srcset=&quot;&quot;&gt;
And download the configuration file(s) you want to use. Store the downloaded files on your computer, and remember the location.&lt;/p&gt;
&lt;h2 id=&quot;using-sirup&quot;&gt;Using &lt;code&gt;sirup&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We start by defining the path to the &lt;code&gt;proton_credentials.txt&lt;/code&gt; file. When you execute the code below, you will be asked to enter the root password, which is necessary to make the connection.&lt;/p&gt;
&lt;p&gt;import getpass
auth_file = “proton_credentials.txt”
pwd = getpass.getpass(“Please enter your root password:”)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A second warning on security.** The code above stores your root password during the Python session without encrypting it. This is OK to do on your laptop — if someone gets access to your Python session, your security has already been compromised — but not recommended on a shared computer such as a cluster or a cloud service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;changing-the-ip-address-with-sirup&quot;&gt;Changing the IP address with &lt;code&gt;sirup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now you can use the &lt;code&gt;VPNConnector&lt;/code&gt; to change our IP address. We will use the &lt;code&gt;&quot;my_config_file.ovpn&quot;&lt;/code&gt; configuration file.&lt;/p&gt;
&lt;p&gt;from sirup.VPNConnector import VPNConnector
config_file = “my_config_file.ovpn”The code below first connects to the server associated with &lt;code&gt;&quot;my_config_file.ovpn&quot;&lt;/code&gt; and then disconnects.&lt;/p&gt;
&lt;p&gt;connector = VPNConnector(auth_file, config_file)&lt;/p&gt;
&lt;h1 id=&quot;lets-see-the-current-ip-address-when-no-vpn-tunnel-is-active&quot;&gt;Let’s see the current IP address when no VPN tunnel is active&lt;/h1&gt;
&lt;p&gt;print(connector.base_ip)&lt;/p&gt;
&lt;p&gt;connector.connect(pwd=pwd)&lt;/p&gt;
&lt;h1 id=&quot;now-the-ip-address-should-differ&quot;&gt;Now the IP address should differ&lt;/h1&gt;
&lt;p&gt;print(connector.current_ip)&lt;/p&gt;
&lt;p&gt;connector.disconnect(pwd=pwd)&lt;/p&gt;
&lt;h1 id=&quot;now-current_ip-should-be-the-same-as-base_ip-above&quot;&gt;Now current_ip should be the same as base_ip above&lt;/h1&gt;
&lt;p&gt;print(connector.current_ip)&lt;/p&gt;
&lt;h3 id=&quot;rotating-the-ip-address-with-sirup&quot;&gt;Rotating the IP address with &lt;code&gt;sirup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Instead of connecting to a single server, you can also rotate across many different servers — which means you rotate your IP address across a set of potential addresses. Doing so is useful for larger scraping jobs because it will spread your requests across more servers.&lt;/p&gt;
&lt;p&gt;To do this, you need to download multiple configuration files as described above. Store all of the &lt;code&gt;.ovpn&lt;/code&gt; configuration files together in a separate directory. Let’s say you store them in the &lt;code&gt;&quot;/path/to/config/files/&quot;&lt;/code&gt; directory. You need to define this path in your Python script:&lt;/p&gt;
&lt;p&gt;config_path = “/path/to/config/files/“The following code connects to two different servers before disconnecting again:&lt;/p&gt;
&lt;p&gt;from sirup.IPRotator import IPRotator&lt;/p&gt;
&lt;p&gt;rotator = IPRotator(auth_file=my_auth_file, config_location=config_path, seed=seed) # this will ask for the root password&lt;/p&gt;
&lt;p&gt;print(rotator.connector.base_ip)&lt;/p&gt;
&lt;p&gt;rotator.connect()
print(rotator.connector.current_ip)&lt;/p&gt;
&lt;p&gt;rotator.rotate()
print(rotator.connector.current_ip)&lt;/p&gt;
&lt;p&gt;rotator.disconnect()&lt;/p&gt;
&lt;p&gt;print(rotator.connector.current_ip)&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This tutorial has walked you through the steps to manage your IP address in Python, using the &lt;code&gt;sirup&lt;/code&gt; package. We hope it makes your scraping workflows easier!&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;sirup&lt;/code&gt; is an open-source package developed by the Netherlands eScience Center. If you use the tool, you can cite &lt;a href=&quot;https://zenodo.org/records/10261949&quot;&gt;this zenodo repository&lt;/a&gt; with the DOI: &lt;a href=&quot;https://doi.org/10.5281/zenodo.10261949&quot;&gt;https://doi.org/10.5281/zenodo.10261949&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The source code of the package is &lt;a href=&quot;https://github.com/ivory-tower-private-power/sirup?tab=readme-ov-file&quot;&gt;here&lt;/a&gt;, where you can contribute to it, build on it and submit issues.&lt;/p&gt;
&lt;p&gt;Thanks to Patrick Bos, Peter Kalverla, Kody Moodley and Carlos Gonzalez Poses for comments.&lt;/p&gt;</description><pubDate>Tue, 27 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This post is the first of a series of blog posts arising from a collaboration between the eScience Center and the ODISSEI Social Data Science Team. You can find this text also at &lt;a href=&quot;https://odissei-soda.nl/tutorials/&quot;&gt;https://odissei-soda.nl/tutorials/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Research often relies on accessing novel data, for instance by collecting them from the internet through web scraping. If you have ever tried this, you may have run into your IP address being blocked by the website you scrape. Websites do this with a good reason — to protect themselves against malicious acts, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Denial-of-service_attack&quot;&gt;denial-of-service attacks&lt;/a&gt; or large-scale scraping by parties with ill intent. This makes sense from the websites’ perspective, but prevents you from answering your research question.&lt;/p&gt;
&lt;p&gt;But this problem can be solved. In this tutorial, we show how you as a researcher can use IP rotation to circumvent certain scraping protections with the &lt;code&gt;sirup&lt;/code&gt; package, which works on Linux operating systems.&lt;/p&gt;
&lt;p&gt;Before we jump into it, it is important to highlight that web scraping and IP rotation need to respect the law and should only be a last resort. For instance, before you scrape data from a website, you should ask the data owner whether they are willing to make them available to you through a data sharing agreement. If you nevertheless decide to scrape the data, you should get approval from the ethical review board at your university. Moreover, do only scrape data that are publicly available on the web and do not send excessive number of requests to the website in a given time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-00102567.DNJxbduL_Z10scUh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@glenncarstenspeters?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Glenn Carstens-Peters&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For rotating the IP address, we will use a VPN service. &lt;a href=&quot;https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-vpn#:~:text=A%20VPN%2C%20which%20stands%20for,and%20firewalls%20on%20the%20internet.&quot;&gt;Here&lt;/a&gt; you can read more about what a VPN service is—in short, the service has a bunch of remote servers, and connecting your computer to one of these servers changes your IP address.&lt;/p&gt;
&lt;h2 id=&quot;what-you-need&quot;&gt;What you need&lt;/h2&gt;
&lt;h2 id=&quot;1-openvpn&quot;&gt;1. &lt;code&gt;OpenVPN&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/OpenVPN&quot;&gt;OpenVPN&lt;/a&gt; is a system that allows you to create secure VPN connections. You can install it by following &lt;a href=&quot;https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos&quot;&gt;these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;2-root-access-to-your-computer&quot;&gt;2. Root access to your computer&lt;/h2&gt;
&lt;p&gt;Because internet connections are an important security concern, OpenVPN requires root access — this is the equivalent to administrator rights on a Windows computer. If you have root access, you can for instance run the following command on your terminal:&lt;/p&gt;
&lt;p&gt;sudo ls -lh # will ask you for your root password&lt;/p&gt;
&lt;h2 id=&quot;installing-and-setting-up-sirup&quot;&gt;Installing and setting up &lt;code&gt;sirup&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can install &lt;code&gt;sirup&lt;/code&gt; as follows:&lt;/p&gt;
&lt;p&gt;python -m pip install sirupTo use the package and change your IP address, you need an account with a VPN service provider that offers OpenVPN configuration files for your account. At the time of writing, for instance ProtonVPN and Surfshark offer this option — note that these services are not for free. We will use ProtonVPN in this tutorial.&lt;/p&gt;
&lt;p&gt;After creating an account, you need to download two sets of files.&lt;/p&gt;
&lt;p&gt;First, you download credentials that identify your Proton account when using OpenVPN. On the ProtonVPN website, click on “Account” and then you see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;315&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-0efd650a.BooFlCCP_Z1Lvn1G.webp&quot; srcset=&quot;&quot;&gt;
Copy and paste the username and the password into a &lt;code&gt;txt&lt;/code&gt; file that looks like this:&lt;/p&gt;
&lt;p&gt;username
passwordThen, save the file as “proton_credentials.txt”. Remember where it is stored — we will need it later.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A first warning on security. **Storing account credentials like this makes it easy for you to use the sirup package. But it also increases the risk that unauthorized persons get a hold on these credentials. Thus, be careful to store the credentials in a safe place on your laptop and to not share them with anyone.&lt;/p&gt;
&lt;p&gt;Second, to use OpenVPN we need configuration files, whose names end with &lt;code&gt;.ovpn&lt;/code&gt;. The files allow OpenVPN to connect to a server from the VPN service provider. In ProtonVPN, go to the “Download” section of your account. Select the options as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to manage your IP address in Python&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;509&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-1c18ffaf.BfZTWBsr_Q79VL.webp&quot; srcset=&quot;&quot;&gt;
And download the configuration file(s) you want to use. Store the downloaded files on your computer, and remember the location.&lt;/p&gt;
&lt;h2 id=&quot;using-sirup&quot;&gt;Using &lt;code&gt;sirup&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We start by defining the path to the &lt;code&gt;proton_credentials.txt&lt;/code&gt; file. When you execute the code below, you will be asked to enter the root password, which is necessary to make the connection.&lt;/p&gt;
&lt;p&gt;import getpass
auth_file = “proton_credentials.txt”
pwd = getpass.getpass(“Please enter your root password:”)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A second warning on security.** The code above stores your root password during the Python session without encrypting it. This is OK to do on your laptop — if someone gets access to your Python session, your security has already been compromised — but not recommended on a shared computer such as a cluster or a cloud service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;changing-the-ip-address-with-sirup&quot;&gt;Changing the IP address with &lt;code&gt;sirup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now you can use the &lt;code&gt;VPNConnector&lt;/code&gt; to change our IP address. We will use the &lt;code&gt;&quot;my_config_file.ovpn&quot;&lt;/code&gt; configuration file.&lt;/p&gt;
&lt;p&gt;from sirup.VPNConnector import VPNConnector
config_file = “my_config_file.ovpn”The code below first connects to the server associated with &lt;code&gt;&quot;my_config_file.ovpn&quot;&lt;/code&gt; and then disconnects.&lt;/p&gt;
&lt;p&gt;connector = VPNConnector(auth_file, config_file)&lt;/p&gt;
&lt;h1 id=&quot;lets-see-the-current-ip-address-when-no-vpn-tunnel-is-active&quot;&gt;Let’s see the current IP address when no VPN tunnel is active&lt;/h1&gt;
&lt;p&gt;print(connector.base_ip)&lt;/p&gt;
&lt;p&gt;connector.connect(pwd=pwd)&lt;/p&gt;
&lt;h1 id=&quot;now-the-ip-address-should-differ&quot;&gt;Now the IP address should differ&lt;/h1&gt;
&lt;p&gt;print(connector.current_ip)&lt;/p&gt;
&lt;p&gt;connector.disconnect(pwd=pwd)&lt;/p&gt;
&lt;h1 id=&quot;now-current_ip-should-be-the-same-as-base_ip-above&quot;&gt;Now current_ip should be the same as base_ip above&lt;/h1&gt;
&lt;p&gt;print(connector.current_ip)&lt;/p&gt;
&lt;h3 id=&quot;rotating-the-ip-address-with-sirup&quot;&gt;Rotating the IP address with &lt;code&gt;sirup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Instead of connecting to a single server, you can also rotate across many different servers — which means you rotate your IP address across a set of potential addresses. Doing so is useful for larger scraping jobs because it will spread your requests across more servers.&lt;/p&gt;
&lt;p&gt;To do this, you need to download multiple configuration files as described above. Store all of the &lt;code&gt;.ovpn&lt;/code&gt; configuration files together in a separate directory. Let’s say you store them in the &lt;code&gt;&quot;/path/to/config/files/&quot;&lt;/code&gt; directory. You need to define this path in your Python script:&lt;/p&gt;
&lt;p&gt;config_path = “/path/to/config/files/“The following code connects to two different servers before disconnecting again:&lt;/p&gt;
&lt;p&gt;from sirup.IPRotator import IPRotator&lt;/p&gt;
&lt;p&gt;rotator = IPRotator(auth_file=my_auth_file, config_location=config_path, seed=seed) # this will ask for the root password&lt;/p&gt;
&lt;p&gt;print(rotator.connector.base_ip)&lt;/p&gt;
&lt;p&gt;rotator.connect()
print(rotator.connector.current_ip)&lt;/p&gt;
&lt;p&gt;rotator.rotate()
print(rotator.connector.current_ip)&lt;/p&gt;
&lt;p&gt;rotator.disconnect()&lt;/p&gt;
&lt;p&gt;print(rotator.connector.current_ip)&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This tutorial has walked you through the steps to manage your IP address in Python, using the &lt;code&gt;sirup&lt;/code&gt; package. We hope it makes your scraping workflows easier!&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;sirup&lt;/code&gt; is an open-source package developed by the Netherlands eScience Center. If you use the tool, you can cite &lt;a href=&quot;https://zenodo.org/records/10261949&quot;&gt;this zenodo repository&lt;/a&gt; with the DOI: &lt;a href=&quot;https://doi.org/10.5281/zenodo.10261949&quot;&gt;https://doi.org/10.5281/zenodo.10261949&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The source code of the package is &lt;a href=&quot;https://github.com/ivory-tower-private-power/sirup?tab=readme-ov-file&quot;&gt;here&lt;/a&gt;, where you can contribute to it, build on it and submit issues.&lt;/p&gt;
&lt;p&gt;Thanks to Patrick Bos, Peter Kalverla, Kody Moodley and Carlos Gonzalez Poses for comments.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-to-manage-your-ip-address-in-python-00102567.DNJxbduL.jpg" medium="image"/><author>Flavio Hafner</author></item><item><title>Differentiation without subtraction</title><link>https://blog.esciencecenter.nl/posts/2024-02-13---differentiation-without-subtraction</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-02-13---differentiation-without-subtraction</guid><description>&lt;p&gt;54&lt;/p&gt;
&lt;p&gt;A surprising application of complex numbers&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-e61cb215.BcArwpWs_ZxtMDI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@charlesdeluvio?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;charlesdeluvio&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some time ago I came across one of those ideas that makes you wonder: &lt;em&gt;“why nobody told me about this before?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Those of you with mathematical training certainly remember the &lt;a href=&quot;https://en.wikipedia.org/wiki/Taylor_series&quot;&gt;Taylor series&lt;/a&gt;. For those who do not, and yet want to keep reading, this &lt;a href=&quot;https://www.geogebra.org/m/CeW2gCzH&quot;&gt;visual simulation &lt;/a&gt;may be helpful.&lt;/p&gt;
&lt;p&gt;The idea is that any continuous, smooth function, can be approximated by a polynomial; the higher the degree, the more accurate the approximation. To put it otherwise: if we know the value of a function and its derivatives at a given point (x), we can estimate its value at a nearby point (x + ε). More specifically:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;63&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-b1f93adc.BE4fSPB9_Ixl5A.webp&quot; srcset=&quot;&quot;&gt;
Example of a generic Taylor seriesIf instead of a step (ε) in the realm of real numbers, we perform a step in the world of imaginary numbers (i ε), it follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;60&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-b8317317.BIFg7E0-_g0Lba.webp&quot; srcset=&quot;&quot;&gt;
It is here where things get interesting. If we take only the imaginary part, we get an equation that involves only the first derivative, the function evaluated in the complex plane, and the step size:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;53&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-2f21efdf.BaYyflhX_Z1MzxLq.webp&quot; srcset=&quot;&quot;&gt;
We just keep the imaginary part, and drop the real oneThis can be rearranged as an interesting formula for an approximate derivative:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;88&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-a80888ed.CbK2fjOB_Z3wfDt.webp&quot; srcset=&quot;&quot;&gt;
Complex-step numerical derivativeThat can be even used for exact evaluation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;106&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-3409cb52.UEyGppZn_Z1rQYNm.webp&quot; srcset=&quot;&quot;&gt;
Complex-step exact derivative&lt;/p&gt;
&lt;h2 id=&quot;is-this-useful-at-all&quot;&gt;Is this useful at all?&lt;/h2&gt;
&lt;p&gt;I know…, that was pretty strange. It feels like a complicated &lt;em&gt;tour de force&lt;/em&gt; for something as well-known as a numerical derivative. Nevertheless, it is hard to find a mathematical result that is completely useless, and complex-step differentiation is no exception.&lt;/p&gt;
&lt;p&gt;Let’s take a look at the last formula of the day, that of the classical step-forward numerical differentiation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;93&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-94add499.q85oueAm_Z1FXbqg.webp&quot; srcset=&quot;&quot;&gt;
Step-forward numerical derivativeIf we use the step-forward numerical derivative on a computer, the subtraction can cause numerical problems. Computers can’t store real numbers, but a rounded representation of them, and their numerical resolution is limited. If e is very small, it may happen that the subtraction above returns a zero as an artifact, making the whole calculation wrong.&lt;/p&gt;
&lt;p&gt;Notice now the main difference between this and our complex-step algorithm: there is no subtraction in the complex one. One problem less!&lt;/p&gt;
&lt;h2 id=&quot;further-information&quot;&gt;Further information&lt;/h2&gt;
&lt;p&gt;More information here: &lt;a href=&quot;https://sinews.siam.org/Details-Page/differentiation-without-a-difference&quot;&gt;Differentiation without a difference. SIAM news&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, you may also like &lt;a href=&quot;https://blog.esciencecenter.nl/automatic-differentiation-from-scratch-23d50c699555&quot;&gt;Automatic differentiation from scratch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;This article appeared first, in Spanish, in &lt;em&gt;&lt;a href=&quot;https://fuga.naukas.com/2018/08/20/derivando-sin-restar/&quot;&gt;&lt;em&gt;Naukas.com&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;</description><pubDate>Tue, 13 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;54&lt;/p&gt;
&lt;p&gt;A surprising application of complex numbers&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-e61cb215.BcArwpWs_ZxtMDI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@charlesdeluvio?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;charlesdeluvio&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some time ago I came across one of those ideas that makes you wonder: &lt;em&gt;“why nobody told me about this before?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Those of you with mathematical training certainly remember the &lt;a href=&quot;https://en.wikipedia.org/wiki/Taylor_series&quot;&gt;Taylor series&lt;/a&gt;. For those who do not, and yet want to keep reading, this &lt;a href=&quot;https://www.geogebra.org/m/CeW2gCzH&quot;&gt;visual simulation &lt;/a&gt;may be helpful.&lt;/p&gt;
&lt;p&gt;The idea is that any continuous, smooth function, can be approximated by a polynomial; the higher the degree, the more accurate the approximation. To put it otherwise: if we know the value of a function and its derivatives at a given point (x), we can estimate its value at a nearby point (x + ε). More specifically:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;63&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-b1f93adc.BE4fSPB9_Ixl5A.webp&quot; srcset=&quot;&quot;&gt;
Example of a generic Taylor seriesIf instead of a step (ε) in the realm of real numbers, we perform a step in the world of imaginary numbers (i ε), it follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;60&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-b8317317.BIFg7E0-_g0Lba.webp&quot; srcset=&quot;&quot;&gt;
It is here where things get interesting. If we take only the imaginary part, we get an equation that involves only the first derivative, the function evaluated in the complex plane, and the step size:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;53&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-2f21efdf.BaYyflhX_Z1MzxLq.webp&quot; srcset=&quot;&quot;&gt;
We just keep the imaginary part, and drop the real oneThis can be rearranged as an interesting formula for an approximate derivative:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;88&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-a80888ed.CbK2fjOB_Z3wfDt.webp&quot; srcset=&quot;&quot;&gt;
Complex-step numerical derivativeThat can be even used for exact evaluation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;106&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-3409cb52.UEyGppZn_Z1rQYNm.webp&quot; srcset=&quot;&quot;&gt;
Complex-step exact derivative&lt;/p&gt;
&lt;h2 id=&quot;is-this-useful-at-all&quot;&gt;Is this useful at all?&lt;/h2&gt;
&lt;p&gt;I know…, that was pretty strange. It feels like a complicated &lt;em&gt;tour de force&lt;/em&gt; for something as well-known as a numerical derivative. Nevertheless, it is hard to find a mathematical result that is completely useless, and complex-step differentiation is no exception.&lt;/p&gt;
&lt;p&gt;Let’s take a look at the last formula of the day, that of the classical step-forward numerical differentiation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Differentiation without subtraction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;580&quot; height=&quot;93&quot; src=&quot;https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-94add499.q85oueAm_Z1FXbqg.webp&quot; srcset=&quot;&quot;&gt;
Step-forward numerical derivativeIf we use the step-forward numerical derivative on a computer, the subtraction can cause numerical problems. Computers can’t store real numbers, but a rounded representation of them, and their numerical resolution is limited. If e is very small, it may happen that the subtraction above returns a zero as an artifact, making the whole calculation wrong.&lt;/p&gt;
&lt;p&gt;Notice now the main difference between this and our complex-step algorithm: there is no subtraction in the complex one. One problem less!&lt;/p&gt;
&lt;h2 id=&quot;further-information&quot;&gt;Further information&lt;/h2&gt;
&lt;p&gt;More information here: &lt;a href=&quot;https://sinews.siam.org/Details-Page/differentiation-without-a-difference&quot;&gt;Differentiation without a difference. SIAM news&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, you may also like &lt;a href=&quot;https://blog.esciencecenter.nl/automatic-differentiation-from-scratch-23d50c699555&quot;&gt;Automatic differentiation from scratch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;This article appeared first, in Spanish, in &lt;em&gt;&lt;a href=&quot;https://fuga.naukas.com/2018/08/20/derivando-sin-restar/&quot;&gt;&lt;em&gt;Naukas.com&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/differentiation-without-subtraction-b1f93adc.BE4fSPB9.png" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Causal Inference in JASP: The Process Module</title><link>https://blog.esciencecenter.nl/posts/2024-02-01---causal-inference-in-jasp-the-process-module</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-02-01---causal-inference-in-jasp-the-process-module</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/malte-luken/&quot;&gt;Malte Lüken&lt;/a&gt;, &lt;a href=&quot;https://juliarohrer.com/&quot;&gt;Julia M. Rohrer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/thijs-vroegh/&quot;&gt;Thijs Vroegh&lt;/a&gt;, &lt;a href=&quot;https://www.uva.nl/en/profile/d/o/j.b.vandoorn/j.b.vandoorn.html&quot;&gt;Johnny van Doorn&lt;/a&gt;, and &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is also published on the JASP &lt;em&gt;&lt;a href=&quot;https://jasp-stats.org/blog/&quot;&gt;&lt;em&gt;blog&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;448&quot; height=&quot;448&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-4987f6a5.B8-TxRvg_bKcUi.webp&quot; srcset=&quot;&quot;&gt;
In a recent &lt;a href=&quot;https://jasp-stats.org/2023/07/27/conditional-process-models/&quot;&gt;blog post&lt;/a&gt;, we announced the development of a JASP module for conditional process models, similar to the popular &lt;a href=&quot;https://www.processmacro.org/&quot;&gt;PROCESS&lt;/a&gt; macro for SPSS (Hayes, 2022a, 2022b). We can now share that we reached a milestone in our development efforts: The latest JASP release 18.2 includes a beta version of the Process module which allows users to apply frequentist process models. Besides covering many of the features of the SPSS macro, the JASP Process module provides a flexible and easy-to-use interface. It also makes the causal assumptions of process models more explicit and provides functionality to test them. In this blog post, we will introduce the main features of the module using a real-world example.&lt;/p&gt;
&lt;h2 id=&quot;mediation-moderation-and-conditional-process-models&quot;&gt;Mediation, Moderation, and Conditional Process Models&lt;/h2&gt;
&lt;p&gt;The aim of our module is to test models that involve mediation and moderation effects. A mediation effect is a causal chain between three variables. For example, when X → M, M → Y, and X → Y, then the causal effect from X to Y is (partly) mediated by M. A moderation effect implies that the relationship between two variables changes depending on a third variable, e.g., the effect X → M changes as the moderator W changes. A model that includes at least one mediation and one moderation effect is called a conditional process model because it makes assumptions about the causal process between variables, but the process is conditional on moderator variables (Hayes, 2022a).&lt;/p&gt;
&lt;p&gt;Conditional process models can also be conceptualized as parametric directed acyclic graphs (DAGs) or structural equation models (SEMs) that only include manifest variables (Pearl, 2012). We can use the properties of DAGs to test the implications of the causal model against data while SEMs are a useful framework for parameter estimation.&lt;/p&gt;
&lt;p&gt;The PROCESS macro for SPSS uses a regression-based approach to estimate process models which allows predictors (including independent variables, covariates, and mediators) to be correlated when there is no explicit causal path between them. Because the JASP Process module uses SEMs for model estimation, these correlations need to be explicitly allowed by the user. We believe this design choice prompts users to think more explicitly about the assumptions of their models. For a discussion of differences between PROCESS and SEM-based estimation, see Hayes et al. (2017).&lt;/p&gt;
&lt;h2 id=&quot;example-age-and-listening-related-fatigue&quot;&gt;Example: Age and Listening-related Fatigue&lt;/h2&gt;
&lt;p&gt;To illustrate the features of the Process module, we use openly available &lt;a href=&quot;https://osf.io/hc8n4/&quot;&gt;data&lt;/a&gt; from the study “Predictors of listening-related fatigue across the adult life span” by McGarrigle et al. (2021) which was published in &lt;em&gt;Psychological Science&lt;/em&gt;. The study investigates how different variables mediate and moderate the causal effect of age on listening-related fatigue using conditional process models. The analysis was pre-registered and the data set has a relatively large sample size (N = 281) which is roughly evenly distributed across age groups. These properties make the study a good example for conditional process analysis with observational data. As the authors of the original study, we assume that age is an exogenous (independent) variable which allows us to clearly identify the direction of the causal effect from age to fatigue.&lt;/p&gt;
&lt;p&gt;In our illustration of the module, we will reproduce the original analysis of the study but also test the implications of the hypothesized causal model. Note that our example only uses z-standardized variables which we renamed so they can be easily identified. The included candidates for mediators or moderators are auditory attention ability (“AudAttention”), perceived hearing impairment (“HearImpair”), perceived memory ability (“Memory”), and perceived mood disturbances (“MoodDisturb”). The example data set is also available in the internal JASP Data Library.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-flexible-conditional-process-models-in-jasp&quot;&gt;The Basics: Flexible Conditional Process Models in JASP&lt;/h2&gt;
&lt;p&gt;To estimate a conditional process model in JASP, we first load the data set and enable the Process module by clicking the blue “+” sign in the top right corner and selecting “Process (beta)”.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;514&quot; height=&quot;133&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-5daca690.D4a8o04O_52N1O.webp&quot; srcset=&quot;&quot;&gt;
We then click on the available module to start the “Classic Process Model” analysis. First, we drag the variable “Fatigue” into the box &lt;em&gt;Dependent Variable&lt;/em&gt; and the variables “Age”, “AudAttention”, “HearImpair”, “Memory”, as well as “MoodDisturb” into the box &lt;em&gt;Continuous Predictors&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-d67427be.CuqoN1D3_1WUm0B.webp&quot; srcset=&quot;&quot;&gt;
In this example, we use a new interface that differs from the way process models are specified in SPSS. In the &lt;em&gt;Models&lt;/em&gt; section, we can construct the hypothesized model by adding causal paths between variables. We add three paths from “Age” to “Fatigue” by selecting the variables in the &lt;em&gt;From&lt;/em&gt; and &lt;em&gt;To&lt;/em&gt; dropdowns. For each path, we choose &lt;em&gt;Mediator&lt;/em&gt; in the &lt;em&gt;Process Type&lt;/em&gt; dropdown and select “AudAttention”, “HearImpair”, “Memory” as the &lt;em&gt;Process Variable&lt;/em&gt;, respectively.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;260&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-914a5c82.CZUD3SKO_DY1EA.webp&quot; srcset=&quot;&quot;&gt;
After completing each path, JASP provides the output of the estimated model including a path diagram showing the conceptual model structure. The path diagram resembles the hypothesized parallel mediation model after the third path.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-54c3bb79.D-2lbkwR_Z24fMe8.webp&quot; srcset=&quot;&quot;&gt;
Before we look at the results, we select &lt;em&gt;Bootstrap&lt;/em&gt; under &lt;em&gt;Method&lt;/em&gt; in the &lt;em&gt;Options&lt;/em&gt; section to enable bootstrapped confidence intervals; this is done because we cannot assume that indirect effects are normally distributed. Bootstrapping in JASP can take a few minutes to finish.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;240&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-3640843a.DI_uQAhp_ZqQfFL.webp&quot; srcset=&quot;&quot;&gt;
Below the path diagram, under “Parameter estimates”, the output shows a table with estimated parameters and effects. The second table “Mediation effects” contains the direct and indirect effects. As in the original study, the table shows a negative direct effect from age to fatigue and a positive indirect effect via perceived hearing impairment, both with bootstrapped confidence intervals excluding zero.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;161&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-9a885c40.CgRVYg-5_1fhwQ4.webp&quot; srcset=&quot;&quot;&gt;
To add a moderation effect to our model, we go back to the “Models” section and click the green “+” button in the top left corner to add a second model to our analysis. As in the previous model, we add three mediation paths from “Age” to “Fatigue”. Then we add a fourth path from “Age” to “Fatigue” and specify “MoodDisturb” as a moderator.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;285&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-9285476b.uUtk5FYI_2jvCSg.webp&quot; srcset=&quot;&quot;&gt;
Now, JASP provides output for both models. In the “Model summary” table, we can see that Model 2 has lower AIC and BIC values indicating a better model fit compared to Model 1 (the weights for both criteria lie almost exclusively on Model 2; AIC and BIC weights can be enabled in the “Options” section).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;85&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-b7f6e2f7.3qYghwGB_Z1Wnp4h.webp&quot; srcset=&quot;&quot;&gt;
Under “Parameter estimates” for Model 2, we can see that the direct effect of mood disturbances on fatigue is positive and its bootstrap confidence interval excludes zero. However, this is not the case for the interaction between age and mood disturbances. Thus, the model does not provide evidence for the hypothesized moderation effect, reproducing the result of the original study.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;251&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-d5746641.Dx5zFN9S_I3pWP.webp&quot; srcset=&quot;&quot;&gt;
How can we explain that Model 2 fits the data better but shows no evidence for a moderation effect? Model 2 does show a strong direct effect of mood disturbance on fatigue, which is not included in Model 1, and we assume that it leads to the better model fit. This suggests that we should include mood disturbances in our model but not as a moderator on the path between age and fatigue.&lt;/p&gt;
&lt;h2 id=&quot;advanced-testing-implications-of-causal-models&quot;&gt;Advanced: Testing Implications of Causal Models&lt;/h2&gt;
&lt;p&gt;Because the estimated effect from age to fatigue pointed in the opposite of the expected direction, McGarrigle et al. (2021) estimated alternative process models in an exploratory analysis. The Process module provides a useful tool that indicates where the assumed causal model does not fit the observed relationships in the data. DAGs have implications for the variables they involve, specifically, for which variables should be independent in the data (Pearl, 2012; Textor et al., 2016). These implications can be tested against data with (conditional) independence tests. In our model, all variables are assumed to be continuous and all relationships to be linear, so we test for (conditional) independence by estimating (partial) correlation coefficients.&lt;/p&gt;
&lt;p&gt;In JASP, we can test local implications by ticking the box &lt;em&gt;Local tests&lt;/em&gt; under *Tests &lt;em&gt;in the &lt;em&gt;Models&lt;/em&gt; section&lt;/em&gt;. *Here, we apply local tests to Model 2. Underneath the box, we can select the type of test we want to use, which is the default (&lt;em&gt;Linear&lt;/em&gt;) in our case. If the model contains categorical variables or relationships are assumed to be nonlinear, a different type should be chosen (e.g., &lt;em&gt;Loess&lt;/em&gt; or &lt;em&gt;Chi-square&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;260&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-ebfb687a.BQT4PiqY_fcxxF.webp&quot; srcset=&quot;&quot;&gt;
After ticking the &lt;em&gt;Local tests&lt;/em&gt; box, a new table appears in the output under “Local tests”. In the first three columns, the table shows which implied relationship is tested: For example, in the first row, auditory attention is assumed to be conditionally independent from hearing impairment given age. This can also be seen in the model diagram, which does not contain any direct arrows between the two variables (i.e., age accounts for the entire covariance between auditory attention and hearing impairment). The estimated partial correlation for this implied relationship is very small and not significant indicating that this implication is not violated. The opposite is true for row four: The model implies that age and mood disturbances are independent since there are no direct (or indirect) arrows between the two variables. However, the estimated correlation is negative and significant suggesting that the implication is violated and the model is misspecified. Rows five to seven also show significant (partial) correlations increasing the evidence that the model is inappropriate for the data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;272&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-0ac11436.CN-zxQx6_Z15B66U.webp&quot; srcset=&quot;&quot;&gt;
Note that the PROCESS macro for SPSS behaves differently to our module by automatically allowing mediators to correlate. In a SEM context, this behavior can be imitated by estimating the residual covariances between mediators in the model. Ticking the box &lt;em&gt;Mediators&lt;/em&gt; under &lt;em&gt;Residual Covariances&lt;/em&gt; in the &lt;em&gt;Models&lt;/em&gt; section enables this.&lt;/p&gt;
&lt;h2 id=&quot;advanced-adjusting-the-model-in-an-exploratory-analysis&quot;&gt;Advanced: Adjusting the Model in an Exploratory Analysis&lt;/h2&gt;
&lt;p&gt;In the original study, McGarrigle et al. conducted an exploratory analysis where they used “MoodDisturb” as a mediator instead of a moderator. Our implication tests of the previous model with “MoodDisturb” provide a rationale for this: The data showed a negative correlation between “Age” and “MoodDisturb” which was not expected by the model. Our exploratory model should therefore account for this correlation by including a direct causal path from “Age” to “MoodDisturb”.&lt;/p&gt;
&lt;p&gt;We open a new Classical Process Model* analysis and select the same variables for &lt;em&gt;Dependent Variable&lt;/em&gt; and &lt;em&gt;Continuous Predictors&lt;/em&gt; as in the previous analysis. In our exploratory model, we specify “MoodDisturb” as a mediator between “Age” and “Fatigue”. We add “HearImpair” as a second mediator and leave out the other variables for simplicity.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;194&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-5fc4cb9f.D_nm5c-D_rYRHN.webp&quot; srcset=&quot;&quot;&gt;
In the output, we can see the conceptual diagram of our exploratory model.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;524&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-344aaf01.B803Zpd-_Z1IbXIe.webp&quot; srcset=&quot;&quot;&gt;
Again, we test the local implications of our new model. We can see that the model expects mood disturbances and hearing impairment to be conditionally independent given age, which is violated in the data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;148&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-2aefc199.CP2Z6xVu_Z1GJIQd.webp&quot; srcset=&quot;&quot;&gt;
Thus, we need to further adjust our model, for example, by adding a direct causal path from “HearImpair” to “MoodDisturb” assuming that increased perceived hearing impairment leads to increased mood disturbance and not vice versa. In JASP, we can add a direct path by selecting &lt;em&gt;Direct&lt;/em&gt; in the &lt;em&gt;Process Type&lt;/em&gt; dropdown under the &lt;em&gt;Models&lt;/em&gt; section.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;259&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-6557220d.Cz0JTX88_Z1tv47X.webp&quot; srcset=&quot;&quot;&gt;
The output now shows the conceptual diagram of the adjusted exploratory model.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;345&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-e967f275.ClsK9YV1_Z2fOIuX.webp&quot; srcset=&quot;&quot;&gt;
If we compare the AIC to the first exploratory model without the direct path, we can see that the AIC of the second model with the direct path is lower, indicating a better model fit (the AIC weight lies almost exclusively on the second model).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;86&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-214cf25e.imkGIn1l_23ASG.webp&quot; srcset=&quot;&quot;&gt;
Looking at the direct and indirect effects in the “Mediation effects” table, we can see that the adjusted exploratory model estimates one direct (first row) and three indirect effects (rows two to four).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;131&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-fd6ec0c4.rmel0apr_1t3W1R.webp&quot; srcset=&quot;&quot;&gt;
The bootstrap confidence interval for the direct effect overlaps with zero but the intervals for the three indirect effects do not. That is, the adjusted exploratory model suggests a threefold causal process from age to fatigue: Via mood disturbances, hearing impairment, and via a path from hearing impairment to mood disturbances.&lt;/p&gt;
&lt;h2 id=&quot;using-conditional-process-models-with-caution&quot;&gt;Using Conditional Process Models with Caution&lt;/h2&gt;
&lt;p&gt;As has been emphasized by Rohrer et al. (2021), process models should be used with caution. They assume that the model structure is appropriate for the problem and data to identify causal effects. While the JASP Process module allows users to test the implications of the causal structure, other assumptions are much more difficult or even impossible to test: For example, to identify causal effects, all potential confounding variables must be accounted for in the model. This is difficult for indirect effects, even in experiments, because unobserved confounders can bias causal effects from the mediator to the dependent variable (Bullock et al., 2010; Rohrer et al., 2021). The Process module allows users to include confounders on all paths; however, they must be known and measured.&lt;/p&gt;
&lt;p&gt;Another common challenge is to correctly establish the direction of causality and ruling out alternative causal models (Kline, 2012; Rohrer et al., 2021; Fiedler et al., 2018). While in our example, it was easy to determine the causal direction from age to fatigue, the direction of causal paths between two mediators or the mediators and the dependent variable was much less evident. Some alternative causal models (stating different directions of causality) can be ruled out through causal implications. However, more often, the most appropriate causal model needs to be justified from theory or established through experimental manipulation.&lt;/p&gt;
&lt;p&gt;Furthermore, moderation effects as part of conditional process models pose several challenges to researchers, such as scale-dependency, choosing hypothesis-appropriate effect sizes, and distinguishing between causal interaction or effect modification (see Rohrer &amp;#x26; Arslan, 2021, for details, examples, and recommendations).&lt;/p&gt;
&lt;p&gt;If there is evidence that a model is misspecified, the adjustment must also be done with care to avoid overfitting (Textor et al., 2016). While the modification can be done in an exploratory fashion, the modified model should always be tested on an independent dataset to draw robust conclusions. At the same time, it should be consistent with theoretical expectations.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The new JASP Process module allows users to apply frequentist conditional process models using an intuitive and flexible interface. Using data from a study by McGarrigle et al. (2021), we demonstrated how users can estimate models involving multiple mediation and moderation effects. We also explained how the module enables users to test the local implications of specified models. In the case of violated implications, users can modify misspecified models accordingly. We believe that the JASP Process module can pave the way toward a more responsible and appropriate use of conditional process models. By providing an intuitive and flexible interface, we also aim to make process models more accessible to researchers and students.&lt;/p&gt;
&lt;h2 id=&quot;behind-the-project&quot;&gt;Behind the Project&lt;/h2&gt;
&lt;p&gt;This project is a collaboration between the JASP Team and the Netherlands eScience Center. As the national institute for research software, the eScience Center awards projects as part of calls for proposals. Instead of monetary funding, it provides in-kind support by Research Software Engineers to create innovative digital solutions. This project was granted as part of the Small-Scale Initiatives Digital Approaches to the Social Sciences call 2022.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Bullock, J. G., Green, D. P., &amp;#x26; Ha, S. E. (2010). Yes, but what’s the mechanism? (don’t expect an easy answer). &lt;em&gt;Journal of Personality and Social Psychology, 98&lt;/em&gt;(4), 550–558. &lt;a href=&quot;https://psycnet.apa.org/doi/10.1037/a0018933&quot;&gt;https://doi.org/10.1037/a0018933&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fiedler, K., Harris, C., &amp;#x26; Schott, M. (2018). Unwarranted inferences from statistical mediation tests — An analysis of articles published in 2015. &lt;em&gt;Journal of Experimental Social Psychology, 75&lt;/em&gt;, 95–102.&lt;a href=&quot;https://doi.org/10.1016/j.jesp.2017.11.008&quot;&gt; https://doi.org/10.1016/j.jesp.2017.11.008&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F., Montoya, A. K., &amp;#x26; Rockwood, N. J. (2017). The analysis of mechanisms and their contingencies: PROCESS versus structural equation modeling. &lt;em&gt;Australasian Marketing Journal, 25&lt;/em&gt;(1), 76–81. &lt;a href=&quot;https://doi.org/10.1016/j.ausmj.2017.02.001&quot;&gt;https://doi.org/10.1016/j.ausmj.2017.02.001&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022a). *Introduction to mediation, moderation, and conditional process analysis *(3rd Ed.). New York: The Guilford Press.&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022b). The PROCESS macro for SPSS, SAS, and R (Version 4.2) [Computer software]. &lt;a href=&quot;https://processmacro.org&quot;&gt;https://processmacro.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Kline, R. B. (2012). Assumptions in structural equation modeling. In R. H. Hoyle (Ed.), &lt;em&gt;Handbook of structural equation modeling&lt;/em&gt; (pp. 111–125). Guilford Press.&lt;/p&gt;
&lt;p&gt;McGarrigle, R., Knight, S., Hornsby, B. W. Y., &amp;#x26; Mattys, S. (2021). Predictors of listening-related fatigue across the adult life span. &lt;em&gt;Psychological Science, 32&lt;/em&gt;(12), 1937–1951. &lt;a href=&quot;https://doi.org/10.1177/09567976211016410&quot;&gt;https://doi.org/10.1177/09567976211016410&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pearl, J. (2012). The causal foundations of structural equation modeling. In R. H. Hoyle (Ed.), &lt;em&gt;Handbook of structural equation modeling&lt;/em&gt; (pp. 68–91). Guilford Press.&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., &amp;#x26; Arslan, R. C. (2021). Precise answers to vague questions: Issues with interactions. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 4&lt;/em&gt;(2), 25152459211007368.&lt;a href=&quot;https://doi.org/10.1177/25152459211007368&quot;&gt; https://doi.org/10.1177/25152459211007368&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., Hünermund, P., Arslan, R. C., Elson, M. (2022). That’s a lot to process! Pitfalls of popular path models. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 5&lt;/em&gt;(2). &lt;a href=&quot;https://doi.org/10.1177/25152459221095827&quot;&gt;https://doi.org/10.1177/25152459221095827&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Textor, J., van der Zander, B., Gilthorpe, M. S., Liśkiewicz, M., &amp;#x26; Ellison, G. T. (2016). Robust causal inference using directed acyclic graphs: The R package ‘dagitty.’* International Journal of Epidemiology, 45*(6), 1887–1894. &lt;a href=&quot;https://doi.org/10.1093/ije/dyw341&quot;&gt;https://doi.org/10.1093/ije/dyw341&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 01 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/malte-luken/&quot;&gt;Malte Lüken&lt;/a&gt;, &lt;a href=&quot;https://juliarohrer.com/&quot;&gt;Julia M. Rohrer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/thijs-vroegh/&quot;&gt;Thijs Vroegh&lt;/a&gt;, &lt;a href=&quot;https://www.uva.nl/en/profile/d/o/j.b.vandoorn/j.b.vandoorn.html&quot;&gt;Johnny van Doorn&lt;/a&gt;, and &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is also published on the JASP &lt;em&gt;&lt;a href=&quot;https://jasp-stats.org/blog/&quot;&gt;&lt;em&gt;blog&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;448&quot; height=&quot;448&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-4987f6a5.B8-TxRvg_bKcUi.webp&quot; srcset=&quot;&quot;&gt;
In a recent &lt;a href=&quot;https://jasp-stats.org/2023/07/27/conditional-process-models/&quot;&gt;blog post&lt;/a&gt;, we announced the development of a JASP module for conditional process models, similar to the popular &lt;a href=&quot;https://www.processmacro.org/&quot;&gt;PROCESS&lt;/a&gt; macro for SPSS (Hayes, 2022a, 2022b). We can now share that we reached a milestone in our development efforts: The latest JASP release 18.2 includes a beta version of the Process module which allows users to apply frequentist process models. Besides covering many of the features of the SPSS macro, the JASP Process module provides a flexible and easy-to-use interface. It also makes the causal assumptions of process models more explicit and provides functionality to test them. In this blog post, we will introduce the main features of the module using a real-world example.&lt;/p&gt;
&lt;h2 id=&quot;mediation-moderation-and-conditional-process-models&quot;&gt;Mediation, Moderation, and Conditional Process Models&lt;/h2&gt;
&lt;p&gt;The aim of our module is to test models that involve mediation and moderation effects. A mediation effect is a causal chain between three variables. For example, when X → M, M → Y, and X → Y, then the causal effect from X to Y is (partly) mediated by M. A moderation effect implies that the relationship between two variables changes depending on a third variable, e.g., the effect X → M changes as the moderator W changes. A model that includes at least one mediation and one moderation effect is called a conditional process model because it makes assumptions about the causal process between variables, but the process is conditional on moderator variables (Hayes, 2022a).&lt;/p&gt;
&lt;p&gt;Conditional process models can also be conceptualized as parametric directed acyclic graphs (DAGs) or structural equation models (SEMs) that only include manifest variables (Pearl, 2012). We can use the properties of DAGs to test the implications of the causal model against data while SEMs are a useful framework for parameter estimation.&lt;/p&gt;
&lt;p&gt;The PROCESS macro for SPSS uses a regression-based approach to estimate process models which allows predictors (including independent variables, covariates, and mediators) to be correlated when there is no explicit causal path between them. Because the JASP Process module uses SEMs for model estimation, these correlations need to be explicitly allowed by the user. We believe this design choice prompts users to think more explicitly about the assumptions of their models. For a discussion of differences between PROCESS and SEM-based estimation, see Hayes et al. (2017).&lt;/p&gt;
&lt;h2 id=&quot;example-age-and-listening-related-fatigue&quot;&gt;Example: Age and Listening-related Fatigue&lt;/h2&gt;
&lt;p&gt;To illustrate the features of the Process module, we use openly available &lt;a href=&quot;https://osf.io/hc8n4/&quot;&gt;data&lt;/a&gt; from the study “Predictors of listening-related fatigue across the adult life span” by McGarrigle et al. (2021) which was published in &lt;em&gt;Psychological Science&lt;/em&gt;. The study investigates how different variables mediate and moderate the causal effect of age on listening-related fatigue using conditional process models. The analysis was pre-registered and the data set has a relatively large sample size (N = 281) which is roughly evenly distributed across age groups. These properties make the study a good example for conditional process analysis with observational data. As the authors of the original study, we assume that age is an exogenous (independent) variable which allows us to clearly identify the direction of the causal effect from age to fatigue.&lt;/p&gt;
&lt;p&gt;In our illustration of the module, we will reproduce the original analysis of the study but also test the implications of the hypothesized causal model. Note that our example only uses z-standardized variables which we renamed so they can be easily identified. The included candidates for mediators or moderators are auditory attention ability (“AudAttention”), perceived hearing impairment (“HearImpair”), perceived memory ability (“Memory”), and perceived mood disturbances (“MoodDisturb”). The example data set is also available in the internal JASP Data Library.&lt;/p&gt;
&lt;h2 id=&quot;the-basics-flexible-conditional-process-models-in-jasp&quot;&gt;The Basics: Flexible Conditional Process Models in JASP&lt;/h2&gt;
&lt;p&gt;To estimate a conditional process model in JASP, we first load the data set and enable the Process module by clicking the blue “+” sign in the top right corner and selecting “Process (beta)”.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;514&quot; height=&quot;133&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-5daca690.D4a8o04O_52N1O.webp&quot; srcset=&quot;&quot;&gt;
We then click on the available module to start the “Classic Process Model” analysis. First, we drag the variable “Fatigue” into the box &lt;em&gt;Dependent Variable&lt;/em&gt; and the variables “Age”, “AudAttention”, “HearImpair”, “Memory”, as well as “MoodDisturb” into the box &lt;em&gt;Continuous Predictors&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-d67427be.CuqoN1D3_1WUm0B.webp&quot; srcset=&quot;&quot;&gt;
In this example, we use a new interface that differs from the way process models are specified in SPSS. In the &lt;em&gt;Models&lt;/em&gt; section, we can construct the hypothesized model by adding causal paths between variables. We add three paths from “Age” to “Fatigue” by selecting the variables in the &lt;em&gt;From&lt;/em&gt; and &lt;em&gt;To&lt;/em&gt; dropdowns. For each path, we choose &lt;em&gt;Mediator&lt;/em&gt; in the &lt;em&gt;Process Type&lt;/em&gt; dropdown and select “AudAttention”, “HearImpair”, “Memory” as the &lt;em&gt;Process Variable&lt;/em&gt;, respectively.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;260&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-914a5c82.CZUD3SKO_DY1EA.webp&quot; srcset=&quot;&quot;&gt;
After completing each path, JASP provides the output of the estimated model including a path diagram showing the conceptual model structure. The path diagram resembles the hypothesized parallel mediation model after the third path.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-54c3bb79.D-2lbkwR_Z24fMe8.webp&quot; srcset=&quot;&quot;&gt;
Before we look at the results, we select &lt;em&gt;Bootstrap&lt;/em&gt; under &lt;em&gt;Method&lt;/em&gt; in the &lt;em&gt;Options&lt;/em&gt; section to enable bootstrapped confidence intervals; this is done because we cannot assume that indirect effects are normally distributed. Bootstrapping in JASP can take a few minutes to finish.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;240&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-3640843a.DI_uQAhp_ZqQfFL.webp&quot; srcset=&quot;&quot;&gt;
Below the path diagram, under “Parameter estimates”, the output shows a table with estimated parameters and effects. The second table “Mediation effects” contains the direct and indirect effects. As in the original study, the table shows a negative direct effect from age to fatigue and a positive indirect effect via perceived hearing impairment, both with bootstrapped confidence intervals excluding zero.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;161&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-9a885c40.CgRVYg-5_1fhwQ4.webp&quot; srcset=&quot;&quot;&gt;
To add a moderation effect to our model, we go back to the “Models” section and click the green “+” button in the top left corner to add a second model to our analysis. As in the previous model, we add three mediation paths from “Age” to “Fatigue”. Then we add a fourth path from “Age” to “Fatigue” and specify “MoodDisturb” as a moderator.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;285&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-9285476b.uUtk5FYI_2jvCSg.webp&quot; srcset=&quot;&quot;&gt;
Now, JASP provides output for both models. In the “Model summary” table, we can see that Model 2 has lower AIC and BIC values indicating a better model fit compared to Model 1 (the weights for both criteria lie almost exclusively on Model 2; AIC and BIC weights can be enabled in the “Options” section).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;85&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-b7f6e2f7.3qYghwGB_Z1Wnp4h.webp&quot; srcset=&quot;&quot;&gt;
Under “Parameter estimates” for Model 2, we can see that the direct effect of mood disturbances on fatigue is positive and its bootstrap confidence interval excludes zero. However, this is not the case for the interaction between age and mood disturbances. Thus, the model does not provide evidence for the hypothesized moderation effect, reproducing the result of the original study.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;251&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-d5746641.Dx5zFN9S_I3pWP.webp&quot; srcset=&quot;&quot;&gt;
How can we explain that Model 2 fits the data better but shows no evidence for a moderation effect? Model 2 does show a strong direct effect of mood disturbance on fatigue, which is not included in Model 1, and we assume that it leads to the better model fit. This suggests that we should include mood disturbances in our model but not as a moderator on the path between age and fatigue.&lt;/p&gt;
&lt;h2 id=&quot;advanced-testing-implications-of-causal-models&quot;&gt;Advanced: Testing Implications of Causal Models&lt;/h2&gt;
&lt;p&gt;Because the estimated effect from age to fatigue pointed in the opposite of the expected direction, McGarrigle et al. (2021) estimated alternative process models in an exploratory analysis. The Process module provides a useful tool that indicates where the assumed causal model does not fit the observed relationships in the data. DAGs have implications for the variables they involve, specifically, for which variables should be independent in the data (Pearl, 2012; Textor et al., 2016). These implications can be tested against data with (conditional) independence tests. In our model, all variables are assumed to be continuous and all relationships to be linear, so we test for (conditional) independence by estimating (partial) correlation coefficients.&lt;/p&gt;
&lt;p&gt;In JASP, we can test local implications by ticking the box &lt;em&gt;Local tests&lt;/em&gt; under *Tests &lt;em&gt;in the &lt;em&gt;Models&lt;/em&gt; section&lt;/em&gt;. *Here, we apply local tests to Model 2. Underneath the box, we can select the type of test we want to use, which is the default (&lt;em&gt;Linear&lt;/em&gt;) in our case. If the model contains categorical variables or relationships are assumed to be nonlinear, a different type should be chosen (e.g., &lt;em&gt;Loess&lt;/em&gt; or &lt;em&gt;Chi-square&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;260&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-ebfb687a.BQT4PiqY_fcxxF.webp&quot; srcset=&quot;&quot;&gt;
After ticking the &lt;em&gt;Local tests&lt;/em&gt; box, a new table appears in the output under “Local tests”. In the first three columns, the table shows which implied relationship is tested: For example, in the first row, auditory attention is assumed to be conditionally independent from hearing impairment given age. This can also be seen in the model diagram, which does not contain any direct arrows between the two variables (i.e., age accounts for the entire covariance between auditory attention and hearing impairment). The estimated partial correlation for this implied relationship is very small and not significant indicating that this implication is not violated. The opposite is true for row four: The model implies that age and mood disturbances are independent since there are no direct (or indirect) arrows between the two variables. However, the estimated correlation is negative and significant suggesting that the implication is violated and the model is misspecified. Rows five to seven also show significant (partial) correlations increasing the evidence that the model is inappropriate for the data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;272&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-0ac11436.CN-zxQx6_Z15B66U.webp&quot; srcset=&quot;&quot;&gt;
Note that the PROCESS macro for SPSS behaves differently to our module by automatically allowing mediators to correlate. In a SEM context, this behavior can be imitated by estimating the residual covariances between mediators in the model. Ticking the box &lt;em&gt;Mediators&lt;/em&gt; under &lt;em&gt;Residual Covariances&lt;/em&gt; in the &lt;em&gt;Models&lt;/em&gt; section enables this.&lt;/p&gt;
&lt;h2 id=&quot;advanced-adjusting-the-model-in-an-exploratory-analysis&quot;&gt;Advanced: Adjusting the Model in an Exploratory Analysis&lt;/h2&gt;
&lt;p&gt;In the original study, McGarrigle et al. conducted an exploratory analysis where they used “MoodDisturb” as a mediator instead of a moderator. Our implication tests of the previous model with “MoodDisturb” provide a rationale for this: The data showed a negative correlation between “Age” and “MoodDisturb” which was not expected by the model. Our exploratory model should therefore account for this correlation by including a direct causal path from “Age” to “MoodDisturb”.&lt;/p&gt;
&lt;p&gt;We open a new Classical Process Model* analysis and select the same variables for &lt;em&gt;Dependent Variable&lt;/em&gt; and &lt;em&gt;Continuous Predictors&lt;/em&gt; as in the previous analysis. In our exploratory model, we specify “MoodDisturb” as a mediator between “Age” and “Fatigue”. We add “HearImpair” as a second mediator and leave out the other variables for simplicity.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;194&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-5fc4cb9f.D_nm5c-D_rYRHN.webp&quot; srcset=&quot;&quot;&gt;
In the output, we can see the conceptual diagram of our exploratory model.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;524&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-344aaf01.B803Zpd-_Z1IbXIe.webp&quot; srcset=&quot;&quot;&gt;
Again, we test the local implications of our new model. We can see that the model expects mood disturbances and hearing impairment to be conditionally independent given age, which is violated in the data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;148&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-2aefc199.CP2Z6xVu_Z1GJIQd.webp&quot; srcset=&quot;&quot;&gt;
Thus, we need to further adjust our model, for example, by adding a direct causal path from “HearImpair” to “MoodDisturb” assuming that increased perceived hearing impairment leads to increased mood disturbance and not vice versa. In JASP, we can add a direct path by selecting &lt;em&gt;Direct&lt;/em&gt; in the &lt;em&gt;Process Type&lt;/em&gt; dropdown under the &lt;em&gt;Models&lt;/em&gt; section.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;259&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-6557220d.Cz0JTX88_Z1tv47X.webp&quot; srcset=&quot;&quot;&gt;
The output now shows the conceptual diagram of the adjusted exploratory model.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;345&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-e967f275.ClsK9YV1_Z2fOIuX.webp&quot; srcset=&quot;&quot;&gt;
If we compare the AIC to the first exploratory model without the direct path, we can see that the AIC of the second model with the direct path is lower, indicating a better model fit (the AIC weight lies almost exclusively on the second model).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;86&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-214cf25e.imkGIn1l_23ASG.webp&quot; srcset=&quot;&quot;&gt;
Looking at the direct and indirect effects in the “Mediation effects” table, we can see that the adjusted exploratory model estimates one direct (first row) and three indirect effects (rows two to four).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Causal Inference in JASP: The Process Module&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;131&quot; src=&quot;https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-fd6ec0c4.rmel0apr_1t3W1R.webp&quot; srcset=&quot;&quot;&gt;
The bootstrap confidence interval for the direct effect overlaps with zero but the intervals for the three indirect effects do not. That is, the adjusted exploratory model suggests a threefold causal process from age to fatigue: Via mood disturbances, hearing impairment, and via a path from hearing impairment to mood disturbances.&lt;/p&gt;
&lt;h2 id=&quot;using-conditional-process-models-with-caution&quot;&gt;Using Conditional Process Models with Caution&lt;/h2&gt;
&lt;p&gt;As has been emphasized by Rohrer et al. (2021), process models should be used with caution. They assume that the model structure is appropriate for the problem and data to identify causal effects. While the JASP Process module allows users to test the implications of the causal structure, other assumptions are much more difficult or even impossible to test: For example, to identify causal effects, all potential confounding variables must be accounted for in the model. This is difficult for indirect effects, even in experiments, because unobserved confounders can bias causal effects from the mediator to the dependent variable (Bullock et al., 2010; Rohrer et al., 2021). The Process module allows users to include confounders on all paths; however, they must be known and measured.&lt;/p&gt;
&lt;p&gt;Another common challenge is to correctly establish the direction of causality and ruling out alternative causal models (Kline, 2012; Rohrer et al., 2021; Fiedler et al., 2018). While in our example, it was easy to determine the causal direction from age to fatigue, the direction of causal paths between two mediators or the mediators and the dependent variable was much less evident. Some alternative causal models (stating different directions of causality) can be ruled out through causal implications. However, more often, the most appropriate causal model needs to be justified from theory or established through experimental manipulation.&lt;/p&gt;
&lt;p&gt;Furthermore, moderation effects as part of conditional process models pose several challenges to researchers, such as scale-dependency, choosing hypothesis-appropriate effect sizes, and distinguishing between causal interaction or effect modification (see Rohrer &amp;#x26; Arslan, 2021, for details, examples, and recommendations).&lt;/p&gt;
&lt;p&gt;If there is evidence that a model is misspecified, the adjustment must also be done with care to avoid overfitting (Textor et al., 2016). While the modification can be done in an exploratory fashion, the modified model should always be tested on an independent dataset to draw robust conclusions. At the same time, it should be consistent with theoretical expectations.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The new JASP Process module allows users to apply frequentist conditional process models using an intuitive and flexible interface. Using data from a study by McGarrigle et al. (2021), we demonstrated how users can estimate models involving multiple mediation and moderation effects. We also explained how the module enables users to test the local implications of specified models. In the case of violated implications, users can modify misspecified models accordingly. We believe that the JASP Process module can pave the way toward a more responsible and appropriate use of conditional process models. By providing an intuitive and flexible interface, we also aim to make process models more accessible to researchers and students.&lt;/p&gt;
&lt;h2 id=&quot;behind-the-project&quot;&gt;Behind the Project&lt;/h2&gt;
&lt;p&gt;This project is a collaboration between the JASP Team and the Netherlands eScience Center. As the national institute for research software, the eScience Center awards projects as part of calls for proposals. Instead of monetary funding, it provides in-kind support by Research Software Engineers to create innovative digital solutions. This project was granted as part of the Small-Scale Initiatives Digital Approaches to the Social Sciences call 2022.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Bullock, J. G., Green, D. P., &amp;#x26; Ha, S. E. (2010). Yes, but what’s the mechanism? (don’t expect an easy answer). &lt;em&gt;Journal of Personality and Social Psychology, 98&lt;/em&gt;(4), 550–558. &lt;a href=&quot;https://psycnet.apa.org/doi/10.1037/a0018933&quot;&gt;https://doi.org/10.1037/a0018933&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fiedler, K., Harris, C., &amp;#x26; Schott, M. (2018). Unwarranted inferences from statistical mediation tests — An analysis of articles published in 2015. &lt;em&gt;Journal of Experimental Social Psychology, 75&lt;/em&gt;, 95–102.&lt;a href=&quot;https://doi.org/10.1016/j.jesp.2017.11.008&quot;&gt; https://doi.org/10.1016/j.jesp.2017.11.008&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F., Montoya, A. K., &amp;#x26; Rockwood, N. J. (2017). The analysis of mechanisms and their contingencies: PROCESS versus structural equation modeling. &lt;em&gt;Australasian Marketing Journal, 25&lt;/em&gt;(1), 76–81. &lt;a href=&quot;https://doi.org/10.1016/j.ausmj.2017.02.001&quot;&gt;https://doi.org/10.1016/j.ausmj.2017.02.001&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022a). *Introduction to mediation, moderation, and conditional process analysis *(3rd Ed.). New York: The Guilford Press.&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022b). The PROCESS macro for SPSS, SAS, and R (Version 4.2) [Computer software]. &lt;a href=&quot;https://processmacro.org&quot;&gt;https://processmacro.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Kline, R. B. (2012). Assumptions in structural equation modeling. In R. H. Hoyle (Ed.), &lt;em&gt;Handbook of structural equation modeling&lt;/em&gt; (pp. 111–125). Guilford Press.&lt;/p&gt;
&lt;p&gt;McGarrigle, R., Knight, S., Hornsby, B. W. Y., &amp;#x26; Mattys, S. (2021). Predictors of listening-related fatigue across the adult life span. &lt;em&gt;Psychological Science, 32&lt;/em&gt;(12), 1937–1951. &lt;a href=&quot;https://doi.org/10.1177/09567976211016410&quot;&gt;https://doi.org/10.1177/09567976211016410&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pearl, J. (2012). The causal foundations of structural equation modeling. In R. H. Hoyle (Ed.), &lt;em&gt;Handbook of structural equation modeling&lt;/em&gt; (pp. 68–91). Guilford Press.&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., &amp;#x26; Arslan, R. C. (2021). Precise answers to vague questions: Issues with interactions. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 4&lt;/em&gt;(2), 25152459211007368.&lt;a href=&quot;https://doi.org/10.1177/25152459211007368&quot;&gt; https://doi.org/10.1177/25152459211007368&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., Hünermund, P., Arslan, R. C., Elson, M. (2022). That’s a lot to process! Pitfalls of popular path models. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 5&lt;/em&gt;(2). &lt;a href=&quot;https://doi.org/10.1177/25152459221095827&quot;&gt;https://doi.org/10.1177/25152459221095827&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Textor, J., van der Zander, B., Gilthorpe, M. S., Liśkiewicz, M., &amp;#x26; Ellison, G. T. (2016). Robust causal inference using directed acyclic graphs: The R package ‘dagitty.’* International Journal of Epidemiology, 45*(6), 1887–1894. &lt;a href=&quot;https://doi.org/10.1093/ije/dyw341&quot;&gt;https://doi.org/10.1093/ije/dyw341&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/causal-inference-in-jasp-the-process-mod-4987f6a5.B8-TxRvg.png" medium="image"/><author>Malte Lüken</author></item><item><title>Talking about energy-efficient GPU computing at SC23</title><link>https://blog.esciencecenter.nl/posts/2024-01-16---talking-about-energy-efficient-gpu-computing-at-sc23</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2024-01-16---talking-about-energy-efficient-gpu-computing-at-sc23</guid><description>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;November is the time for Supercomputing, or &lt;a href=&quot;https://sc23.supercomputing.org/&quot;&gt;SC&lt;/a&gt; as it is called nowadays, and in 2023 the largest High-Performance Computing (HPC) conference in the world took place in Denver, USA, from the 12th to the 17th of that month.&lt;/p&gt;
&lt;p&gt;It was a week packed with talks, workshops, tutorials, exhibitors from all over the world, social gatherings, announcements and all of the usual SC glamour. While the eyes of the world were all pointed at the &lt;a href=&quot;https://top500.org/&quot;&gt;TOP500&lt;/a&gt; to see if Aurora would become the fastest supercomputer on the planet (spoiler: it did not; &lt;a href=&quot;https://www.hpcwire.com/off-the-wire/argonne-shares-strong-early-performance-numbers-for-aurora-supercomputer/&quot;&gt;Aurora sits at number 2 behind Frontier&lt;/a&gt;), there were many highlights of the conference.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-ef98a387.DdIm_n1F_QMNK.webp&quot; srcset=&quot;&quot;&gt;
Ben, Floris-Jan, Stijn, and Alessio standing with the SC23 logo at the Colorado Convention Center in Denver. Photo by Floris-Jan Willemsen.On the technical front, it is clear that Graphics Processing Units (GPUs) are here to stay, as they provide more than 70% of the total TOP500 FLOPs (Floating Point Operations per second); in other words, most of the computational power of the largest supercomputers in the world comes from GPUs.&lt;/p&gt;
&lt;p&gt;With new systems being installed, GPUs from at least three different vendors (i.e. AMD, Intel, NVIDIA) being used, and &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3624062.3624178&quot;&gt;a dozen or so programming models available&lt;/a&gt; for programming them, one of the hottest topics of SC23 was performance portability.&lt;/p&gt;
&lt;p&gt;Performance portability means that software written originally for one platform can not only run on a different platform but even provide comparable performance. This is a very important property for scientific software, which typically has a lifespan longer than that of the life of any modern supercomputer.&lt;/p&gt;
&lt;p&gt;Another hot topic was energy efficiency. Being able to perform more work for the same energy budget, by increasing energy efficiency, is a societal issue that is becoming increasingly pressing in the HPC community. An entire workshop was dedicated to “Sustainable Supercomputing”, with discussions ranging from how to make code more efficient, to where to build a data center to utilize renewable energy. The workshop also highlighted how simply making users aware of the energy consumption of scientific code can have an impact, especially at the political level.&lt;/p&gt;
&lt;p&gt;A small delegation from the Netherlands eScience Center comprised of Ben van Werkhoven, Alessio Sclocco, Stijn Heldens and Floris-Jan Willemsen attended SC23 to present a tutorial on “&lt;a href=&quot;https://sc23.conference-program.com/presentation/?id=tut127&amp;#x26;sess=sess217&quot;&gt;Energy-Efficient GPU Computing&lt;/a&gt;” on the first Sunday of the conference; the same engineers taught a tutorial about &lt;a href=&quot;https://blog.esciencecenter.nl/kernel-tuner-tutorial-at-supercomputing-2021-d97444d6961a&quot;&gt;Kernel Tuner&lt;/a&gt; at SC21 in St. Louis, USA. The new tutorial was also mentioned on a slide in the opening of the “&lt;a href=&quot;https://www.hpcwire.com/2023/11/29/sc23-the-ethics-of-supercomputing/&quot;&gt;Ethics in HPC&lt;/a&gt;” session, as further proof that energy and sustainability are pressing concerns of the SC community in 2023.&lt;/p&gt;
&lt;p&gt;While energy efficiency in HPC is a broad topic, our focus was on what programmers can do to reduce the energy consumption, and thereby increase the efficiency, of their GPU code. The focus on GPUs does not only come from our expertise, but also reflects the fact that GPUs are what provide most of the computational power in current supercomputers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;468&quot; height=&quot;351&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-abaffb9a.BVk59tYs_Z25QKHt.webp&quot; srcset=&quot;&quot;&gt;
Ben teaching part of the tutorial. Photo by Floris-Jan Willemsen.The tutorial was structured into four parts, each consisting of a brief lecture followed by a hands-on session. We strongly believe that participants learn more effectively when they can immediately apply what they have learned.&lt;/p&gt;
&lt;p&gt;The main takeaway of this first part could be summarized in the three action points for energy-efficient GPU code: (1) use energy-aware optimizations, (2) reduce data movement and (3) optimize clock frequencies.&lt;/p&gt;
&lt;p&gt;The second part of the tutorial was all about improving the performance of GPU code, since code that runs faster often ends up consuming less energy for the same amount of work, thereby being more efficient.&lt;/p&gt;
&lt;p&gt;After a lecture on GPU code optimizations, loosely based on a &lt;a href=&quot;https://dl.acm.org/doi/full/10.1145/3570638&quot;&gt;paper&lt;/a&gt; we published last spring, participants applied “kernel fusion” during the hands-on. This is an optimization that merges two GPU functions into one, in which it becomes apparent that optimizations can not only improve performance, but can also lower energy consumption.&lt;/p&gt;
&lt;p&gt;The third part focused on reducing data movement, crucial for energy efficiency, through mixed precision programming. This technique uses lower precision data types to decrease the number of bytes required for data storage, at the cost of introducing numerical error in the results. Fortunately, this error can be kept within an acceptable error margin by utilizing Kernel Tuner’s new capabilities for accuracy tuning, resulting in code that is faster, more energy-efficient, and shows minimal numerical error. Additionally, we showcased &lt;a href=&quot;https://github.com/KernelTuner/kernel_float&quot;&gt;Kernel Float&lt;/a&gt;, a C++ library developed by the eScience Center for mixed precision programming in NVIDIA CUDA. Participants had the chance to experiment with this in real GPU code during the hands-on session.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;528&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-3c41024a.PExc6-Rx_1KQR3O.webp&quot; srcset=&quot;&quot;&gt;
Stijn talking about mixed precision in front of the audience. Photo by Floris-Jan Willemsen.In the last part of the tutorial, we looked at how Kernel Tuner can be used to automatically tune power capping values and clock frequencies. While just improving performance is generally enough to improve the energy efficiency of a program, we also showed how finding the optimal GPU core frequency can further improve efficiency.&lt;/p&gt;
&lt;p&gt;Moreover, based on the result of a &lt;a href=&quot;https://ieeexplore.ieee.org/abstract/document/10024022&quot;&gt;paper&lt;/a&gt; published last year, we also showed that by directing Kernel Tuner to use energy efficiency as its main metric in the search for the optimal configuration, it is possible to find the most energy-efficient configuration and even quantify the acceptable loss in performance to achieve it.&lt;/p&gt;
&lt;p&gt;The tutorial was well attended, with over 30 participants, and the interaction with the audience was very positive, especially during the hands-on. We received many questions, and some participants have already contacted us online in the Kernel Tuner &lt;a href=&quot;https://github.com/orgs/KernelTuner/discussions&quot;&gt;discussion forum&lt;/a&gt;. If you would like to know more about this tutorial, the &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner_tutorial/blob/master/slides/2023_Supercomputing/SC23.pdf&quot;&gt;slides&lt;/a&gt; we used are available online (for free), and using Google Colab you can also run the hands-on exercises that we prepared for the event.&lt;/p&gt;
&lt;p&gt;Funding acknowledgments: the “Energy-Efficient GPU Computing” tutorial has been made possible by the CORTEX, COMPAS, and ESiWACE3 projects. The CORTEX project has received funding from the Dutch Research Council (NWO) in the framework of the NWA-ORC Call (file number NWA.1160.18.316). The COMPAS project has received funding from the Netherlands eScience Center (NLESC.OEC.2022.001). ESiWACE3 is funded by the European Union. This work has received funding from the European High Performance Computing Joint Undertaking (JU) and Spain, Netherlands, Germany, Sweden, Finland, Italy and France, under grant agreement No 1010930.&lt;/p&gt;</description><pubDate>Tue, 16 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;November is the time for Supercomputing, or &lt;a href=&quot;https://sc23.supercomputing.org/&quot;&gt;SC&lt;/a&gt; as it is called nowadays, and in 2023 the largest High-Performance Computing (HPC) conference in the world took place in Denver, USA, from the 12th to the 17th of that month.&lt;/p&gt;
&lt;p&gt;It was a week packed with talks, workshops, tutorials, exhibitors from all over the world, social gatherings, announcements and all of the usual SC glamour. While the eyes of the world were all pointed at the &lt;a href=&quot;https://top500.org/&quot;&gt;TOP500&lt;/a&gt; to see if Aurora would become the fastest supercomputer on the planet (spoiler: it did not; &lt;a href=&quot;https://www.hpcwire.com/off-the-wire/argonne-shares-strong-early-performance-numbers-for-aurora-supercomputer/&quot;&gt;Aurora sits at number 2 behind Frontier&lt;/a&gt;), there were many highlights of the conference.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-ef98a387.DdIm_n1F_QMNK.webp&quot; srcset=&quot;&quot;&gt;
Ben, Floris-Jan, Stijn, and Alessio standing with the SC23 logo at the Colorado Convention Center in Denver. Photo by Floris-Jan Willemsen.On the technical front, it is clear that Graphics Processing Units (GPUs) are here to stay, as they provide more than 70% of the total TOP500 FLOPs (Floating Point Operations per second); in other words, most of the computational power of the largest supercomputers in the world comes from GPUs.&lt;/p&gt;
&lt;p&gt;With new systems being installed, GPUs from at least three different vendors (i.e. AMD, Intel, NVIDIA) being used, and &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3624062.3624178&quot;&gt;a dozen or so programming models available&lt;/a&gt; for programming them, one of the hottest topics of SC23 was performance portability.&lt;/p&gt;
&lt;p&gt;Performance portability means that software written originally for one platform can not only run on a different platform but even provide comparable performance. This is a very important property for scientific software, which typically has a lifespan longer than that of the life of any modern supercomputer.&lt;/p&gt;
&lt;p&gt;Another hot topic was energy efficiency. Being able to perform more work for the same energy budget, by increasing energy efficiency, is a societal issue that is becoming increasingly pressing in the HPC community. An entire workshop was dedicated to “Sustainable Supercomputing”, with discussions ranging from how to make code more efficient, to where to build a data center to utilize renewable energy. The workshop also highlighted how simply making users aware of the energy consumption of scientific code can have an impact, especially at the political level.&lt;/p&gt;
&lt;p&gt;A small delegation from the Netherlands eScience Center comprised of Ben van Werkhoven, Alessio Sclocco, Stijn Heldens and Floris-Jan Willemsen attended SC23 to present a tutorial on “&lt;a href=&quot;https://sc23.conference-program.com/presentation/?id=tut127&amp;#x26;sess=sess217&quot;&gt;Energy-Efficient GPU Computing&lt;/a&gt;” on the first Sunday of the conference; the same engineers taught a tutorial about &lt;a href=&quot;https://blog.esciencecenter.nl/kernel-tuner-tutorial-at-supercomputing-2021-d97444d6961a&quot;&gt;Kernel Tuner&lt;/a&gt; at SC21 in St. Louis, USA. The new tutorial was also mentioned on a slide in the opening of the “&lt;a href=&quot;https://www.hpcwire.com/2023/11/29/sc23-the-ethics-of-supercomputing/&quot;&gt;Ethics in HPC&lt;/a&gt;” session, as further proof that energy and sustainability are pressing concerns of the SC community in 2023.&lt;/p&gt;
&lt;p&gt;While energy efficiency in HPC is a broad topic, our focus was on what programmers can do to reduce the energy consumption, and thereby increase the efficiency, of their GPU code. The focus on GPUs does not only come from our expertise, but also reflects the fact that GPUs are what provide most of the computational power in current supercomputers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;468&quot; height=&quot;351&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-abaffb9a.BVk59tYs_Z25QKHt.webp&quot; srcset=&quot;&quot;&gt;
Ben teaching part of the tutorial. Photo by Floris-Jan Willemsen.The tutorial was structured into four parts, each consisting of a brief lecture followed by a hands-on session. We strongly believe that participants learn more effectively when they can immediately apply what they have learned.&lt;/p&gt;
&lt;p&gt;The main takeaway of this first part could be summarized in the three action points for energy-efficient GPU code: (1) use energy-aware optimizations, (2) reduce data movement and (3) optimize clock frequencies.&lt;/p&gt;
&lt;p&gt;The second part of the tutorial was all about improving the performance of GPU code, since code that runs faster often ends up consuming less energy for the same amount of work, thereby being more efficient.&lt;/p&gt;
&lt;p&gt;After a lecture on GPU code optimizations, loosely based on a &lt;a href=&quot;https://dl.acm.org/doi/full/10.1145/3570638&quot;&gt;paper&lt;/a&gt; we published last spring, participants applied “kernel fusion” during the hands-on. This is an optimization that merges two GPU functions into one, in which it becomes apparent that optimizations can not only improve performance, but can also lower energy consumption.&lt;/p&gt;
&lt;p&gt;The third part focused on reducing data movement, crucial for energy efficiency, through mixed precision programming. This technique uses lower precision data types to decrease the number of bytes required for data storage, at the cost of introducing numerical error in the results. Fortunately, this error can be kept within an acceptable error margin by utilizing Kernel Tuner’s new capabilities for accuracy tuning, resulting in code that is faster, more energy-efficient, and shows minimal numerical error. Additionally, we showcased &lt;a href=&quot;https://github.com/KernelTuner/kernel_float&quot;&gt;Kernel Float&lt;/a&gt;, a C++ library developed by the eScience Center for mixed precision programming in NVIDIA CUDA. Participants had the chance to experiment with this in real GPU code during the hands-on session.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Talking about energy-efficient GPU computing at SC23&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;528&quot; src=&quot;https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-3c41024a.PExc6-Rx_1KQR3O.webp&quot; srcset=&quot;&quot;&gt;
Stijn talking about mixed precision in front of the audience. Photo by Floris-Jan Willemsen.In the last part of the tutorial, we looked at how Kernel Tuner can be used to automatically tune power capping values and clock frequencies. While just improving performance is generally enough to improve the energy efficiency of a program, we also showed how finding the optimal GPU core frequency can further improve efficiency.&lt;/p&gt;
&lt;p&gt;Moreover, based on the result of a &lt;a href=&quot;https://ieeexplore.ieee.org/abstract/document/10024022&quot;&gt;paper&lt;/a&gt; published last year, we also showed that by directing Kernel Tuner to use energy efficiency as its main metric in the search for the optimal configuration, it is possible to find the most energy-efficient configuration and even quantify the acceptable loss in performance to achieve it.&lt;/p&gt;
&lt;p&gt;The tutorial was well attended, with over 30 participants, and the interaction with the audience was very positive, especially during the hands-on. We received many questions, and some participants have already contacted us online in the Kernel Tuner &lt;a href=&quot;https://github.com/orgs/KernelTuner/discussions&quot;&gt;discussion forum&lt;/a&gt;. If you would like to know more about this tutorial, the &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner_tutorial/blob/master/slides/2023_Supercomputing/SC23.pdf&quot;&gt;slides&lt;/a&gt; we used are available online (for free), and using Google Colab you can also run the hands-on exercises that we prepared for the event.&lt;/p&gt;
&lt;p&gt;Funding acknowledgments: the “Energy-Efficient GPU Computing” tutorial has been made possible by the CORTEX, COMPAS, and ESiWACE3 projects. The CORTEX project has received funding from the Dutch Research Council (NWO) in the framework of the NWA-ORC Call (file number NWA.1160.18.316). The COMPAS project has received funding from the Netherlands eScience Center (NLESC.OEC.2022.001). ESiWACE3 is funded by the European Union. This work has received funding from the European High Performance Computing Joint Undertaking (JU) and Spain, Netherlands, Germany, Sweden, Finland, Italy and France, under grant agreement No 1010930.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/talking-about-energy-efficient-gpu-compu-ef98a387.DdIm_n1F.jpeg" medium="image"/><author>Alessio Sclocco</author></item><item><title>How to ensure that others can run your code</title><link>https://blog.esciencecenter.nl/posts/2023-12-12---how-to-ensure-that-others-can-run-your-code</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-12-12---how-to-ensure-that-others-can-run-your-code</guid><description>&lt;p&gt;6&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://juliangonggrijp.com/&quot;&gt;Julian Gonggrijp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog was originally written for the &lt;em&gt;&lt;a href=&quot;https://www.uu.nl/en/news/how-to-ensure-that-others-can-run-your-code?utm_source=Maileon&amp;#x26;utm_medium=email&amp;#x26;utm_campaign=Centre+for+Digital+Humanities+Newsletter+-+November+2023&amp;#x26;utm_content=https%3A%2F%2Fwww.uu.nl%2Fen%2Fnews%2Fhow-to-ensure-that-others-can-run-your-code&quot;&gt;&lt;em&gt;Utrecht University (UU) website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; by Scientific Programmer &lt;em&gt;&lt;a href=&quot;https://www.uu.nl/staff/JGonggrijp&quot;&gt;&lt;em&gt;Julian Gonggrijp&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;. We enjoyed this useful blog post, and hope you will too! If you’re looking for more resources on reusable code, also see &lt;em&gt;&lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/code-reuse&quot;&gt;&lt;em&gt;this chapter&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in &lt;em&gt;&lt;a href=&quot;https://the-turing-way.netlify.app/index.html&quot;&gt;&lt;em&gt;the Turing Way&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is the last eScience Center blog post of 2023, but fear not! We will be back in January with lots more interesting writing from our Center.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to ensure that others can run your code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-ensure-that-others-can-run-your-c-4f7aaef5.sGCyufxL_ZouTsr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@thisisengineering?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;ThisisEngineering RAEng&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Imagine the following scenario. You need to analyze your research data. As is often the case in research, your analysis is going to be similar to, but not quite the same as, previous research. You look for existing software that can do the job for you, but nothing suits your situation. You decide this will be a good opportunity to brush up on your Python-fu. You sit down at your laptop, crack your knuckles and start hacking.&lt;/p&gt;
&lt;p&gt;The analysis is far from trivial; so is writing the code. You learn several new things along the way, some of which are interesting, gain a few grey hairs, spend two very late “afternoons” with a colleague to squash a notorious bug. Ten weeks and several hundred lines of code later, though, you manage to make it work. You toast with your colleague, present your analysis at a conference and get very positive responses. Your own software is a great success!&lt;/p&gt;
&lt;p&gt;At the conference, you meet a colleague from a different institution. She has a totally different dataset, but she might be able to apply the exact same analysis. You are excited: you might be onto a new methodology, worthy of several papers and a grant or two.&lt;/p&gt;
&lt;p&gt;A few months later, you hear back from your new acquaintance. She found time to experiment with your new method and she asks for your code. You were already prepared for that. Your code is on &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/tools/software-and-computing/github-and-git&quot;&gt;GitHub&lt;/a&gt;, it has a README and you even thought of an open source license, so she can freely adapt the code if necessary. You eagerly send her the link.&lt;/p&gt;
&lt;p&gt;You don’t hear back for a while. After two months, you take a deep breath and send her an email. Was she able to get any useful results out of the analysis? Alas, it turns out she did not even reach that stage. She was unable to run your code, even with help from a student assistant from the computer science department. The code would crash with error messages that they could not get past. She went with the conventional analysis in the end; the results were not spectacular, but she managed to squeeze a publication out of it and moved on.&lt;/p&gt;
&lt;p&gt;Of course, you are disappointed. Did you just spend ten weeks of your life developing new software, only to find that it will never run through another dataset? Should you have hired a scientific programmer instead of writing the analysis yourself? Fortunately, at this point, you run into this blog, saving you from a depression.&lt;/p&gt;
&lt;h2 id=&quot;why-runnable-code-matters&quot;&gt;Why runnable code matters&lt;/h2&gt;
&lt;p&gt;In the above scenario, it is obvious that other people must be able to run your code because you want your method to be reusable. However, even if you write a quick one-off just for your own research, it is important to ensure that somebody else could run your code. There are two main reasons for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As Stefano mentioned &lt;a href=&quot;https://www.uu.nl/en/news/what-is-version-control-and-what-are-the-benefits-of-it-for-you&quot;&gt;in the previous blog&lt;/a&gt; on UU’s website, your future self is another person. You might upgrade or replace the PC on which you wrote the code and you might forget some of the preparatory magic incantations. Even in case of a one-off, you might want to run the code again in order to double-check your results, to add new datapoints or even just to impress your spouse. 😉 By ensuring that the code is easy to run while everything is still fresh in memory, you can save time (and dignity) in the future.&lt;/li&gt;
&lt;li&gt;By ensuring that your code is easy to run, you make it easy for others to repeat and verify your work. This can be a great way to convince people!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Making sure that code is easy to &lt;em&gt;run&lt;/em&gt; is different from ensuring that the code is easy to &lt;em&gt;read&lt;/em&gt;. The latter is certainly also worthwhile, for different reasons, but that is for another blog post.&lt;/p&gt;
&lt;p&gt;Making the code easy to run is also not exactly the same as making it easy to install. If you are serious about your software, you will likely think about publishing it to a package repository (which is also for another blog post) so that it can be easily found and installed, and you should! However, while this technically makes your code easy to run as well, this does not replace making it easy to run the code when obtaining a raw copy. At the very least, the future developer who is going to update the package will need to run it &lt;em&gt;without&lt;/em&gt; installing it from a package repository.&lt;/p&gt;
&lt;h2 id=&quot;why-is-code-not-runnable-out-of-the-box&quot;&gt;Why is code not runnable out of the box?&lt;/h2&gt;
&lt;p&gt;Let us be honest: it is &lt;em&gt;infuriating&lt;/em&gt; that code never runs out of the box. We can double-click any picture, PDF file or spreadsheet and it will just open and work, but for some reason, when it comes to code, we still seem to be living in the 1960s. Whenever we receive code from a colleague, we usually first have to install additional software, learn a few new skills, massage our data in just the right shape, take two non-obvious preparatory steps and make a rain dance before we can even hope to be able to run it. Then, there are the unexpected errors.&lt;/p&gt;
&lt;p&gt;While this is no excuse by itself, creating infrastructure that makes code easy to run is notoriously difficult. Code is run by other code, and that other code has to be extremely flexible in order to cater to all the possible applications. This by itself already requires highly specialized skills. On top of that, the software landscape is constantly moving because people keep finding new use cases for code, so everyone is constantly struggling to keep their own code compatible with somebody else’s code. Between all that effort, attention tends to be drawn away from keeping the software usable. There have been many honourable attempts at improving this situation, some of them quite successful — I will mention a few below — but even those projects cannot escape the constant struggle to keep their infrastructure current. Making running code as easy as a double-click remains elusive for now.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to ensure that others can run your code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-ensure-that-others-can-run-your-c-5683b09b.mD9iurTK_Z1v6WfR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sigmund?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Sigmund&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;six-things-that-should-be-documented-for-any-code&quot;&gt;Six things that should be documented for any code&lt;/h2&gt;
&lt;p&gt;The first thing we can do, is to transfer as much knowledge as possible. The following checklist may help you to ensure that you include all the important details in your README. This is a &lt;a href=&quot;https://github.com/UUDigitalHumanitieslab/tscan/blob/master/README.md&quot;&gt;good example&lt;/a&gt; of a correct README.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why does your code exist? This may seem obvious, but you will be surprised at how often this information is left out. Knowing what your code is about will motivate prospective users to try it for the right reasons. It will also help clarify why things are done a certain way, why some features are included and others omitted.&lt;/li&gt;
&lt;li&gt;What other software needs to be installed before your code can be run? Most unexpected errors, where the software worked for the programmer but not for the user, are due to dependencies that are either missing or have a mismatching version. To prevent this, list the version of your programming language as well as all the packages that your code depends on and be as specific as possible about which versions are expected to work. Also explain how to obtain all dependencies.&lt;/li&gt;
&lt;li&gt;For what type of data is your code suitable and how should it be stored? Include everything relevant: file format versions, required and optional fields, column order, maximum input size, character encoding, etcetera.&lt;/li&gt;
&lt;li&gt;What steps should be followed to use your code? As programmers, this is usually the first thing we think of when writing a README, so it tends to be relatively well documented. For completeness, I will mention that you need to clearly distinguish between steps that need to be run every time or only the first time, describe the different modes/scenarios/use cases for which the code may be used, discuss optional and required arguments, and explain the expected output.&lt;/li&gt;
&lt;li&gt;How to reach out for help? Despite your best efforts to document everything, users can still run into trouble. Some users will not reach out unless you make them aware of the option. An email address is good, a link to an issue tracker on GitHub, Codeberg, GitLab or BitBucket is even better.&lt;/li&gt;
&lt;li&gt;Your software license. Technically, this does not really change how easy or difficult it is to run your code, but it does need to be in the README.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dont-be-that-person&quot;&gt;Don’t be that person&lt;/h2&gt;
&lt;p&gt;Good documentation will get you a long way, but if there are intrinsic hurdles in your code, users will still struggle and possibly give up. The most common way for this to happen, is when the code is too specific to the current situation of the programmer.&lt;/p&gt;
&lt;p&gt;If your code only runs on your computer with your files on it, in January under easterly wind while the moon is waning, then your colleagues will likely find it difficult to run your code. Possibly more problematic is that, one year into the future, even you will not be able to run your code.&lt;/p&gt;
&lt;p&gt;For example, a line like the following is all too common in research software:&lt;/p&gt;
&lt;p&gt;DATAFILE = “C:\Users\Frank\Downloads\KNMI_klimaat_DeBilt_1980-2010.CSV”Hardcoded assumptions like these are errors waiting to happen. They can be avoided by making parameters like file paths user-configurable. For example, in Python, you can use the &lt;code&gt;[argparse](https://docs.python.org/3/library/argparse.html)&lt;/code&gt; module to accept file paths as command line arguments.&lt;/p&gt;
&lt;h2 id=&quot;use-helpful-standards&quot;&gt;Use helpful standards&lt;/h2&gt;
&lt;p&gt;As I mentioned before, there have been many attempts at improving the ease with which code can be run. None of them will reduce the effort to a double click, but the more you leverage these projects in your own code, the easier it will be to run it. I mention a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When working with Python, you can list your package dependencies in a &lt;code&gt;[requirements.txt](https://pip.pypa.io/en/stable/reference/requirements-file-format/)&lt;/code&gt; and tell users to run &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;. This saves users from installing the packages manually and ensures that they will have the right version of each package. Even better is to use a &lt;a href=&quot;https://docs.python.org/3/library/venv.html&quot;&gt;virtual environment&lt;/a&gt; and manage the dependencies with &lt;code&gt;[pip-tools](https://pypi.org/project/pip-tools/)&lt;/code&gt; or &lt;code&gt;[pipenv](https://pypi.org/project/pipenv/)&lt;/code&gt; (which is a high-level wrapper around &lt;code&gt;venv&lt;/code&gt; and &lt;code&gt;pip-tools&lt;/code&gt;). Similar solutions exist for most other programming languages.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Docker_(software)&quot;&gt;Docker&lt;/a&gt; can take the hassle out of installing software in general. You define what installation steps should be taken and how to start the software. Your colleagues only need to run Docker in order to make it happen. Installing Docker itself is a bit tricky, though, especially on Windows, so it is somewhat of a double-edged sword.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mybinder.org/&quot;&gt;Binder&lt;/a&gt; lets you publish and run Docker images in the cloud (i.e., on somebody else’s computer), so that your colleagues do not need to install Docker. It also automatically selects predefined Docker images for a few common types of projects, so you do not need to define your own Dockerfile. The only drawback is that the code tends to start with a noticable delay. It is mostly suitable for visualizations.&lt;/li&gt;
&lt;li&gt;Notebooks provide a handy way to combine scripts, visualizations and documentation in a single file that is relatively easy to run. Dependency management is greatly simplified in notebooks. &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter&lt;/a&gt; is probably the most widely known notebook format, which supports Julia, Python and R (hence the name). A honorable mention goes to &lt;a href=&quot;https://plutojl.org/&quot;&gt;Pluto&lt;/a&gt;, which only supports Julia but which is probably the easiest and most intuitive notebook environment available. Both of these can run in the cloud using Binder. &lt;a href=&quot;https://cocalc.com/&quot;&gt;CoCalc&lt;/a&gt; and &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Google Colab&lt;/a&gt; provide additional cloud hosting options for Jupyter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-your-colleague-as-a-guinea-pig&quot;&gt;Use your colleague as a guinea pig&lt;/h2&gt;
&lt;p&gt;If you follow all the tips above, your code is easier to run than if you don’t. The best way to be sure, however, is to test-drive your code with an unsuspecting colleague. This colleague must not have been involved in the writing of the code. Ideally, you find a colleague who is interested in the problem domain, but who tends to use a different programming environment (or none at all) and a different operating system (so if you wrote your code on a Mac, try to find a tester who runs Windows). Don’t sit next to your colleague during testing; let them figure it out using only the documentation.&lt;/p&gt;
&lt;p&gt;If your tester can run your code without trouble, you can be fairly confident that your code is reusable. If not, keep adjusting until it is. Remember that it is always your code or your documentation that needs fixing, never your colleague.&lt;/p&gt;
&lt;h2 id=&quot;join-the-crowd&quot;&gt;Join the crowd&lt;/h2&gt;
&lt;p&gt;It is challenging to make reusable software, and you are not the first researcher to embark on this adventure. Utrecht University has various initiatives where you can meet fellow programmers and exchange tips and tricks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research Data Management Support organizes a monthly &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/workshops/programming-cafe&quot;&gt;Programming Café&lt;/a&gt; or hop by at the &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/workshops/walk-in-hours-research-data-and-software&quot;&gt;Walk-in Hours&lt;/a&gt; at the &lt;a href=&quot;https://maps.app.goo.gl/YV7fGkAtcT9PmWjdA&quot;&gt;Library Utrecht Science Park&lt;/a&gt; that are held every Monday afternoon.&lt;/li&gt;
&lt;li&gt;If you happen to work at the Utrecht University Faculty of Humanities, you can also visit the weekly &lt;a href=&quot;https://cdh.uu.nl/walk-in-hours/&quot;&gt;Digital Humanities walk-in hour&lt;/a&gt;, or email the &lt;a href=&quot;https://cdh.uu.nl/&quot;&gt;Centre for Digital Humanities&lt;/a&gt; at any time for advice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wish you much inspiration and fun on your voyage!&lt;/p&gt;</description><pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;6&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://juliangonggrijp.com/&quot;&gt;Julian Gonggrijp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog was originally written for the &lt;em&gt;&lt;a href=&quot;https://www.uu.nl/en/news/how-to-ensure-that-others-can-run-your-code?utm_source=Maileon&amp;#x26;utm_medium=email&amp;#x26;utm_campaign=Centre+for+Digital+Humanities+Newsletter+-+November+2023&amp;#x26;utm_content=https%3A%2F%2Fwww.uu.nl%2Fen%2Fnews%2Fhow-to-ensure-that-others-can-run-your-code&quot;&gt;&lt;em&gt;Utrecht University (UU) website&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; by Scientific Programmer &lt;em&gt;&lt;a href=&quot;https://www.uu.nl/staff/JGonggrijp&quot;&gt;&lt;em&gt;Julian Gonggrijp&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;. We enjoyed this useful blog post, and hope you will too! If you’re looking for more resources on reusable code, also see &lt;em&gt;&lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/code-reuse&quot;&gt;&lt;em&gt;this chapter&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; in &lt;em&gt;&lt;a href=&quot;https://the-turing-way.netlify.app/index.html&quot;&gt;&lt;em&gt;the Turing Way&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is the last eScience Center blog post of 2023, but fear not! We will be back in January with lots more interesting writing from our Center.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to ensure that others can run your code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-ensure-that-others-can-run-your-c-4f7aaef5.sGCyufxL_ZouTsr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@thisisengineering?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;ThisisEngineering RAEng&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Imagine the following scenario. You need to analyze your research data. As is often the case in research, your analysis is going to be similar to, but not quite the same as, previous research. You look for existing software that can do the job for you, but nothing suits your situation. You decide this will be a good opportunity to brush up on your Python-fu. You sit down at your laptop, crack your knuckles and start hacking.&lt;/p&gt;
&lt;p&gt;The analysis is far from trivial; so is writing the code. You learn several new things along the way, some of which are interesting, gain a few grey hairs, spend two very late “afternoons” with a colleague to squash a notorious bug. Ten weeks and several hundred lines of code later, though, you manage to make it work. You toast with your colleague, present your analysis at a conference and get very positive responses. Your own software is a great success!&lt;/p&gt;
&lt;p&gt;At the conference, you meet a colleague from a different institution. She has a totally different dataset, but she might be able to apply the exact same analysis. You are excited: you might be onto a new methodology, worthy of several papers and a grant or two.&lt;/p&gt;
&lt;p&gt;A few months later, you hear back from your new acquaintance. She found time to experiment with your new method and she asks for your code. You were already prepared for that. Your code is on &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/tools/software-and-computing/github-and-git&quot;&gt;GitHub&lt;/a&gt;, it has a README and you even thought of an open source license, so she can freely adapt the code if necessary. You eagerly send her the link.&lt;/p&gt;
&lt;p&gt;You don’t hear back for a while. After two months, you take a deep breath and send her an email. Was she able to get any useful results out of the analysis? Alas, it turns out she did not even reach that stage. She was unable to run your code, even with help from a student assistant from the computer science department. The code would crash with error messages that they could not get past. She went with the conventional analysis in the end; the results were not spectacular, but she managed to squeeze a publication out of it and moved on.&lt;/p&gt;
&lt;p&gt;Of course, you are disappointed. Did you just spend ten weeks of your life developing new software, only to find that it will never run through another dataset? Should you have hired a scientific programmer instead of writing the analysis yourself? Fortunately, at this point, you run into this blog, saving you from a depression.&lt;/p&gt;
&lt;h2 id=&quot;why-runnable-code-matters&quot;&gt;Why runnable code matters&lt;/h2&gt;
&lt;p&gt;In the above scenario, it is obvious that other people must be able to run your code because you want your method to be reusable. However, even if you write a quick one-off just for your own research, it is important to ensure that somebody else could run your code. There are two main reasons for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As Stefano mentioned &lt;a href=&quot;https://www.uu.nl/en/news/what-is-version-control-and-what-are-the-benefits-of-it-for-you&quot;&gt;in the previous blog&lt;/a&gt; on UU’s website, your future self is another person. You might upgrade or replace the PC on which you wrote the code and you might forget some of the preparatory magic incantations. Even in case of a one-off, you might want to run the code again in order to double-check your results, to add new datapoints or even just to impress your spouse. 😉 By ensuring that the code is easy to run while everything is still fresh in memory, you can save time (and dignity) in the future.&lt;/li&gt;
&lt;li&gt;By ensuring that your code is easy to run, you make it easy for others to repeat and verify your work. This can be a great way to convince people!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Making sure that code is easy to &lt;em&gt;run&lt;/em&gt; is different from ensuring that the code is easy to &lt;em&gt;read&lt;/em&gt;. The latter is certainly also worthwhile, for different reasons, but that is for another blog post.&lt;/p&gt;
&lt;p&gt;Making the code easy to run is also not exactly the same as making it easy to install. If you are serious about your software, you will likely think about publishing it to a package repository (which is also for another blog post) so that it can be easily found and installed, and you should! However, while this technically makes your code easy to run as well, this does not replace making it easy to run the code when obtaining a raw copy. At the very least, the future developer who is going to update the package will need to run it &lt;em&gt;without&lt;/em&gt; installing it from a package repository.&lt;/p&gt;
&lt;h2 id=&quot;why-is-code-not-runnable-out-of-the-box&quot;&gt;Why is code not runnable out of the box?&lt;/h2&gt;
&lt;p&gt;Let us be honest: it is &lt;em&gt;infuriating&lt;/em&gt; that code never runs out of the box. We can double-click any picture, PDF file or spreadsheet and it will just open and work, but for some reason, when it comes to code, we still seem to be living in the 1960s. Whenever we receive code from a colleague, we usually first have to install additional software, learn a few new skills, massage our data in just the right shape, take two non-obvious preparatory steps and make a rain dance before we can even hope to be able to run it. Then, there are the unexpected errors.&lt;/p&gt;
&lt;p&gt;While this is no excuse by itself, creating infrastructure that makes code easy to run is notoriously difficult. Code is run by other code, and that other code has to be extremely flexible in order to cater to all the possible applications. This by itself already requires highly specialized skills. On top of that, the software landscape is constantly moving because people keep finding new use cases for code, so everyone is constantly struggling to keep their own code compatible with somebody else’s code. Between all that effort, attention tends to be drawn away from keeping the software usable. There have been many honourable attempts at improving this situation, some of them quite successful — I will mention a few below — but even those projects cannot escape the constant struggle to keep their infrastructure current. Making running code as easy as a double-click remains elusive for now.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to ensure that others can run your code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-ensure-that-others-can-run-your-c-5683b09b.mD9iurTK_Z1v6WfR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sigmund?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Sigmund&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;six-things-that-should-be-documented-for-any-code&quot;&gt;Six things that should be documented for any code&lt;/h2&gt;
&lt;p&gt;The first thing we can do, is to transfer as much knowledge as possible. The following checklist may help you to ensure that you include all the important details in your README. This is a &lt;a href=&quot;https://github.com/UUDigitalHumanitieslab/tscan/blob/master/README.md&quot;&gt;good example&lt;/a&gt; of a correct README.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why does your code exist? This may seem obvious, but you will be surprised at how often this information is left out. Knowing what your code is about will motivate prospective users to try it for the right reasons. It will also help clarify why things are done a certain way, why some features are included and others omitted.&lt;/li&gt;
&lt;li&gt;What other software needs to be installed before your code can be run? Most unexpected errors, where the software worked for the programmer but not for the user, are due to dependencies that are either missing or have a mismatching version. To prevent this, list the version of your programming language as well as all the packages that your code depends on and be as specific as possible about which versions are expected to work. Also explain how to obtain all dependencies.&lt;/li&gt;
&lt;li&gt;For what type of data is your code suitable and how should it be stored? Include everything relevant: file format versions, required and optional fields, column order, maximum input size, character encoding, etcetera.&lt;/li&gt;
&lt;li&gt;What steps should be followed to use your code? As programmers, this is usually the first thing we think of when writing a README, so it tends to be relatively well documented. For completeness, I will mention that you need to clearly distinguish between steps that need to be run every time or only the first time, describe the different modes/scenarios/use cases for which the code may be used, discuss optional and required arguments, and explain the expected output.&lt;/li&gt;
&lt;li&gt;How to reach out for help? Despite your best efforts to document everything, users can still run into trouble. Some users will not reach out unless you make them aware of the option. An email address is good, a link to an issue tracker on GitHub, Codeberg, GitLab or BitBucket is even better.&lt;/li&gt;
&lt;li&gt;Your software license. Technically, this does not really change how easy or difficult it is to run your code, but it does need to be in the README.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dont-be-that-person&quot;&gt;Don’t be that person&lt;/h2&gt;
&lt;p&gt;Good documentation will get you a long way, but if there are intrinsic hurdles in your code, users will still struggle and possibly give up. The most common way for this to happen, is when the code is too specific to the current situation of the programmer.&lt;/p&gt;
&lt;p&gt;If your code only runs on your computer with your files on it, in January under easterly wind while the moon is waning, then your colleagues will likely find it difficult to run your code. Possibly more problematic is that, one year into the future, even you will not be able to run your code.&lt;/p&gt;
&lt;p&gt;For example, a line like the following is all too common in research software:&lt;/p&gt;
&lt;p&gt;DATAFILE = “C:\Users\Frank\Downloads\KNMI_klimaat_DeBilt_1980-2010.CSV”Hardcoded assumptions like these are errors waiting to happen. They can be avoided by making parameters like file paths user-configurable. For example, in Python, you can use the &lt;code&gt;[argparse](https://docs.python.org/3/library/argparse.html)&lt;/code&gt; module to accept file paths as command line arguments.&lt;/p&gt;
&lt;h2 id=&quot;use-helpful-standards&quot;&gt;Use helpful standards&lt;/h2&gt;
&lt;p&gt;As I mentioned before, there have been many attempts at improving the ease with which code can be run. None of them will reduce the effort to a double click, but the more you leverage these projects in your own code, the easier it will be to run it. I mention a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When working with Python, you can list your package dependencies in a &lt;code&gt;[requirements.txt](https://pip.pypa.io/en/stable/reference/requirements-file-format/)&lt;/code&gt; and tell users to run &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;. This saves users from installing the packages manually and ensures that they will have the right version of each package. Even better is to use a &lt;a href=&quot;https://docs.python.org/3/library/venv.html&quot;&gt;virtual environment&lt;/a&gt; and manage the dependencies with &lt;code&gt;[pip-tools](https://pypi.org/project/pip-tools/)&lt;/code&gt; or &lt;code&gt;[pipenv](https://pypi.org/project/pipenv/)&lt;/code&gt; (which is a high-level wrapper around &lt;code&gt;venv&lt;/code&gt; and &lt;code&gt;pip-tools&lt;/code&gt;). Similar solutions exist for most other programming languages.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Docker_(software)&quot;&gt;Docker&lt;/a&gt; can take the hassle out of installing software in general. You define what installation steps should be taken and how to start the software. Your colleagues only need to run Docker in order to make it happen. Installing Docker itself is a bit tricky, though, especially on Windows, so it is somewhat of a double-edged sword.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mybinder.org/&quot;&gt;Binder&lt;/a&gt; lets you publish and run Docker images in the cloud (i.e., on somebody else’s computer), so that your colleagues do not need to install Docker. It also automatically selects predefined Docker images for a few common types of projects, so you do not need to define your own Dockerfile. The only drawback is that the code tends to start with a noticable delay. It is mostly suitable for visualizations.&lt;/li&gt;
&lt;li&gt;Notebooks provide a handy way to combine scripts, visualizations and documentation in a single file that is relatively easy to run. Dependency management is greatly simplified in notebooks. &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter&lt;/a&gt; is probably the most widely known notebook format, which supports Julia, Python and R (hence the name). A honorable mention goes to &lt;a href=&quot;https://plutojl.org/&quot;&gt;Pluto&lt;/a&gt;, which only supports Julia but which is probably the easiest and most intuitive notebook environment available. Both of these can run in the cloud using Binder. &lt;a href=&quot;https://cocalc.com/&quot;&gt;CoCalc&lt;/a&gt; and &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Google Colab&lt;/a&gt; provide additional cloud hosting options for Jupyter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-your-colleague-as-a-guinea-pig&quot;&gt;Use your colleague as a guinea pig&lt;/h2&gt;
&lt;p&gt;If you follow all the tips above, your code is easier to run than if you don’t. The best way to be sure, however, is to test-drive your code with an unsuspecting colleague. This colleague must not have been involved in the writing of the code. Ideally, you find a colleague who is interested in the problem domain, but who tends to use a different programming environment (or none at all) and a different operating system (so if you wrote your code on a Mac, try to find a tester who runs Windows). Don’t sit next to your colleague during testing; let them figure it out using only the documentation.&lt;/p&gt;
&lt;p&gt;If your tester can run your code without trouble, you can be fairly confident that your code is reusable. If not, keep adjusting until it is. Remember that it is always your code or your documentation that needs fixing, never your colleague.&lt;/p&gt;
&lt;h2 id=&quot;join-the-crowd&quot;&gt;Join the crowd&lt;/h2&gt;
&lt;p&gt;It is challenging to make reusable software, and you are not the first researcher to embark on this adventure. Utrecht University has various initiatives where you can meet fellow programmers and exchange tips and tricks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research Data Management Support organizes a monthly &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/workshops/programming-cafe&quot;&gt;Programming Café&lt;/a&gt; or hop by at the &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management/workshops/walk-in-hours-research-data-and-software&quot;&gt;Walk-in Hours&lt;/a&gt; at the &lt;a href=&quot;https://maps.app.goo.gl/YV7fGkAtcT9PmWjdA&quot;&gt;Library Utrecht Science Park&lt;/a&gt; that are held every Monday afternoon.&lt;/li&gt;
&lt;li&gt;If you happen to work at the Utrecht University Faculty of Humanities, you can also visit the weekly &lt;a href=&quot;https://cdh.uu.nl/walk-in-hours/&quot;&gt;Digital Humanities walk-in hour&lt;/a&gt;, or email the &lt;a href=&quot;https://cdh.uu.nl/&quot;&gt;Centre for Digital Humanities&lt;/a&gt; at any time for advice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wish you much inspiration and fun on your voyage!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-to-ensure-that-others-can-run-your-c-4f7aaef5.sGCyufxL.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Machine Learning Machinery for Quantum Chemistry</title><link>https://blog.esciencecenter.nl/posts/2023-12-06---machine-learning-machinery-for-quantum-chemistry</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-12-06---machine-learning-machinery-for-quantum-chemistry</guid><description>&lt;p&gt;Machine learning techniques are impacting all areas of science, and molecular simulations are not spared. This blog post shows how to make use of the tools and techniques developed for machine learning to facilitate high-accuracy electronic structure calculations.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-17dd1dc0.j4LJOKz3_Z24ylJU.webp&quot; srcset=&quot;&quot;&gt;
Quantum chemistry, the application of quantum mechanics to the study of molecular systems, is a powerful approach to design better materials, more efficient catalysts, and even better drugs. If you are reading this text on a fancy 4K &lt;a href=&quot;https://en.wikipedia.org/wiki/OLED&quot;&gt;OLED&lt;/a&gt; screen, chances are that quantum chemistry was used to fine-tune the light emission properties of the molecules that are shooting photons at you.&lt;/p&gt;
&lt;p&gt;Quantum chemistry is, however, not a single technique, but the aggregation of many approaches that have been developed over many decades by many people. Some methods are computationally inexpensive and usually not so accurate, while others require important computational resources but can reach a higher degree of accuracy.&lt;/p&gt;
&lt;p&gt;Quantum Monte Carlo (QMC) simulations are particularly interesting as they can reach a high degree of accuracy and can also be efficiently parallelized on very large computational resources. Many software packages, like &lt;a href=&quot;https://github.com/filippi-claudia/champ&quot;&gt;CHAMP &lt;/a&gt;or &lt;a href=&quot;https://github.com/TREX-CoE/qmcchem2&quot;&gt;QMC=CHEM&lt;/a&gt;, provide solutions to perform QMC simulations and have been used in countless scientific publications.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;300&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-d0f2af93.VGSxax-R_Z20BpCy.webp&quot; srcset=&quot;&quot;&gt;
Illustration of the QMC approach. We first define a wave function containing tunable parameters. We sample the associated density and compute the system’s energy and its gradient w.r.t. the tunable parameters. We then update the value of the parameters and start again until we find the minimum value of the total energyTo understand how QMC works, let’s consider a small molecule of, let’s say, benzene. To keep things simple we are going to assume that all the electrons of the molecule are located around its center following a Gaussian distribution of variable width. To compute the energy of the molecule, we first sample this distribution to obtain representative configurations of the electronic positions. This can be done via a variety of techniques, for example, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm&quot;&gt;Metropolis-Hastings&lt;/a&gt; algorithm. Computing the energy of the electrons in these configurations and taking averaging them can finally be used to approximate the total energy of the molecule.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Variational_method_(quantum_mechanics)&quot;&gt;cornerstone of quantum chemistry&lt;/a&gt; tells us that the most accurate description of the molecule is obtained for the lowest value of its total energy. In our simple example, we can tweak the width of the Gaussian distribution until we find the minimal value of the total energy. If you now think, &lt;em&gt;hey that almost looks like a machine learning problem&lt;/em&gt;, you’re not completely wrong. All we need is to encode the wave function in some sort of neural network.&lt;/p&gt;
&lt;h2 id=&quot;lets-start-with-a-toy-problem&quot;&gt;Let’s start with a toy problem&lt;/h2&gt;
&lt;p&gt;Let’s first look at a toy problem that you may have encountered in your undergraduate studies: a single particle in a one-dimensional potential. We pick here the Morse potential as it is simple enough yet non-trivial.&lt;/p&gt;
&lt;p&gt;We choose here to use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Radial_basis_function_network&quot;&gt;radial basis function (RBF) neural network&lt;/a&gt; to encode the wave function of this one-dimensional potential. In our RBF network, the input node encodes the position of the particle and each hidden node computes the value of a particular Gaussian function at this location. These values are then summed up on the output node to yield the value of the wave function at the particle’s location. This architecture therefore expresses the wave function of our particle as a sum of Gaussian functions, which is sufficient for this particular problem.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-c2c21611.O8Y3_5tb_8m2AB.webp&quot; srcset=&quot;&quot;&gt;
Schrodinet in action. The solver optimizes the positions, widths, and heights of all the Gaussian functions composing the RBF network to minimize the energy of the system.&lt;/p&gt;
&lt;h2 id=&quot;qmctorch-for-molecules&quot;&gt;QMCTorch for molecules&lt;/h2&gt;
&lt;p&gt;While replacing first-year university students with simple neural networks is appealing, it would be even better to apply the same machinery to more complex cases, for example, molecules. Unfortunately, the wave functions of molecular systems are much more complex than the one of a single particle trapped in a one-dimensional potential. All the electrons of the molecule interact with each other and also with the atomic nuclei and everything becomes very complicated very quickly. Fortunately, many scientists have given us a good understanding of the ingredients that should make up the wave functions of these systems.&lt;/p&gt;
&lt;p&gt;Armed with this vast amount of knowledge, and a little bit of tenacity, we have developed &lt;a href=&quot;https://github.com/NLESC-JCER/QMCTOrch&quot;&gt;&lt;strong&gt;QMCTorch&lt;/strong&gt;&lt;/a&gt;** **a Python package that allows to run QMC simulations of molecular systems using neural network wave functions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;392&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-5f17922c.BW2PfwlE_Z3DJiy.webp&quot; srcset=&quot;&quot;&gt;
Representation of the neural network that encodes the wave function in QMCTorch. Starting from the atomic and electronic coordinates, different layers progressively compute the value of the wave function.Neural networks in QMCTorch take the positions of the electrons and atoms as inputs and compute the value of the wave function as an output. In between the input and output layers, many layers compute the different ingredients involved in the definition of the molecular wave function. These layers have parameters that can be specified by the user or extracted from external chemistry codes such as &lt;a href=&quot;https://pyscf.org/&quot;&gt;pyscf&lt;/a&gt; or &lt;a href=&quot;https://www.scm.com/product/adf/&quot;&gt;ADF&lt;/a&gt;. These parameters can be further optimized to lead to an even more accurate wave function.&lt;/p&gt;
&lt;p&gt;As the name indicates, QMCTorch is based on the popular deep learning framework &lt;a href=&quot;https://pytorch.org/&quot;&gt;PyTorch &lt;/a&gt;and leverages automatic differentiation to compute various derivatives needed in the optimization process. The use of automatic differentiation allows users to easily explore new flavors of the wave function without having to analytically compute all its derivatives. QMCTorch can also make use of multiple GPUs to accelerate the simulations thanks to the native capabilities of PyTorch and the distributed deep learning library &lt;a href=&quot;https://horovod.ai/&quot;&gt;Horovd&lt;/a&gt;. For more information on QMCTorch, go see the &lt;a href=&quot;https://qmctorch.readthedocs.io/en/latest/&quot;&gt;code documentation&lt;/a&gt; or the &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.05472&quot;&gt;paper&lt;/a&gt; in the Journal of Open Source Software.&lt;/p&gt;
&lt;p&gt;To use the code we first need to define a molecule through its atomic positions. QMCTorch allows for a few different flavors of wave functions to be used and we therefore need to pick one. We also have to define a sampler and an optimizer to compute and minimize the total energy of the system. Of course, each component has a lot of knobs that can be tweaked and that can greatly affect the result of the calculation.&lt;/p&gt;
&lt;p&gt;from torch import optim
from qmctorch.scf import Molecule
from qmctorch.wavefunction import SlaterJastrow,
from qmctorch.solver import Solver
from qmctorch.sampler import Metropolis&lt;/p&gt;
&lt;h1 id=&quot;create-a-h2-molecule&quot;&gt;create a H2 molecule&lt;/h1&gt;
&lt;p&gt;mol = Molecule(atom=‘H 0 0 -0.69; H 0 0 0.69’)&lt;/p&gt;
&lt;h1 id=&quot;create-the-wave-function-object&quot;&gt;create the wave function object&lt;/h1&gt;
&lt;p&gt;wf = SlaterJastrow(mol, cuda=True)&lt;/p&gt;
&lt;h1 id=&quot;create-a-sampler&quot;&gt;create a sampler&lt;/h1&gt;
&lt;p&gt;sampler = Metropolis(nwalkers=1000, nstep=2000,
step_size=0.2, nelec=wf.nelec,
cuda=True)&lt;/p&gt;
&lt;h1 id=&quot;create-an-optimizer&quot;&gt;create an optimizer&lt;/h1&gt;
&lt;p&gt;opt = optim.Adam(wf.parameters(), lr=1E-3)&lt;/p&gt;
&lt;h1 id=&quot;create-a-solver-and-optimize-the-wave-function&quot;&gt;create a solver and optimize the wave function&lt;/h1&gt;
&lt;p&gt;solver = Solver(wf=wf, sampler=sampler, optimizer=opt)
solver.run(250)We can then ask QMCTorch to optimize the wave function of a molecule or even to optimize its geometry. The illustration below shows the result of such a geometry optimization for a water molecule. Starting from a non-ideal atomic arrangement, where the oxygen and the two hydrogens are aligned, the optimization process quickly brings the atoms in a more favorable conformation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;660&quot; height=&quot;736&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-6746e7cc.DjPEOi5U_2aa3C6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What now?&lt;/h2&gt;
&lt;p&gt;Many research groups have also developed their own solutions, like &lt;a href=&quot;https://arxiv.org/pdf/1909.02487.pdf&quot;&gt;FermiNet &lt;/a&gt;or &lt;a href=&quot;https://arxiv.org/abs/1909.08423&quot;&gt;PauliNet &lt;/a&gt;and many others, to use machine learning techniques to accelerate and improve QMC calculations. Their approaches often use more convoluted functional forms than the ones used in QMCTorch. This allows for greater flexibility in the wave function and therefore more accurate results that have the potential to expand our chemical intuition.&lt;/p&gt;
&lt;p&gt;One could, of course, argue that the energy change during a QMC optimization is so small that it does not justify the large amount of computing resources thrown at it. But if you want your red pixel to be red and not reddish/brown this is the level of accuracy needed!&lt;/p&gt;</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Machine learning techniques are impacting all areas of science, and molecular simulations are not spared. This blog post shows how to make use of the tools and techniques developed for machine learning to facilitate high-accuracy electronic structure calculations.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-17dd1dc0.j4LJOKz3_Z24ylJU.webp&quot; srcset=&quot;&quot;&gt;
Quantum chemistry, the application of quantum mechanics to the study of molecular systems, is a powerful approach to design better materials, more efficient catalysts, and even better drugs. If you are reading this text on a fancy 4K &lt;a href=&quot;https://en.wikipedia.org/wiki/OLED&quot;&gt;OLED&lt;/a&gt; screen, chances are that quantum chemistry was used to fine-tune the light emission properties of the molecules that are shooting photons at you.&lt;/p&gt;
&lt;p&gt;Quantum chemistry is, however, not a single technique, but the aggregation of many approaches that have been developed over many decades by many people. Some methods are computationally inexpensive and usually not so accurate, while others require important computational resources but can reach a higher degree of accuracy.&lt;/p&gt;
&lt;p&gt;Quantum Monte Carlo (QMC) simulations are particularly interesting as they can reach a high degree of accuracy and can also be efficiently parallelized on very large computational resources. Many software packages, like &lt;a href=&quot;https://github.com/filippi-claudia/champ&quot;&gt;CHAMP &lt;/a&gt;or &lt;a href=&quot;https://github.com/TREX-CoE/qmcchem2&quot;&gt;QMC=CHEM&lt;/a&gt;, provide solutions to perform QMC simulations and have been used in countless scientific publications.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;300&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-d0f2af93.VGSxax-R_Z20BpCy.webp&quot; srcset=&quot;&quot;&gt;
Illustration of the QMC approach. We first define a wave function containing tunable parameters. We sample the associated density and compute the system’s energy and its gradient w.r.t. the tunable parameters. We then update the value of the parameters and start again until we find the minimum value of the total energyTo understand how QMC works, let’s consider a small molecule of, let’s say, benzene. To keep things simple we are going to assume that all the electrons of the molecule are located around its center following a Gaussian distribution of variable width. To compute the energy of the molecule, we first sample this distribution to obtain representative configurations of the electronic positions. This can be done via a variety of techniques, for example, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm&quot;&gt;Metropolis-Hastings&lt;/a&gt; algorithm. Computing the energy of the electrons in these configurations and taking averaging them can finally be used to approximate the total energy of the molecule.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Variational_method_(quantum_mechanics)&quot;&gt;cornerstone of quantum chemistry&lt;/a&gt; tells us that the most accurate description of the molecule is obtained for the lowest value of its total energy. In our simple example, we can tweak the width of the Gaussian distribution until we find the minimal value of the total energy. If you now think, &lt;em&gt;hey that almost looks like a machine learning problem&lt;/em&gt;, you’re not completely wrong. All we need is to encode the wave function in some sort of neural network.&lt;/p&gt;
&lt;h2 id=&quot;lets-start-with-a-toy-problem&quot;&gt;Let’s start with a toy problem&lt;/h2&gt;
&lt;p&gt;Let’s first look at a toy problem that you may have encountered in your undergraduate studies: a single particle in a one-dimensional potential. We pick here the Morse potential as it is simple enough yet non-trivial.&lt;/p&gt;
&lt;p&gt;We choose here to use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Radial_basis_function_network&quot;&gt;radial basis function (RBF) neural network&lt;/a&gt; to encode the wave function of this one-dimensional potential. In our RBF network, the input node encodes the position of the particle and each hidden node computes the value of a particular Gaussian function at this location. These values are then summed up on the output node to yield the value of the wave function at the particle’s location. This architecture therefore expresses the wave function of our particle as a sum of Gaussian functions, which is sufficient for this particular problem.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-c2c21611.O8Y3_5tb_8m2AB.webp&quot; srcset=&quot;&quot;&gt;
Schrodinet in action. The solver optimizes the positions, widths, and heights of all the Gaussian functions composing the RBF network to minimize the energy of the system.&lt;/p&gt;
&lt;h2 id=&quot;qmctorch-for-molecules&quot;&gt;QMCTorch for molecules&lt;/h2&gt;
&lt;p&gt;While replacing first-year university students with simple neural networks is appealing, it would be even better to apply the same machinery to more complex cases, for example, molecules. Unfortunately, the wave functions of molecular systems are much more complex than the one of a single particle trapped in a one-dimensional potential. All the electrons of the molecule interact with each other and also with the atomic nuclei and everything becomes very complicated very quickly. Fortunately, many scientists have given us a good understanding of the ingredients that should make up the wave functions of these systems.&lt;/p&gt;
&lt;p&gt;Armed with this vast amount of knowledge, and a little bit of tenacity, we have developed &lt;a href=&quot;https://github.com/NLESC-JCER/QMCTOrch&quot;&gt;&lt;strong&gt;QMCTorch&lt;/strong&gt;&lt;/a&gt;** **a Python package that allows to run QMC simulations of molecular systems using neural network wave functions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;392&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-5f17922c.BW2PfwlE_Z3DJiy.webp&quot; srcset=&quot;&quot;&gt;
Representation of the neural network that encodes the wave function in QMCTorch. Starting from the atomic and electronic coordinates, different layers progressively compute the value of the wave function.Neural networks in QMCTorch take the positions of the electrons and atoms as inputs and compute the value of the wave function as an output. In between the input and output layers, many layers compute the different ingredients involved in the definition of the molecular wave function. These layers have parameters that can be specified by the user or extracted from external chemistry codes such as &lt;a href=&quot;https://pyscf.org/&quot;&gt;pyscf&lt;/a&gt; or &lt;a href=&quot;https://www.scm.com/product/adf/&quot;&gt;ADF&lt;/a&gt;. These parameters can be further optimized to lead to an even more accurate wave function.&lt;/p&gt;
&lt;p&gt;As the name indicates, QMCTorch is based on the popular deep learning framework &lt;a href=&quot;https://pytorch.org/&quot;&gt;PyTorch &lt;/a&gt;and leverages automatic differentiation to compute various derivatives needed in the optimization process. The use of automatic differentiation allows users to easily explore new flavors of the wave function without having to analytically compute all its derivatives. QMCTorch can also make use of multiple GPUs to accelerate the simulations thanks to the native capabilities of PyTorch and the distributed deep learning library &lt;a href=&quot;https://horovod.ai/&quot;&gt;Horovd&lt;/a&gt;. For more information on QMCTorch, go see the &lt;a href=&quot;https://qmctorch.readthedocs.io/en/latest/&quot;&gt;code documentation&lt;/a&gt; or the &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.05472&quot;&gt;paper&lt;/a&gt; in the Journal of Open Source Software.&lt;/p&gt;
&lt;p&gt;To use the code we first need to define a molecule through its atomic positions. QMCTorch allows for a few different flavors of wave functions to be used and we therefore need to pick one. We also have to define a sampler and an optimizer to compute and minimize the total energy of the system. Of course, each component has a lot of knobs that can be tweaked and that can greatly affect the result of the calculation.&lt;/p&gt;
&lt;p&gt;from torch import optim
from qmctorch.scf import Molecule
from qmctorch.wavefunction import SlaterJastrow,
from qmctorch.solver import Solver
from qmctorch.sampler import Metropolis&lt;/p&gt;
&lt;h1 id=&quot;create-a-h2-molecule&quot;&gt;create a H2 molecule&lt;/h1&gt;
&lt;p&gt;mol = Molecule(atom=‘H 0 0 -0.69; H 0 0 0.69’)&lt;/p&gt;
&lt;h1 id=&quot;create-the-wave-function-object&quot;&gt;create the wave function object&lt;/h1&gt;
&lt;p&gt;wf = SlaterJastrow(mol, cuda=True)&lt;/p&gt;
&lt;h1 id=&quot;create-a-sampler&quot;&gt;create a sampler&lt;/h1&gt;
&lt;p&gt;sampler = Metropolis(nwalkers=1000, nstep=2000,
step_size=0.2, nelec=wf.nelec,
cuda=True)&lt;/p&gt;
&lt;h1 id=&quot;create-an-optimizer&quot;&gt;create an optimizer&lt;/h1&gt;
&lt;p&gt;opt = optim.Adam(wf.parameters(), lr=1E-3)&lt;/p&gt;
&lt;h1 id=&quot;create-a-solver-and-optimize-the-wave-function&quot;&gt;create a solver and optimize the wave function&lt;/h1&gt;
&lt;p&gt;solver = Solver(wf=wf, sampler=sampler, optimizer=opt)
solver.run(250)We can then ask QMCTorch to optimize the wave function of a molecule or even to optimize its geometry. The illustration below shows the result of such a geometry optimization for a water molecule. Starting from a non-ideal atomic arrangement, where the oxygen and the two hydrogens are aligned, the optimization process quickly brings the atoms in a more favorable conformation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning Machinery for Quantum Chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;660&quot; height=&quot;736&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-6746e7cc.DjPEOi5U_2aa3C6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What now?&lt;/h2&gt;
&lt;p&gt;Many research groups have also developed their own solutions, like &lt;a href=&quot;https://arxiv.org/pdf/1909.02487.pdf&quot;&gt;FermiNet &lt;/a&gt;or &lt;a href=&quot;https://arxiv.org/abs/1909.08423&quot;&gt;PauliNet &lt;/a&gt;and many others, to use machine learning techniques to accelerate and improve QMC calculations. Their approaches often use more convoluted functional forms than the ones used in QMCTorch. This allows for greater flexibility in the wave function and therefore more accurate results that have the potential to expand our chemical intuition.&lt;/p&gt;
&lt;p&gt;One could, of course, argue that the energy change during a QMC optimization is so small that it does not justify the large amount of computing resources thrown at it. But if you want your red pixel to be red and not reddish/brown this is the level of accuracy needed!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/machine-learning-machinery-for-quantum-c-d0f2af93.VGSxax-R.png" medium="image"/><author>Nicolas Renaud</author></item><item><title>Navigating research software policies: Insights from the Dutch research community</title><link>https://blog.esciencecenter.nl/posts/2023-11-28---navigating-research-software-policies-insights-from-the-dutc</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-28---navigating-research-software-policies-insights-from-the-dutc</guid><description>&lt;h1 id=&quot;navigating-research-software-policies-insights-from-the-dutch-research-community&quot;&gt;&lt;strong&gt;Navigating research software policies: Insights from the Dutch research community&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Imagine you’re a researcher who developed a brilliant piece of software that may be useful to many. Maybe it’s a single script that cleans data in a specific format. Or perhaps it’s a larger piece of research infrastructure, that could be a crucial part of the workflow for nearly all researchers in your discipline. You may be wondering how to make your software available in a way that safeguards your, your institute’s, the users’ and science’s interests. What if the rules around doing this would all be thoroughly outlined to you by your institute?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Navigating research software policies: Insights from the Dutch research community&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/navigating-research-software-policies-in-ea981e66.xiUpiGH6_2udFCa.webp&quot; srcset=&quot;&quot;&gt;
Just as there are many decisions to make about how to license software, there are many decisions to be made when drafting an institutional software policy. All possible decision paths can seem overwhelming, which is why &lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;PRO4RS&lt;/a&gt; is helping policy makers and researchers with this task. Photo by &lt;a href=&quot;https://unsplash.com/@distinctmind?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Distinct Mind&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;The eScience Center, NWO, TU Delft and the VU organized an event on 3 October 2023 where we discussed with representatives from more than 20 Dutch knowledge organizations (research institutes, research infrastructure providers, research funding organizations, universities, UMCs and universities of applied sciences) how to develop and implement institutional research software policies, and what the challenges may be in embarking on such a project.&lt;/p&gt;
&lt;h3 id=&quot;why-institutional-software-policies&quot;&gt;Why Institutional Software Policies?&lt;/h3&gt;
&lt;p&gt;To provide valuable context, &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; director &lt;a href=&quot;https://www.epcc.ed.ac.uk/about-us/our-team/prof-neil-chue-hong&quot;&gt;professor Neil Chue Hong&lt;/a&gt; laid out why research software policies are important. He started his presentation by explaining that institutional policy generally serves as a crucial element in effecting cultural change. Policies provide various purposes, such as encouraging good practices, ensuring legal compliance, maintaining ethical norms, reducing institutional risk, improving operational efficiency, and promoting and enhancing a mission.&lt;/p&gt;
&lt;p&gt;The cultural change research software policies specifically encourage are open research and open science practices. They typically focus on promoting reuse of research software through recommendations about licenses and research output management plans (data or software management plans). On an individual level, these policies should encourage authors and developers to cite software and make their software citable. On an institutional level, research software policies are used to mitigate institutional risk in areas such as cybersecurity, procurement, asset management, research ethics, and integrity.&lt;/p&gt;
&lt;p&gt;Research software policies are important for good practices in research software management and open science. Despite this, many organizations do not yet have an institutional research software policy. During our event, those interested in setting up or further developing their own policies answered questions about the situation at their institutes via Mentimeter. From the answers to those questions, it became clear that most of the Dutch institutes that were represented (77%) do not have a policy on research software (yet). However, about half of those institutes are currently (planning on) developing one.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Navigating research software policies: Insights from the Dutch research community&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/navigating-research-software-policies-in-9a3d4359.BPnRmbVf_sF4JU.webp&quot; srcset=&quot;&quot;&gt;
Participants during the 3 October 2023 event discussed what should be included in their institutional research software policy, and how to practically go about developing this policy.&lt;/p&gt;
&lt;h3 id=&quot;drafting-and-implementing-research-software-policies&quot;&gt;Drafting and Implementing Research Software Policies&lt;/h3&gt;
&lt;p&gt;Drafting research software policies poses several challenges. First, &lt;a href=&quot;https://doi.org/10.5281/zenodo.5504016&quot;&gt;defining research software can be difficult&lt;/a&gt;, as the same piece of software may be categorized as research software or not depending on its &lt;a href=&quot;https://blog.esciencecenter.nl/defining-the-roles-of-research-software-21535a43f23&quot;&gt;role&lt;/a&gt;, or the context where it is produced and used. Second, &lt;a href=&quot;https://blog.esciencecenter.nl/defining-the-roles-of-research-software-21535a43f23&quot;&gt;the complexity and maturity of research software vary&lt;/a&gt;, ranging from &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4940273&quot;&gt;analysis code to prototype tools to mature research software infrastructure&lt;/a&gt;. Institutions need to account for all these levels of complexity in their policies without being overly prescriptive or incomplete for different cases. Third, multiple stakeholders, including senior management, IT services, libraries, enterprise and innovation offices, and open science/open source policy offices, need to be involved in creating research software policies. The challenge lies in avoiding a situation where “if everyone is responsible, no one is”. Fourth, research software policies are interconnected with other university policies and processes. Integrating a new policy with existing policies can raise new questions and challenges.&lt;/p&gt;
&lt;p&gt;The challenges pointed out by Neil Chue Hong and the audience were reflected in &lt;a href=&quot;https://www.universiteitleiden.nl/medewerkers/jacko-koster#tab-1&quot;&gt;Jacko Koster&lt;/a&gt;’s talk. Jacko provided a snapshot of Leiden University’s work in progress in developing such a policy. The variety of parties involved, as well as the many aspects of research software, make for a complicated process that involves discussing with many stakeholders at all levels of the university. &lt;a href=&quot;https://www.tudelft.nl/library/research-data-management/r/support/data-stewardship/contact/paula-martinez-lavanchy&quot;&gt;Paula Martinez Lavanchy&lt;/a&gt; from TU Delft discussed her university’s success story. In 2021, she led the drafting and implementation of &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4629661&quot;&gt;TU Delft’s research software policy&lt;/a&gt; together with a group of TU Delft’s employees. She started by putting together a working group that encompassed relevant stakeholders from all areas: researchers, librarians, data stewards, valorisation center employees, legal services and the ICT department. The inclusion of many different parties and integration of all their perspectives was crucial to her success.&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4629661)Click&quot;&gt;https://zenodo.org/doi/10.5281/zenodo.4629661)Click&lt;/a&gt; the image to read TU Delft’s research software policyTU Delft’s experience provides valuable insights into what can make institutional research software policies effective. For example, TU Delft has made sure that the implementation and software workflow described by the policy is solidly integrated into training for staff. This approach fits well with findings by the PASTEUR40A project, which investigated success factors in implementing policies at universities. In their project, they investigated Open Access policies at 120 different universities. Drawing from these experiences with implementing Open Access policies, they wrote &lt;a href=&quot;https://doi.org/10.5281/zenodo.35635&quot;&gt;a paper&lt;/a&gt; that concluded that effective policies should be minimally burdensome, mandatory, linked to evaluation and incentives, and applied at the optimal time in the lifecycle. Additionally, they must align with funders’ policies for university staff to adhere to them.&lt;/p&gt;
&lt;p&gt;The challenge of drafting and implementing research software policies for individuals at knowledge institutions has inspired the formation of the recently approved RDA working group PRO4RS, a joint initiative by ReSA and the RDA, with support of the RDA Tiger project. For those wondering how to go about drafting an institutional research software policy, this group is working on an overview of existing policies. Next steps will include putting together resources on how to achieve policy change at an institute, and to develop a common framework for research software policy, specifically. You can &lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;join this group&lt;/a&gt; to receive updates and information about the group’s work, as well as sessions during the RDA plenary (two times per year). A summary of the working group’s most recent (autumn 2023) RDA plenary session is available &lt;a href=&quot;https://www.rd-alliance.org/group/rda-resa-policies-research-organisations-research-software-pro4rs/post/summary-rda-plenary-21&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The participants at our event brainstormed about what should be part of their research software policies. They agreed that at a minimum, a definition of research software should be included in the policy. Most participants agreed that it should include rules about licensing and sharing software, too. An interesting point of discussion was the question whether guidelines on good practices in software development should be part of a research software policy, and where to draw the line regarding this. For example, some participants agreed that pointers on research software quality and a commitment to training researchers on good practices should be part of a research software policy, while others did not.&lt;/p&gt;
&lt;h3 id=&quot;next-steps&quot;&gt;Next steps**&lt;/h3&gt;
&lt;p&gt;We invite anyone interested in staying up to date about institutional research software policies to **attend &lt;strong&gt;&lt;a href=&quot;https://www.eventbrite.com/e/institutional-research-software-policies-tickets-765126843987?aff=oddtdtcreator&quot;&gt;&lt;strong&gt;our webinar&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt; on 16 January 2024 to continue the conversation about institutional research software policies in the Netherlands. **During this webinar, we plan to include an update from the PRO4RS RDA working group and reiterate the most important points from our workshop on 3 October to those who missed it. Sign up &lt;a href=&quot;https://www.eventbrite.com/e/institutional-research-software-policies-tickets-765126843987?aff=oddtdtcreator&quot;&gt;here&lt;/a&gt; to join the webinar.&lt;/p&gt;
&lt;p&gt;If you are interested in developing institutional research software policies, you can** subscribe to updates from the PRO4RS RDA working group **&lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, on 23 April 2024, the eScience Center is jointly organising &lt;a href=&quot;https://www.eventbrite.com/e/national-research-software-day-tickets-761242004327?aff=oddtdtcreator&quot;&gt;&lt;strong&gt;National Research Software Day&lt;/strong&gt;&lt;/a&gt;, where policy makers, research supporters and community leaders will come together to discuss all things research software. You can find out more and sign up for this day here.&lt;/p&gt;
&lt;p&gt;Written by Lieke de Boer. Thanks to Carlos Martinez-Ortiz, Maaike de Jong, Maria Cruz and Meron Vermaas for comments.*&lt;/p&gt;</description><pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;navigating-research-software-policies-insights-from-the-dutch-research-community&quot;&gt;&lt;strong&gt;Navigating research software policies: Insights from the Dutch research community&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Imagine you’re a researcher who developed a brilliant piece of software that may be useful to many. Maybe it’s a single script that cleans data in a specific format. Or perhaps it’s a larger piece of research infrastructure, that could be a crucial part of the workflow for nearly all researchers in your discipline. You may be wondering how to make your software available in a way that safeguards your, your institute’s, the users’ and science’s interests. What if the rules around doing this would all be thoroughly outlined to you by your institute?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Navigating research software policies: Insights from the Dutch research community&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/navigating-research-software-policies-in-ea981e66.xiUpiGH6_2udFCa.webp&quot; srcset=&quot;&quot;&gt;
Just as there are many decisions to make about how to license software, there are many decisions to be made when drafting an institutional software policy. All possible decision paths can seem overwhelming, which is why &lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;PRO4RS&lt;/a&gt; is helping policy makers and researchers with this task. Photo by &lt;a href=&quot;https://unsplash.com/@distinctmind?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Distinct Mind&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;The eScience Center, NWO, TU Delft and the VU organized an event on 3 October 2023 where we discussed with representatives from more than 20 Dutch knowledge organizations (research institutes, research infrastructure providers, research funding organizations, universities, UMCs and universities of applied sciences) how to develop and implement institutional research software policies, and what the challenges may be in embarking on such a project.&lt;/p&gt;
&lt;h3 id=&quot;why-institutional-software-policies&quot;&gt;Why Institutional Software Policies?&lt;/h3&gt;
&lt;p&gt;To provide valuable context, &lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute&lt;/a&gt; director &lt;a href=&quot;https://www.epcc.ed.ac.uk/about-us/our-team/prof-neil-chue-hong&quot;&gt;professor Neil Chue Hong&lt;/a&gt; laid out why research software policies are important. He started his presentation by explaining that institutional policy generally serves as a crucial element in effecting cultural change. Policies provide various purposes, such as encouraging good practices, ensuring legal compliance, maintaining ethical norms, reducing institutional risk, improving operational efficiency, and promoting and enhancing a mission.&lt;/p&gt;
&lt;p&gt;The cultural change research software policies specifically encourage are open research and open science practices. They typically focus on promoting reuse of research software through recommendations about licenses and research output management plans (data or software management plans). On an individual level, these policies should encourage authors and developers to cite software and make their software citable. On an institutional level, research software policies are used to mitigate institutional risk in areas such as cybersecurity, procurement, asset management, research ethics, and integrity.&lt;/p&gt;
&lt;p&gt;Research software policies are important for good practices in research software management and open science. Despite this, many organizations do not yet have an institutional research software policy. During our event, those interested in setting up or further developing their own policies answered questions about the situation at their institutes via Mentimeter. From the answers to those questions, it became clear that most of the Dutch institutes that were represented (77%) do not have a policy on research software (yet). However, about half of those institutes are currently (planning on) developing one.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Navigating research software policies: Insights from the Dutch research community&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/navigating-research-software-policies-in-9a3d4359.BPnRmbVf_sF4JU.webp&quot; srcset=&quot;&quot;&gt;
Participants during the 3 October 2023 event discussed what should be included in their institutional research software policy, and how to practically go about developing this policy.&lt;/p&gt;
&lt;h3 id=&quot;drafting-and-implementing-research-software-policies&quot;&gt;Drafting and Implementing Research Software Policies&lt;/h3&gt;
&lt;p&gt;Drafting research software policies poses several challenges. First, &lt;a href=&quot;https://doi.org/10.5281/zenodo.5504016&quot;&gt;defining research software can be difficult&lt;/a&gt;, as the same piece of software may be categorized as research software or not depending on its &lt;a href=&quot;https://blog.esciencecenter.nl/defining-the-roles-of-research-software-21535a43f23&quot;&gt;role&lt;/a&gt;, or the context where it is produced and used. Second, &lt;a href=&quot;https://blog.esciencecenter.nl/defining-the-roles-of-research-software-21535a43f23&quot;&gt;the complexity and maturity of research software vary&lt;/a&gt;, ranging from &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4940273&quot;&gt;analysis code to prototype tools to mature research software infrastructure&lt;/a&gt;. Institutions need to account for all these levels of complexity in their policies without being overly prescriptive or incomplete for different cases. Third, multiple stakeholders, including senior management, IT services, libraries, enterprise and innovation offices, and open science/open source policy offices, need to be involved in creating research software policies. The challenge lies in avoiding a situation where “if everyone is responsible, no one is”. Fourth, research software policies are interconnected with other university policies and processes. Integrating a new policy with existing policies can raise new questions and challenges.&lt;/p&gt;
&lt;p&gt;The challenges pointed out by Neil Chue Hong and the audience were reflected in &lt;a href=&quot;https://www.universiteitleiden.nl/medewerkers/jacko-koster#tab-1&quot;&gt;Jacko Koster&lt;/a&gt;’s talk. Jacko provided a snapshot of Leiden University’s work in progress in developing such a policy. The variety of parties involved, as well as the many aspects of research software, make for a complicated process that involves discussing with many stakeholders at all levels of the university. &lt;a href=&quot;https://www.tudelft.nl/library/research-data-management/r/support/data-stewardship/contact/paula-martinez-lavanchy&quot;&gt;Paula Martinez Lavanchy&lt;/a&gt; from TU Delft discussed her university’s success story. In 2021, she led the drafting and implementation of &lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4629661&quot;&gt;TU Delft’s research software policy&lt;/a&gt; together with a group of TU Delft’s employees. She started by putting together a working group that encompassed relevant stakeholders from all areas: researchers, librarians, data stewards, valorisation center employees, legal services and the ICT department. The inclusion of many different parties and integration of all their perspectives was crucial to her success.&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://zenodo.org/doi/10.5281/zenodo.4629661)Click&quot;&gt;https://zenodo.org/doi/10.5281/zenodo.4629661)Click&lt;/a&gt; the image to read TU Delft’s research software policyTU Delft’s experience provides valuable insights into what can make institutional research software policies effective. For example, TU Delft has made sure that the implementation and software workflow described by the policy is solidly integrated into training for staff. This approach fits well with findings by the PASTEUR40A project, which investigated success factors in implementing policies at universities. In their project, they investigated Open Access policies at 120 different universities. Drawing from these experiences with implementing Open Access policies, they wrote &lt;a href=&quot;https://doi.org/10.5281/zenodo.35635&quot;&gt;a paper&lt;/a&gt; that concluded that effective policies should be minimally burdensome, mandatory, linked to evaluation and incentives, and applied at the optimal time in the lifecycle. Additionally, they must align with funders’ policies for university staff to adhere to them.&lt;/p&gt;
&lt;p&gt;The challenge of drafting and implementing research software policies for individuals at knowledge institutions has inspired the formation of the recently approved RDA working group PRO4RS, a joint initiative by ReSA and the RDA, with support of the RDA Tiger project. For those wondering how to go about drafting an institutional research software policy, this group is working on an overview of existing policies. Next steps will include putting together resources on how to achieve policy change at an institute, and to develop a common framework for research software policy, specifically. You can &lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;join this group&lt;/a&gt; to receive updates and information about the group’s work, as well as sessions during the RDA plenary (two times per year). A summary of the working group’s most recent (autumn 2023) RDA plenary session is available &lt;a href=&quot;https://www.rd-alliance.org/group/rda-resa-policies-research-organisations-research-software-pro4rs/post/summary-rda-plenary-21&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The participants at our event brainstormed about what should be part of their research software policies. They agreed that at a minimum, a definition of research software should be included in the policy. Most participants agreed that it should include rules about licensing and sharing software, too. An interesting point of discussion was the question whether guidelines on good practices in software development should be part of a research software policy, and where to draw the line regarding this. For example, some participants agreed that pointers on research software quality and a commitment to training researchers on good practices should be part of a research software policy, while others did not.&lt;/p&gt;
&lt;h3 id=&quot;next-steps&quot;&gt;Next steps**&lt;/h3&gt;
&lt;p&gt;We invite anyone interested in staying up to date about institutional research software policies to **attend &lt;strong&gt;&lt;a href=&quot;https://www.eventbrite.com/e/institutional-research-software-policies-tickets-765126843987?aff=oddtdtcreator&quot;&gt;&lt;strong&gt;our webinar&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt; on 16 January 2024 to continue the conversation about institutional research software policies in the Netherlands. **During this webinar, we plan to include an update from the PRO4RS RDA working group and reiterate the most important points from our workshop on 3 October to those who missed it. Sign up &lt;a href=&quot;https://www.eventbrite.com/e/institutional-research-software-policies-tickets-765126843987?aff=oddtdtcreator&quot;&gt;here&lt;/a&gt; to join the webinar.&lt;/p&gt;
&lt;p&gt;If you are interested in developing institutional research software policies, you can** subscribe to updates from the PRO4RS RDA working group **&lt;a href=&quot;https://www.rd-alliance.org/groups/rda-resa-policies-research-organisations-research-software-pro4rs&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, on 23 April 2024, the eScience Center is jointly organising &lt;a href=&quot;https://www.eventbrite.com/e/national-research-software-day-tickets-761242004327?aff=oddtdtcreator&quot;&gt;&lt;strong&gt;National Research Software Day&lt;/strong&gt;&lt;/a&gt;, where policy makers, research supporters and community leaders will come together to discuss all things research software. You can find out more and sign up for this day here.&lt;/p&gt;
&lt;p&gt;Written by Lieke de Boer. Thanks to Carlos Martinez-Ortiz, Maaike de Jong, Maria Cruz and Meron Vermaas for comments.*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/navigating-research-software-policies-in-ea981e66.xiUpiGH6.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Cracking the (moisture) tracking code</title><link>https://blog.esciencecenter.nl/posts/2023-11-21---cracking-the-moisture-tracking-code</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-21---cracking-the-moisture-tracking-code</guid><description>&lt;h2 id=&quot;an-exclusive-interview-with-our-project-partners&quot;&gt;An exclusive interview with our project partners&lt;/h2&gt;
&lt;p&gt;This post is part of a series on our 2021 Small Scale Initiative Call in Software Performance Optimization. This week’s highlight: “&lt;a href=&quot;https://research-software-directory.org/projects/optimizing-tracking-of-moisture-in-the-atmosphere&quot;&gt;Optimizing tracking of moisture in the atmosphere&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;What is moisture tracking? Can Python deliver optimal performance? What’s it like to have others modify your code? How can a team avoid alienation in coding? Will the output of this project be part of CMIP? Find out in this exclusive interview with project team members &lt;a href=&quot;https://www.linkedin.com/in/imme-benedict-abab09b8&quot;&gt;Imme Benedict&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/ruud-van-der-ent-79142b11&quot;&gt;Ruud van der Ent&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/chris-weijenborg-17ab1431/&quot;&gt;Chris Weijenborg&lt;/a&gt;, and Peter Kalverla!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;560&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-e7c68a7c.D1PgIWpw_Z1fDxMi.webp&quot; srcset=&quot;&quot;&gt;
Project team. Imme and Ruud, Peter, Chris and Yang (top-to-bottom, left-to-right).&lt;/p&gt;
&lt;h3 id=&quot;chris-youre-an-expert-in-atmospheric-dynamics-can-you-explain-what-moisture-tracking-is-and-why-it-is-useful&quot;&gt;Chris, you’re an expert in atmospheric dynamics. Can you explain what moisture tracking is, and why it is useful?**&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Chris&lt;/em&gt;: The essential question you want to answer with moisture tracking is where moisture leading to precipitation in a certain area is coming from. This can be related to a particular event, think about for example the floods in West-Europe in 2021, but also related to the climatological precipitation. This is useful, since it gives us other insights then just looking at precipitation and or wind fields directly. For example, if the sea surface temperature is increasing in a warmer climate, does this lead to an increased climatological precipitation at another location? Or are the Floods in 2021 caused by increased sea surface temperatures in the Mediterranean Sea or the increased soil moisture over the continent? You might wonder now how all of this works: it’s complicated, but we have a nice animation to show the basics:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;169&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-8a91d349.CMAsRdvw_ZSbsc8.webp&quot; srcset=&quot;&quot;&gt;
Animation of a moisture-tracking experiment. The video first runs forward, then reversed. On the left, you see the total water content in the atmosphere, on the right only the part that contributed to the 2021 floods over the Eiffel and the Ardennes.&lt;/p&gt;
&lt;h3 id=&quot;imme-you-were-the-main-applicant-for-this-project-what-was-your-original-goal-with-the-proposal&quot;&gt;&lt;strong&gt;Imme, you were the main applicant for this project. What was your original goal with the proposal?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: I had been working in my PhD with the &lt;a href=&quot;https://research-software-directory.org/software/wam2layers&quot;&gt;WAM2layers model&lt;/a&gt; and also adapted parts of the code. When I got a position as lecturer and researcher, I was keen on continuing the work on moisture tracking, and one way was to work with MSc thesis projects. However, the tool became a bit outdated as it was written to use &lt;a href=&quot;https://climatedataguide.ucar.edu/climate-data/era-interim&quot;&gt;ERA-Interim dataset&lt;/a&gt; as input, while for most recent events only the newest dataset ERA5 was available, as the ERA-Interim dataset was phased out. Therefore,&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;I became hesitant to use moisture tracking in my own and students research, which I thought was a shame.&lt;/p&gt;
&lt;p&gt;Then I wrote this proposal to update and speed-up the code such that researchers new in the field (like students) could easily start to use it.&lt;/p&gt;
&lt;h3 id=&quot;ruud-as-the-original-developer-of-wam2layers-you-published-your-code-many-years-ago-what-were-your-expectations-back-then-and-how-do-you-look-back-on-that-today&quot;&gt;&lt;strong&gt;Ruud, as the original developer of WAM2layers you published your code many years ago. What were your expectations back then? And how do you look back on that today?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Initially I just wanted to archive the code, so other researchers would more easily be able to find it. I naively thought of the code as something quite static. Since then, demand for moisture tracking in various fields of application has increased enormously and so has the importance to develop and maintain the code. I hope that with the user community around WAM2layers we can keep the software up to date with the latest developments and relevant for several years to come.&lt;/p&gt;
&lt;h3 id=&quot;peter-you-have-a-background-in-meteorology--wageningen-university-what-was-it-like-to-go-back-to-your-roots-in-this-project&quot;&gt;&lt;strong&gt;Peter, you have a background in meteorology @ Wageningen University. What was it like to go back to your roots in this project?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: Indeed, this project was right up my alley. I benefited a lot from my meteorology background and I enjoyed delving into some of the equations I’d almost forgotten about. I also liked the collaboration in this project. It felt like a real team effort, where everyone brought their own unique expertise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I left Wageningen to join the eScience Center, I wanted to improve my own research software engineering skills so I could apply them to the benefit of academic research. I think that really worked out well with this project.&lt;/p&gt;
&lt;h3 id=&quot;now-that-were-past-the-introductions-lets-take-a-deeper-dive-into-the-project-you-mentioned-the-code-was-too-slow-to-work-with-high-resolution-data-like-era5-did-you-solve-this-problem-and-how&quot;&gt;&lt;strong&gt;Now that we’re past the introductions, let’s take a deeper dive into the project. You mentioned the code was too slow to work with high-resolution data like ERA5. Did you solve this problem, and how?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: Yes, we did. The easiest win was changing the code from Python2 to Python3, and then some relatively straightforward changes, for example better use of numpy’s broadcasting capabilities.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;47&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-c3bdc752.9PiMDSLZ_Z23B0zl.webp&quot; srcset=&quot;&quot;&gt;
Illustration of the time steps in the input data (above) and in the model time loop (below).&lt;/p&gt;
&lt;h3 id=&quot;wam2layers-was-originally-written-in-matlab-then-translated-to-python-wasnt-it-time-for-another-switch-especially-considering-pythons-reputation-regarding-performance&quot;&gt;WAM2layers was originally written in Matlab, then translated to Python. Wasn’t it time for another switch, especially considering Python’s reputation regarding performance?**&lt;/h3&gt;
&lt;p&gt;Peter*: We considered it. I’ve been experimenting a bit with Julia in the past and it seems like a suitable alternative. However, we wanted to make sure that the code was still understandable for scientists or students: even if they are not actively changing the code, it’s good if they can understand what’s going on. Python still is by far the most widely known language in the field.&lt;/p&gt;
&lt;p&gt;Moreover, Python is fast enough for now. For most operations we use highly optimized numpy functions. If we wanted to squeeze out even more we could still look into numba, for example. Having said that, some of the changes we made to the code structure &lt;em&gt;do&lt;/em&gt; actually make it easier to replace expensive operations with optimized code in another language, should we ever wish to do that.&lt;/p&gt;
&lt;h3 id=&quot;in-the-end-you-did-more-than-make-it-faster-can-you-elaborate-on-some-of-the-unexpected-changes&quot;&gt;&lt;strong&gt;In the end, you did more than make it faster. Can you elaborate on some of the unexpected changes?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: yes, one example is that we made it easier to (pip) install the model and use it from the command line.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;People can now get the software working in a matter of minutes. One does not need to be an expert anymore, which is a great development.&lt;/p&gt;
&lt;p&gt;However, when people do research with it, I still hope that they involve someone from the core development team as there might be some tricky devils in the details.&lt;/p&gt;
&lt;h3 id=&quot;in-retrospect-what-are-the-main-things-you-got-out-of-this-project&quot;&gt;&lt;strong&gt;In retrospect, what are the main things you got out of this project?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Personally, I really enjoyed two things: 1) working in a horizontal team, and 2) blocking time in my agenda to do some coding.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chris&lt;/em&gt;: I really enjoyed learning something new again, moreover in the meanwhile I also was ‘forced’ to learn version control with Git.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: Teamwork, and learning Git! But also the possibility to have students working with the tool again.&lt;/p&gt;
&lt;h3 id=&quot;can-you-elaborate-on-the-student-projects&quot;&gt;&lt;strong&gt;Can you elaborate on the student projects?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud &amp;#x26; Imme&lt;/em&gt;: Sure! Below are the results from 4 student projects: Wenyu looked at &lt;a href=&quot;http://resolver.tudelft.nl/uuid:28f594b4-b24f-4aec-b01c-662e777ca971&quot;&gt;monsoon moisture source&lt;/a&gt; for the Yangtze River Basin, Rens studied &lt;a href=&quot;http://resolver.tudelft.nl/uuid:4e8cfdc1-350f-403f-aa7e-e76b55f5a800&quot;&gt;trends in moisture sources&lt;/a&gt; related to rising lakes in Keny, Emma studied the &lt;a href=&quot;http://resolver.tudelft.nl/uuid:7185c2b7-8313-4dc9-8a10-f57a7cd5ca35&quot;&gt;drivers of rainfall variability&lt;/a&gt; in Surinam, and Vincent used WAM2layers to study the moisture sources over the Amazon region during August 2023 when a big field campaign took place to understand biosphere-atmosphere interactions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-384b7503.DDWvrbCd_Z5iS17.webp&quot; srcset=&quot;&quot;&gt;
WAM2layers output as produced and visualized in students’ projects. Shading illustrates the moisture sources for the each of the case studies.&lt;/p&gt;
&lt;h3 id=&quot;recently-a-follow-up-project-was-granted-so-this-story-will-continue&quot;&gt;&lt;strong&gt;Recently a follow-up project was granted. So this story will continue?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Absolutely, with the NWO Open Science project and our own time we want to make WAM2layers even more user-friendly, increase the number of features, applicability to climate models, and get a better grip on the uncertainties. To this end we will also engage with the wider moisture tracking community.&lt;/p&gt;
&lt;h3 id=&quot;will-cmip7-include-an-atmospheric-moisture-tracking-mip-in-the-future&quot;&gt;&lt;strong&gt;Will CMIP7 include an “Atmospheric moisture tracking-MIP” in the future?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: Ha, that would be amazing of course, but realistically I think there are still some steps in between before such a big goal can be achieved. We are currently initiating a moisture tracking intercomparison project, where multiple moisture tracking models will run the same case to address uncertainty of moisture sources between models. This project will be supported by a workshop at the Lorentz centre in Leiden in May 2024.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is part of a series on our 2021 Small Scale Initiative Call in Software Performance Optimization. See also our post on the project &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/minds-for-mobile-agents-speeding-up-social-distancing-simulations-62d3fb412ff6&quot;&gt;&lt;em&gt;Minds for Mobile Agents&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Tue, 21 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;an-exclusive-interview-with-our-project-partners&quot;&gt;An exclusive interview with our project partners&lt;/h2&gt;
&lt;p&gt;This post is part of a series on our 2021 Small Scale Initiative Call in Software Performance Optimization. This week’s highlight: “&lt;a href=&quot;https://research-software-directory.org/projects/optimizing-tracking-of-moisture-in-the-atmosphere&quot;&gt;Optimizing tracking of moisture in the atmosphere&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;What is moisture tracking? Can Python deliver optimal performance? What’s it like to have others modify your code? How can a team avoid alienation in coding? Will the output of this project be part of CMIP? Find out in this exclusive interview with project team members &lt;a href=&quot;https://www.linkedin.com/in/imme-benedict-abab09b8&quot;&gt;Imme Benedict&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/ruud-van-der-ent-79142b11&quot;&gt;Ruud van der Ent&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/chris-weijenborg-17ab1431/&quot;&gt;Chris Weijenborg&lt;/a&gt;, and Peter Kalverla!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;560&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-e7c68a7c.D1PgIWpw_Z1fDxMi.webp&quot; srcset=&quot;&quot;&gt;
Project team. Imme and Ruud, Peter, Chris and Yang (top-to-bottom, left-to-right).&lt;/p&gt;
&lt;h3 id=&quot;chris-youre-an-expert-in-atmospheric-dynamics-can-you-explain-what-moisture-tracking-is-and-why-it-is-useful&quot;&gt;Chris, you’re an expert in atmospheric dynamics. Can you explain what moisture tracking is, and why it is useful?**&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Chris&lt;/em&gt;: The essential question you want to answer with moisture tracking is where moisture leading to precipitation in a certain area is coming from. This can be related to a particular event, think about for example the floods in West-Europe in 2021, but also related to the climatological precipitation. This is useful, since it gives us other insights then just looking at precipitation and or wind fields directly. For example, if the sea surface temperature is increasing in a warmer climate, does this lead to an increased climatological precipitation at another location? Or are the Floods in 2021 caused by increased sea surface temperatures in the Mediterranean Sea or the increased soil moisture over the continent? You might wonder now how all of this works: it’s complicated, but we have a nice animation to show the basics:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;169&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-8a91d349.CMAsRdvw_ZSbsc8.webp&quot; srcset=&quot;&quot;&gt;
Animation of a moisture-tracking experiment. The video first runs forward, then reversed. On the left, you see the total water content in the atmosphere, on the right only the part that contributed to the 2021 floods over the Eiffel and the Ardennes.&lt;/p&gt;
&lt;h3 id=&quot;imme-you-were-the-main-applicant-for-this-project-what-was-your-original-goal-with-the-proposal&quot;&gt;&lt;strong&gt;Imme, you were the main applicant for this project. What was your original goal with the proposal?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: I had been working in my PhD with the &lt;a href=&quot;https://research-software-directory.org/software/wam2layers&quot;&gt;WAM2layers model&lt;/a&gt; and also adapted parts of the code. When I got a position as lecturer and researcher, I was keen on continuing the work on moisture tracking, and one way was to work with MSc thesis projects. However, the tool became a bit outdated as it was written to use &lt;a href=&quot;https://climatedataguide.ucar.edu/climate-data/era-interim&quot;&gt;ERA-Interim dataset&lt;/a&gt; as input, while for most recent events only the newest dataset ERA5 was available, as the ERA-Interim dataset was phased out. Therefore,&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;I became hesitant to use moisture tracking in my own and students research, which I thought was a shame.&lt;/p&gt;
&lt;p&gt;Then I wrote this proposal to update and speed-up the code such that researchers new in the field (like students) could easily start to use it.&lt;/p&gt;
&lt;h3 id=&quot;ruud-as-the-original-developer-of-wam2layers-you-published-your-code-many-years-ago-what-were-your-expectations-back-then-and-how-do-you-look-back-on-that-today&quot;&gt;&lt;strong&gt;Ruud, as the original developer of WAM2layers you published your code many years ago. What were your expectations back then? And how do you look back on that today?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Initially I just wanted to archive the code, so other researchers would more easily be able to find it. I naively thought of the code as something quite static. Since then, demand for moisture tracking in various fields of application has increased enormously and so has the importance to develop and maintain the code. I hope that with the user community around WAM2layers we can keep the software up to date with the latest developments and relevant for several years to come.&lt;/p&gt;
&lt;h3 id=&quot;peter-you-have-a-background-in-meteorology--wageningen-university-what-was-it-like-to-go-back-to-your-roots-in-this-project&quot;&gt;&lt;strong&gt;Peter, you have a background in meteorology @ Wageningen University. What was it like to go back to your roots in this project?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: Indeed, this project was right up my alley. I benefited a lot from my meteorology background and I enjoyed delving into some of the equations I’d almost forgotten about. I also liked the collaboration in this project. It felt like a real team effort, where everyone brought their own unique expertise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I left Wageningen to join the eScience Center, I wanted to improve my own research software engineering skills so I could apply them to the benefit of academic research. I think that really worked out well with this project.&lt;/p&gt;
&lt;h3 id=&quot;now-that-were-past-the-introductions-lets-take-a-deeper-dive-into-the-project-you-mentioned-the-code-was-too-slow-to-work-with-high-resolution-data-like-era5-did-you-solve-this-problem-and-how&quot;&gt;&lt;strong&gt;Now that we’re past the introductions, let’s take a deeper dive into the project. You mentioned the code was too slow to work with high-resolution data like ERA5. Did you solve this problem, and how?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: Yes, we did. The easiest win was changing the code from Python2 to Python3, and then some relatively straightforward changes, for example better use of numpy’s broadcasting capabilities.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;47&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-c3bdc752.9PiMDSLZ_Z23B0zl.webp&quot; srcset=&quot;&quot;&gt;
Illustration of the time steps in the input data (above) and in the model time loop (below).&lt;/p&gt;
&lt;h3 id=&quot;wam2layers-was-originally-written-in-matlab-then-translated-to-python-wasnt-it-time-for-another-switch-especially-considering-pythons-reputation-regarding-performance&quot;&gt;WAM2layers was originally written in Matlab, then translated to Python. Wasn’t it time for another switch, especially considering Python’s reputation regarding performance?**&lt;/h3&gt;
&lt;p&gt;Peter*: We considered it. I’ve been experimenting a bit with Julia in the past and it seems like a suitable alternative. However, we wanted to make sure that the code was still understandable for scientists or students: even if they are not actively changing the code, it’s good if they can understand what’s going on. Python still is by far the most widely known language in the field.&lt;/p&gt;
&lt;p&gt;Moreover, Python is fast enough for now. For most operations we use highly optimized numpy functions. If we wanted to squeeze out even more we could still look into numba, for example. Having said that, some of the changes we made to the code structure &lt;em&gt;do&lt;/em&gt; actually make it easier to replace expensive operations with optimized code in another language, should we ever wish to do that.&lt;/p&gt;
&lt;h3 id=&quot;in-the-end-you-did-more-than-make-it-faster-can-you-elaborate-on-some-of-the-unexpected-changes&quot;&gt;&lt;strong&gt;In the end, you did more than make it faster. Can you elaborate on some of the unexpected changes?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Peter&lt;/em&gt;: yes, one example is that we made it easier to (pip) install the model and use it from the command line.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;People can now get the software working in a matter of minutes. One does not need to be an expert anymore, which is a great development.&lt;/p&gt;
&lt;p&gt;However, when people do research with it, I still hope that they involve someone from the core development team as there might be some tricky devils in the details.&lt;/p&gt;
&lt;h3 id=&quot;in-retrospect-what-are-the-main-things-you-got-out-of-this-project&quot;&gt;&lt;strong&gt;In retrospect, what are the main things you got out of this project?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Personally, I really enjoyed two things: 1) working in a horizontal team, and 2) blocking time in my agenda to do some coding.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chris&lt;/em&gt;: I really enjoyed learning something new again, moreover in the meanwhile I also was ‘forced’ to learn version control with Git.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: Teamwork, and learning Git! But also the possibility to have students working with the tool again.&lt;/p&gt;
&lt;h3 id=&quot;can-you-elaborate-on-the-student-projects&quot;&gt;&lt;strong&gt;Can you elaborate on the student projects?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud &amp;#x26; Imme&lt;/em&gt;: Sure! Below are the results from 4 student projects: Wenyu looked at &lt;a href=&quot;http://resolver.tudelft.nl/uuid:28f594b4-b24f-4aec-b01c-662e777ca971&quot;&gt;monsoon moisture source&lt;/a&gt; for the Yangtze River Basin, Rens studied &lt;a href=&quot;http://resolver.tudelft.nl/uuid:4e8cfdc1-350f-403f-aa7e-e76b55f5a800&quot;&gt;trends in moisture sources&lt;/a&gt; related to rising lakes in Keny, Emma studied the &lt;a href=&quot;http://resolver.tudelft.nl/uuid:7185c2b7-8313-4dc9-8a10-f57a7cd5ca35&quot;&gt;drivers of rainfall variability&lt;/a&gt; in Surinam, and Vincent used WAM2layers to study the moisture sources over the Amazon region during August 2023 when a big field campaign took place to understand biosphere-atmosphere interactions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cracking the (moisture) tracking code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-384b7503.DDWvrbCd_Z5iS17.webp&quot; srcset=&quot;&quot;&gt;
WAM2layers output as produced and visualized in students’ projects. Shading illustrates the moisture sources for the each of the case studies.&lt;/p&gt;
&lt;h3 id=&quot;recently-a-follow-up-project-was-granted-so-this-story-will-continue&quot;&gt;&lt;strong&gt;Recently a follow-up project was granted. So this story will continue?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ruud&lt;/em&gt;: Absolutely, with the NWO Open Science project and our own time we want to make WAM2layers even more user-friendly, increase the number of features, applicability to climate models, and get a better grip on the uncertainties. To this end we will also engage with the wider moisture tracking community.&lt;/p&gt;
&lt;h3 id=&quot;will-cmip7-include-an-atmospheric-moisture-tracking-mip-in-the-future&quot;&gt;&lt;strong&gt;Will CMIP7 include an “Atmospheric moisture tracking-MIP” in the future?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Imme&lt;/em&gt;: Ha, that would be amazing of course, but realistically I think there are still some steps in between before such a big goal can be achieved. We are currently initiating a moisture tracking intercomparison project, where multiple moisture tracking models will run the same case to address uncertainty of moisture sources between models. This project will be supported by a workshop at the Lorentz centre in Leiden in May 2024.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is part of a series on our 2021 Small Scale Initiative Call in Software Performance Optimization. See also our post on the project &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/minds-for-mobile-agents-speeding-up-social-distancing-simulations-62d3fb412ff6&quot;&gt;&lt;em&gt;Minds for Mobile Agents&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/cracking-the-moisture-tracking-code-e7c68a7c.D1PgIWpw.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Automatic differentiation from scratch</title><link>https://blog.esciencecenter.nl/posts/2023-11-09---automatic-differentiation-from-scratch</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-09---automatic-differentiation-from-scratch</guid><description>&lt;p&gt;A surprisingly simple and elegant way to teach your computer how to perform derivatives, with some Julia (and Python) examples&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;664&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-b0c3396d.DnMFMg-f_106PyB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@crissyjarvis?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Crissy Jarvis&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;first-a-disclaimer&quot;&gt;First, a disclaimer&lt;/h2&gt;
&lt;p&gt;Automatic differentiation is a well-known sub-field of applied mathematics. You definitely don’t have to implement it from scratch, unless, as I did, you want to. And why would you want to do such a thing? My motivation was a mix of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I like to understand what the packages I use do&lt;/li&gt;
&lt;li&gt;The theory behind automatic differentiation happens to be very beautiful&lt;/li&gt;
&lt;li&gt;I could use it as a case study to improve my understanding of the Julia language&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, if you are interested in performance, you’d likely want to focus on backward automatic differentiation, and not, as I did, on the forward one.&lt;/p&gt;
&lt;p&gt;If you are still reading, it means that after all these disclaimers your intrinsic motivation is still intact. Great! Let me introduce you to the fascinating topic of automatic differentiation and my (quick and dirty) implementation.&lt;/p&gt;
&lt;h2 id=&quot;enter-the-dual-numbers&quot;&gt;Enter the dual numbers&lt;/h2&gt;
&lt;p&gt;Probably you remember it from your high school years. The nightmare of derivatives! All those tables you had to memorize, all those rules you had to apply… chances are that it is not a good memory!&lt;/p&gt;
&lt;p&gt;Would it be possible to teach a computer the rules of differentiation? The answer is yes! It is not only possible but can even be elegant. Enter the dual numbers! A dual number is very similar to a two-dimensional vector:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;112&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7efd31d4.BZRFlLQG_1WlpU.webp&quot; srcset=&quot;&quot;&gt;
the first element represents the value of a function at a given point, and the second one is its derivative at the same point. For instance, the constant 3 will be written as the dual number (3, 0) (the 0 means that it’s a constant and thus its derivative is 0) and the variable x = 3 will be written as (3,1) (the 1 meaning that 3 is an evaluation of the variable x, and thus its derivative respective to x is 1). I know this sounds strange, but stick with me; it will become clearer later.&lt;/p&gt;
&lt;p&gt;So, we have a new mathematical toy. We have to write down the game rules if we want to have any fun with it: let’s start defining addition, subtraction, and multiplication by a scalar. We decide they follow exactly the same rules that vectors do:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;353&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0f2bc067.CsOggy-q_Z1qaYlh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;353&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7ea6a471.pmZHmzUA_Ac09a.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;224&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0c493360.CSP6ISNI_1hG8U0.webp&quot; srcset=&quot;&quot;&gt;
So far, nothing exciting. The multiplication is defined in a more interesting way:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;355&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0256af77.DY7pq6De_1hBSac.webp&quot; srcset=&quot;&quot;&gt;
Why? Because we said the second term represents a derivative, it has to follow the product rule for derivatives.&lt;/p&gt;
&lt;p&gt;What about quotients? You guessed… the division of dual numbers follows the quotient rule for derivatives:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;219&quot; height=&quot;39&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-ae806035.B-ZZ78wS_Z28zKXt.webp&quot; srcset=&quot;&quot;&gt;
Last but not least, the power of a dual number to a real number is defined as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;278&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-dfaecdf1.8__mDMGS_1ztMN1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Perhaps you feel curiosity about the multiplication by u’. This corresponds to the chain rule, and enables our dual numbers for something as desirable as function composition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The operations defined above cover a lot of ground. Indeed, any algebraic operation can be built using them as basic components. This means that we can pass a dual number as the argument of an algebraic function, and here comes the magic, the result will be:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;340&quot; height=&quot;26&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-a331eeae.CjPBcQIW_Z1lMM62.webp&quot; srcset=&quot;&quot;&gt;
It is hard to overstate how powerful this is. The equation above tells us that just by feeding the function the dual number (x, 1) it will return its value at, plus its derivative! Two for the price of one!&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Those readers familiar with complex numbers may find interesting to try the following exercise:&lt;/p&gt;
&lt;p&gt;If we define a dual number as&lt;/p&gt;
&lt;p&gt;(u, u’) = u + e u’&lt;/p&gt;
&lt;p&gt;with e² = 0, all the properties above are automatically satisfied!&lt;/p&gt;
&lt;h2 id=&quot;teaching-derivatives-to-your-computer&quot;&gt;Teaching derivatives to your computer&lt;/h2&gt;
&lt;p&gt;Just as a calculus student will do, the rules of differentiation turn a calculus problem into an algebra one. And the good news: computers are better at algebra than you!&lt;/p&gt;
&lt;p&gt;So, how can we implement these rules in a practical way on our computer? Implementing a new object (a dual number) with its own interaction rules sounds like a task for object-oriented programming. And, interestingly enough, the process is surprisingly similar to that of teaching a human student. With the difference that our “digital student” will never forget a rule, apply it the wrong way, or forget a minus sign!&lt;/p&gt;
&lt;p&gt;So, how do these rules look, for instance, in Julia? (For a Python implementation, take a look &lt;a href=&quot;https://github.com/PabRod/dualdiff&quot;&gt;here&lt;/a&gt;). First of all, we need to define a &lt;code&gt;Dual&lt;/code&gt; object, representing a dual number. In principle, it is as simple as a container for two real numbers:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Structure representing a Dual number &quot;&quot;&quot;
struct Dual
x::Real
dx::Real
endLater, it will come in handy to add a couple of constructors.&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Structure representing a Dual number &quot;&quot;&quot;
struct Dual
x::Real
dx::Real&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;&quot;&quot; Default constructor &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function Dual(x::Real, dx::Real=0)::Dual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    new(x, dx)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;&quot;&quot; If passed a Dual, just return it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This will be handy later &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function Dual(x::Dual)::Dual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;end&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Don’t worry too much if you don’t understand the lines above. They have been added only making the &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt; object easier to use (for instance, &lt;em&gt;&lt;code&gt;*Dual(1)*&lt;/code&gt;&lt;/em&gt; would have failed without the first constructor, and so would have done the application of &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt; to a number that is already a &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another trick that will prove handy soon is to create a type alias for anything that is either a &lt;code&gt;Number&lt;/code&gt; (one of Julia’s base types) or a &lt;code&gt;Dual&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;const DualNumber = Union{Dual, Number}And now comes the fun part. We’ll teach our new object how to do mathematics! For instance, as we saw earlier, the rule for adding dual numbers is to add both their components, just as in a 2D vector:&lt;/p&gt;
&lt;p&gt;import Base: +
function +(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
return Dual(self.x + other.x, self.dx + other.dx)
endWe have to teach even more basic stuff. Remember a computer is dramatically devoid of common sense, so, for instance, we have to define the meaning of a plus sign in front of a &lt;code&gt;Dual&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;+(z::Dual) = z&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This sounds as idiotic as explaining that +3 is equal to 3, but the computer needs to know! Another possibility is using inheritance, but this is an advanced topic beyond the scope of this piece.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Defining minus a &lt;code&gt;Dual&lt;/code&gt; will also be needed:&lt;/p&gt;
&lt;p&gt;import Base: -
-(z::Dual) = Dual(-z.x, -z.dx)and actually, it allows us to define the subtraction of two dual numbers as a sum:&lt;/p&gt;
&lt;p&gt;function -(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
return self + (-other) # A subtraction disguised as a sum!
endSome basic operations may be slightly trickier than expected. For instance, when is a dual number smaller than another dual number? Notice that in this case, it only makes sense to compare the first elements, and ignore the derivatives:&lt;/p&gt;
&lt;p&gt;import Base: &amp;#x3C;
&amp;#x3C;(self::Dual, other::Dual) = self.x &amp;#x3C; other.xAs we saw before, more interesting stuff happens with multiplication and division:&lt;/p&gt;
&lt;p&gt;import Base: *, /&lt;/p&gt;
&lt;p&gt;function *(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x * other.x
dy = self.dx * other.x + self.x * other.dx # Rule of product for derivatives
return Dual(y, dy)
end&lt;/p&gt;
&lt;p&gt;function /(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x / other.x
dy = (self.dx * other.x - self.x * other.dx) / (other.x)^2 # Rule of quotient for derivatives
return Dual(y, dy)
endand with potentiation to a real number:&lt;/p&gt;
&lt;p&gt;import Base: ^
function ^(self::Dual, other::Real)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x^other.x
dy = other.x * self.x^(other.x - 1) * self.dx # Derivative of u(x)^n
return Dual(y, dy)
endThe full list of definitions for algebraic operations &lt;a href=&quot;https://github.com/PabRod/DualDiff.jl/blob/main/src/Dual.jl&quot;&gt;is here&lt;/a&gt;. For Python, use &lt;a href=&quot;https://github.com/PabRod/dualdiff/blob/main/dualdiff/dual.py&quot;&gt;this link&lt;/a&gt;. I recommend taking a look!&lt;/p&gt;
&lt;p&gt;After this, each and every time our dual number finds one of the operations defined above in its mysterious journey down a function or a script, it will keep track of its effect on the derivative. It doesn’t matter how long, complicated, or poorly programmed the function is, the second coordinate of our dual number will manage it. Well, as long as the function is differentiable and we don’t hit the machine’s precision… but that would be asking our computer to do magic.&lt;/p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;As an example, let’s calculate the derivative of the polynomial:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;248&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-ae298bad.Bb9Nk4Zy_Z1BK9tS.webp&quot; srcset=&quot;&quot;&gt;
at x = 3.&lt;/p&gt;
&lt;p&gt;For the sake of clarity, we can compute the derivative by hand:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;224&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-45eb0e13.CT0fgSsk_OLgfP.webp&quot; srcset=&quot;&quot;&gt;
it is apparent that and p(3) = 39 and p’(3) = 34.&lt;/p&gt;
&lt;p&gt;Using our &lt;code&gt;Dual&lt;/code&gt; object, we can reach the same conclusion automatically:&lt;/p&gt;
&lt;p&gt;poly = x -&gt; x^3 + x^2 + x
z = Dual(3, 1)
poly(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(39, 34)Even if the same polynomial is defined in a more intricate way, the &lt;code&gt;Dual&lt;/code&gt; object can keep track:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Equivalent to poly = x -&gt; x^3 + x^2 + x
Just uglier &quot;&quot;&quot;
function poly(x)
aux = 0 # Initialize auxiliary variable
for n in 1:3 # Add x^1, x^2 and x^3
aux = aux + x^n
end
end&lt;/p&gt;
&lt;p&gt;poly(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(39, 34)&lt;/p&gt;
&lt;h2 id=&quot;what-about-non-algebraic-functions&quot;&gt;What about non-algebraic functions?&lt;/h2&gt;
&lt;p&gt;The method sketched above will fail miserably as soon as our function contains a non-algebraic element, such as a sine or an exponential. But don’t panic, we can just go to our calculus book and teach our computer some more basic derivatives. For instance, our table of derivatives tells us that the derivative of a sine is a cosine. In the language of dual numbers, this reads:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;313&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0dd189ff.BBfzEf-y_ZK9RUA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Confused about the u’? Once again, this is just the chain rule.*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The rule of thumb here is, and actually was since the very beginning:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;484&quot; height=&quot;31&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-d3a44ff1.DFvVYuAW_Fgb5f.webp&quot; srcset=&quot;&quot;&gt;
We can create a &lt;code&gt;_factory&lt;/code&gt; function that abstracts this structure for us:&lt;/p&gt;
&lt;p&gt;function _factory(f::Function, df::Function)::Function
return z -&gt; Dual(f(z.x), df(z.x) * z.dx)
endSo now, we only have to open our derivatives table and fill line by line, starting with the derivative of a sine, continuing with that of a cosine, a tangent, etc.&lt;/p&gt;
&lt;p&gt;import Base: sin, cos&lt;/p&gt;
&lt;p&gt;sin(z::Dual) = _factory(sin, cos)(z)
cos(z::Dual) = _factory(cos, x -&gt; -sin(x))(z) # An explicit lambda function is often requiredIf we know our maths, we don’t even need to fill all the derivatives manually from the table. For instance, the tangent is defined as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;135&quot; height=&quot;30&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-3c2438c8.CCr9nuWa_XoBAT.webp&quot; srcset=&quot;&quot;&gt;
and we already have automatically differentiable sine, cosine, and division in our arsenal. So this line will do the trick:&lt;/p&gt;
&lt;p&gt;import Base: tan&lt;/p&gt;
&lt;p&gt;tan(z::Dual) = sin(z) / cos(z) # We can rely on previously defined functions!Of course, hard-coding the tangent’s derivative is also possible, and probably good for code performance and numerical stability. But hey, it’s quite cool that this is even possible!&lt;/p&gt;
&lt;p&gt;See a more complete derivatives table &lt;a href=&quot;https://github.com/PabRod/DualDiff.jl/blob/main/src/primitives.jl&quot;&gt;here&lt;/a&gt; (Python version &lt;a href=&quot;https://github.com/PabRod/dualdiff/blob/main/dualdiff/primitives.py&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;example-1&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Let’s compute the derivative of the non-algebraic function&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;335&quot; height=&quot;28&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-a6b0d3c2.Biri3LFY_Z16f0E.webp&quot; srcset=&quot;&quot;&gt;
It is easy to prove analytically that the derivative is 1 everywhere (notice that the argument of the tangent is actually constant). Now, using &lt;code&gt;Dual&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;fun = x -&gt; x + tan(cos(x)^2 + sin(x)^2)&lt;/p&gt;
&lt;p&gt;z = Dual(0, 1)
fun(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(1.557407724654902, 1.0)&lt;/p&gt;
&lt;h2 id=&quot;making-it-more-user-friendly&quot;&gt;Making it more user-friendly&lt;/h2&gt;
&lt;p&gt;We can use dual numbers to create a user-friendly derivative function:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot;
derivative(f)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seamlessly turns a given function f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;into&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;the function&apos;s derivative&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&quot;&quot;&quot;
function derivative(f)
df = x -&gt; f(Dual(x, 1.0)).dx
return df
endUsing this, our example above will look like:&lt;/p&gt;
&lt;p&gt;fun = x -&gt; x + tan(cos(x)^2 + sin(x)^2)&lt;/p&gt;
&lt;p&gt;dfun = derivative(f)
dfun(0)&lt;/p&gt;
&lt;p&gt;&gt; 1.0&lt;/p&gt;
&lt;h3 id=&quot;another-example&quot;&gt;Another example**&lt;/h3&gt;
&lt;p&gt;Now we want to calculate and visualize the derivatives of:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;388&quot; height=&quot;31&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7e1f04a0.DGpBHSBj_vC9q5.webp&quot; srcset=&quot;&quot;&gt;
First, we have to input the function, and the derivative gets calculated automatically:&lt;/p&gt;
&lt;p&gt;f(x) = x^2 - 5x + 6 - 5x^3 - 5 * exp(-50 * x^2)&lt;/p&gt;
&lt;p&gt;df = derivative(f)We can visualize the results by plotting a tangent line:&lt;/p&gt;
&lt;p&gt;using Plots&lt;/p&gt;
&lt;p&gt;I = [-0.7; 0.7]
δ = 0.025
@gif for a = [I[1]:δ:I[2]; I[2]-δ:-δ:I[1]+δ]
L(x) = f(a) + df(a) * (x - a)
plot(f, -1, 1, leg=false)
scatter!([a], [f(a)], m=(:red, 2))
plot!(L, -1, 1, c=:red)
ylims!(-5, 15)
end
&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-fe83078a.B4ZOJz_g_Z2lQYqz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;is-this-useful&quot;&gt;Is this useful?&lt;/h2&gt;
&lt;p&gt;Automatic differentiation is particularly useful in the field of Machine Learning, where multidimensional derivatives (better known as gradients) have to be performed as fast and exactly as possible. Said this, automatic differentiation for Machine Learning is usually implemented in a different way, the so-called backward or reverse mode, for efficiency reasons.&lt;/p&gt;
&lt;p&gt;A well-established library for automatic differentiation is &lt;a href=&quot;https://jax.readthedocs.io/en/latest/&quot;&gt;JAX&lt;/a&gt; (for Python). Machine learning frameworks such as &lt;a href=&quot;https://www.tensorflow.org/&quot;&gt;Tensorflow&lt;/a&gt; and &lt;a href=&quot;https://pytorch.org/&quot;&gt;Pytorch&lt;/a&gt; also implement automatic differentiation. For Julia, multiple libraries &lt;a href=&quot;https://juliadiff.org/&quot;&gt;seem to be competing&lt;/a&gt;, but &lt;a href=&quot;https://enzyme.mit.edu/&quot;&gt;Enzyme.jl&lt;/a&gt; seems to be ahead. &lt;a href=&quot;https://juliadiff.org/ForwardDiff.jl/stable/&quot;&gt;Forwarddiff.jl&lt;/a&gt; is also worth taking a look at.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I want to say thanks to my colleague and friend &lt;a href=&quot;https://abelsiqueira.com&quot;&gt;Abel Siqueira&lt;/a&gt;, for kindly introducing me to Julia and reviewing this post, and to &lt;a href=&quot;https://medium.com/@aronpjansen&quot;&gt;Aron Jansen&lt;/a&gt;, for his kind and useful suggestions. A more in-depth introduction can be found in &lt;a href=&quot;https://book.sciml.ai/notes/08-Forward-Mode_Automatic_Differentiation_(AD)_via_High_Dimensional_Algebras/&quot;&gt;this episode&lt;/a&gt; of Chris Rackauckas’ &lt;a href=&quot;https://book.sciml.ai/&quot;&gt;book on scientific machine learning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/mathaddons/tex-math-here&quot;&gt;TeX Math Here&lt;/a&gt; browser add-in also played an important role: it allowed me to transfer my Latex equations from Markdown to Medium in an (almost) painless way.&lt;/p&gt;</description><pubDate>Thu, 09 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A surprisingly simple and elegant way to teach your computer how to perform derivatives, with some Julia (and Python) examples&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;664&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-b0c3396d.DnMFMg-f_106PyB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@crissyjarvis?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Crissy Jarvis&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;first-a-disclaimer&quot;&gt;First, a disclaimer&lt;/h2&gt;
&lt;p&gt;Automatic differentiation is a well-known sub-field of applied mathematics. You definitely don’t have to implement it from scratch, unless, as I did, you want to. And why would you want to do such a thing? My motivation was a mix of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I like to understand what the packages I use do&lt;/li&gt;
&lt;li&gt;The theory behind automatic differentiation happens to be very beautiful&lt;/li&gt;
&lt;li&gt;I could use it as a case study to improve my understanding of the Julia language&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, if you are interested in performance, you’d likely want to focus on backward automatic differentiation, and not, as I did, on the forward one.&lt;/p&gt;
&lt;p&gt;If you are still reading, it means that after all these disclaimers your intrinsic motivation is still intact. Great! Let me introduce you to the fascinating topic of automatic differentiation and my (quick and dirty) implementation.&lt;/p&gt;
&lt;h2 id=&quot;enter-the-dual-numbers&quot;&gt;Enter the dual numbers&lt;/h2&gt;
&lt;p&gt;Probably you remember it from your high school years. The nightmare of derivatives! All those tables you had to memorize, all those rules you had to apply… chances are that it is not a good memory!&lt;/p&gt;
&lt;p&gt;Would it be possible to teach a computer the rules of differentiation? The answer is yes! It is not only possible but can even be elegant. Enter the dual numbers! A dual number is very similar to a two-dimensional vector:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;112&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7efd31d4.BZRFlLQG_1WlpU.webp&quot; srcset=&quot;&quot;&gt;
the first element represents the value of a function at a given point, and the second one is its derivative at the same point. For instance, the constant 3 will be written as the dual number (3, 0) (the 0 means that it’s a constant and thus its derivative is 0) and the variable x = 3 will be written as (3,1) (the 1 meaning that 3 is an evaluation of the variable x, and thus its derivative respective to x is 1). I know this sounds strange, but stick with me; it will become clearer later.&lt;/p&gt;
&lt;p&gt;So, we have a new mathematical toy. We have to write down the game rules if we want to have any fun with it: let’s start defining addition, subtraction, and multiplication by a scalar. We decide they follow exactly the same rules that vectors do:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;353&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0f2bc067.CsOggy-q_Z1qaYlh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;353&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7ea6a471.pmZHmzUA_Ac09a.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;224&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0c493360.CSP6ISNI_1hG8U0.webp&quot; srcset=&quot;&quot;&gt;
So far, nothing exciting. The multiplication is defined in a more interesting way:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;355&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0256af77.DY7pq6De_1hBSac.webp&quot; srcset=&quot;&quot;&gt;
Why? Because we said the second term represents a derivative, it has to follow the product rule for derivatives.&lt;/p&gt;
&lt;p&gt;What about quotients? You guessed… the division of dual numbers follows the quotient rule for derivatives:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;219&quot; height=&quot;39&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-ae806035.B-ZZ78wS_Z28zKXt.webp&quot; srcset=&quot;&quot;&gt;
Last but not least, the power of a dual number to a real number is defined as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;278&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-dfaecdf1.8__mDMGS_1ztMN1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Perhaps you feel curiosity about the multiplication by u’. This corresponds to the chain rule, and enables our dual numbers for something as desirable as function composition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The operations defined above cover a lot of ground. Indeed, any algebraic operation can be built using them as basic components. This means that we can pass a dual number as the argument of an algebraic function, and here comes the magic, the result will be:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;340&quot; height=&quot;26&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-a331eeae.CjPBcQIW_Z1lMM62.webp&quot; srcset=&quot;&quot;&gt;
It is hard to overstate how powerful this is. The equation above tells us that just by feeding the function the dual number (x, 1) it will return its value at, plus its derivative! Two for the price of one!&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Those readers familiar with complex numbers may find interesting to try the following exercise:&lt;/p&gt;
&lt;p&gt;If we define a dual number as&lt;/p&gt;
&lt;p&gt;(u, u’) = u + e u’&lt;/p&gt;
&lt;p&gt;with e² = 0, all the properties above are automatically satisfied!&lt;/p&gt;
&lt;h2 id=&quot;teaching-derivatives-to-your-computer&quot;&gt;Teaching derivatives to your computer&lt;/h2&gt;
&lt;p&gt;Just as a calculus student will do, the rules of differentiation turn a calculus problem into an algebra one. And the good news: computers are better at algebra than you!&lt;/p&gt;
&lt;p&gt;So, how can we implement these rules in a practical way on our computer? Implementing a new object (a dual number) with its own interaction rules sounds like a task for object-oriented programming. And, interestingly enough, the process is surprisingly similar to that of teaching a human student. With the difference that our “digital student” will never forget a rule, apply it the wrong way, or forget a minus sign!&lt;/p&gt;
&lt;p&gt;So, how do these rules look, for instance, in Julia? (For a Python implementation, take a look &lt;a href=&quot;https://github.com/PabRod/dualdiff&quot;&gt;here&lt;/a&gt;). First of all, we need to define a &lt;code&gt;Dual&lt;/code&gt; object, representing a dual number. In principle, it is as simple as a container for two real numbers:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Structure representing a Dual number &quot;&quot;&quot;
struct Dual
x::Real
dx::Real
endLater, it will come in handy to add a couple of constructors.&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Structure representing a Dual number &quot;&quot;&quot;
struct Dual
x::Real
dx::Real&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;&quot;&quot; Default constructor &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function Dual(x::Real, dx::Real=0)::Dual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    new(x, dx)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;&quot;&quot; If passed a Dual, just return it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This will be handy later &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function Dual(x::Dual)::Dual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;end&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Don’t worry too much if you don’t understand the lines above. They have been added only making the &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt; object easier to use (for instance, &lt;em&gt;&lt;code&gt;*Dual(1)*&lt;/code&gt;&lt;/em&gt; would have failed without the first constructor, and so would have done the application of &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt; to a number that is already a &lt;em&gt;&lt;code&gt;*Dual*&lt;/code&gt;&lt;/em&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another trick that will prove handy soon is to create a type alias for anything that is either a &lt;code&gt;Number&lt;/code&gt; (one of Julia’s base types) or a &lt;code&gt;Dual&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;const DualNumber = Union{Dual, Number}And now comes the fun part. We’ll teach our new object how to do mathematics! For instance, as we saw earlier, the rule for adding dual numbers is to add both their components, just as in a 2D vector:&lt;/p&gt;
&lt;p&gt;import Base: +
function +(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
return Dual(self.x + other.x, self.dx + other.dx)
endWe have to teach even more basic stuff. Remember a computer is dramatically devoid of common sense, so, for instance, we have to define the meaning of a plus sign in front of a &lt;code&gt;Dual&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;+(z::Dual) = z&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This sounds as idiotic as explaining that +3 is equal to 3, but the computer needs to know! Another possibility is using inheritance, but this is an advanced topic beyond the scope of this piece.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Defining minus a &lt;code&gt;Dual&lt;/code&gt; will also be needed:&lt;/p&gt;
&lt;p&gt;import Base: -
-(z::Dual) = Dual(-z.x, -z.dx)and actually, it allows us to define the subtraction of two dual numbers as a sum:&lt;/p&gt;
&lt;p&gt;function -(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
return self + (-other) # A subtraction disguised as a sum!
endSome basic operations may be slightly trickier than expected. For instance, when is a dual number smaller than another dual number? Notice that in this case, it only makes sense to compare the first elements, and ignore the derivatives:&lt;/p&gt;
&lt;p&gt;import Base: &amp;#x3C;
&amp;#x3C;(self::Dual, other::Dual) = self.x &amp;#x3C; other.xAs we saw before, more interesting stuff happens with multiplication and division:&lt;/p&gt;
&lt;p&gt;import Base: *, /&lt;/p&gt;
&lt;p&gt;function *(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x * other.x
dy = self.dx * other.x + self.x * other.dx # Rule of product for derivatives
return Dual(y, dy)
end&lt;/p&gt;
&lt;p&gt;function /(self::DualNumber, other::DualNumber)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x / other.x
dy = (self.dx * other.x - self.x * other.dx) / (other.x)^2 # Rule of quotient for derivatives
return Dual(y, dy)
endand with potentiation to a real number:&lt;/p&gt;
&lt;p&gt;import Base: ^
function ^(self::Dual, other::Real)::Dual
self, other = Dual(self), Dual(other) # Coerce into Dual
y = self.x^other.x
dy = other.x * self.x^(other.x - 1) * self.dx # Derivative of u(x)^n
return Dual(y, dy)
endThe full list of definitions for algebraic operations &lt;a href=&quot;https://github.com/PabRod/DualDiff.jl/blob/main/src/Dual.jl&quot;&gt;is here&lt;/a&gt;. For Python, use &lt;a href=&quot;https://github.com/PabRod/dualdiff/blob/main/dualdiff/dual.py&quot;&gt;this link&lt;/a&gt;. I recommend taking a look!&lt;/p&gt;
&lt;p&gt;After this, each and every time our dual number finds one of the operations defined above in its mysterious journey down a function or a script, it will keep track of its effect on the derivative. It doesn’t matter how long, complicated, or poorly programmed the function is, the second coordinate of our dual number will manage it. Well, as long as the function is differentiable and we don’t hit the machine’s precision… but that would be asking our computer to do magic.&lt;/p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;As an example, let’s calculate the derivative of the polynomial:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;248&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-ae298bad.Bb9Nk4Zy_Z1BK9tS.webp&quot; srcset=&quot;&quot;&gt;
at x = 3.&lt;/p&gt;
&lt;p&gt;For the sake of clarity, we can compute the derivative by hand:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;224&quot; height=&quot;27&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-45eb0e13.CT0fgSsk_OLgfP.webp&quot; srcset=&quot;&quot;&gt;
it is apparent that and p(3) = 39 and p’(3) = 34.&lt;/p&gt;
&lt;p&gt;Using our &lt;code&gt;Dual&lt;/code&gt; object, we can reach the same conclusion automatically:&lt;/p&gt;
&lt;p&gt;poly = x -&gt; x^3 + x^2 + x
z = Dual(3, 1)
poly(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(39, 34)Even if the same polynomial is defined in a more intricate way, the &lt;code&gt;Dual&lt;/code&gt; object can keep track:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot; Equivalent to poly = x -&gt; x^3 + x^2 + x
Just uglier &quot;&quot;&quot;
function poly(x)
aux = 0 # Initialize auxiliary variable
for n in 1:3 # Add x^1, x^2 and x^3
aux = aux + x^n
end
end&lt;/p&gt;
&lt;p&gt;poly(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(39, 34)&lt;/p&gt;
&lt;h2 id=&quot;what-about-non-algebraic-functions&quot;&gt;What about non-algebraic functions?&lt;/h2&gt;
&lt;p&gt;The method sketched above will fail miserably as soon as our function contains a non-algebraic element, such as a sine or an exponential. But don’t panic, we can just go to our calculus book and teach our computer some more basic derivatives. For instance, our table of derivatives tells us that the derivative of a sine is a cosine. In the language of dual numbers, this reads:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;313&quot; height=&quot;25&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-0dd189ff.BBfzEf-y_ZK9RUA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Confused about the u’? Once again, this is just the chain rule.*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The rule of thumb here is, and actually was since the very beginning:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;484&quot; height=&quot;31&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-d3a44ff1.DFvVYuAW_Fgb5f.webp&quot; srcset=&quot;&quot;&gt;
We can create a &lt;code&gt;_factory&lt;/code&gt; function that abstracts this structure for us:&lt;/p&gt;
&lt;p&gt;function _factory(f::Function, df::Function)::Function
return z -&gt; Dual(f(z.x), df(z.x) * z.dx)
endSo now, we only have to open our derivatives table and fill line by line, starting with the derivative of a sine, continuing with that of a cosine, a tangent, etc.&lt;/p&gt;
&lt;p&gt;import Base: sin, cos&lt;/p&gt;
&lt;p&gt;sin(z::Dual) = _factory(sin, cos)(z)
cos(z::Dual) = _factory(cos, x -&gt; -sin(x))(z) # An explicit lambda function is often requiredIf we know our maths, we don’t even need to fill all the derivatives manually from the table. For instance, the tangent is defined as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;135&quot; height=&quot;30&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-3c2438c8.CCr9nuWa_XoBAT.webp&quot; srcset=&quot;&quot;&gt;
and we already have automatically differentiable sine, cosine, and division in our arsenal. So this line will do the trick:&lt;/p&gt;
&lt;p&gt;import Base: tan&lt;/p&gt;
&lt;p&gt;tan(z::Dual) = sin(z) / cos(z) # We can rely on previously defined functions!Of course, hard-coding the tangent’s derivative is also possible, and probably good for code performance and numerical stability. But hey, it’s quite cool that this is even possible!&lt;/p&gt;
&lt;p&gt;See a more complete derivatives table &lt;a href=&quot;https://github.com/PabRod/DualDiff.jl/blob/main/src/primitives.jl&quot;&gt;here&lt;/a&gt; (Python version &lt;a href=&quot;https://github.com/PabRod/dualdiff/blob/main/dualdiff/primitives.py&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;example-1&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Let’s compute the derivative of the non-algebraic function&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;335&quot; height=&quot;28&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-a6b0d3c2.Biri3LFY_Z16f0E.webp&quot; srcset=&quot;&quot;&gt;
It is easy to prove analytically that the derivative is 1 everywhere (notice that the argument of the tangent is actually constant). Now, using &lt;code&gt;Dual&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;fun = x -&gt; x + tan(cos(x)^2 + sin(x)^2)&lt;/p&gt;
&lt;p&gt;z = Dual(0, 1)
fun(z)&lt;/p&gt;
&lt;p&gt;&gt; Dual(1.557407724654902, 1.0)&lt;/p&gt;
&lt;h2 id=&quot;making-it-more-user-friendly&quot;&gt;Making it more user-friendly&lt;/h2&gt;
&lt;p&gt;We can use dual numbers to create a user-friendly derivative function:&lt;/p&gt;
&lt;p&gt;&quot;&quot;&quot;
derivative(f)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seamlessly turns a given function f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;into&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;the function&apos;s derivative&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&quot;&quot;&quot;
function derivative(f)
df = x -&gt; f(Dual(x, 1.0)).dx
return df
endUsing this, our example above will look like:&lt;/p&gt;
&lt;p&gt;fun = x -&gt; x + tan(cos(x)^2 + sin(x)^2)&lt;/p&gt;
&lt;p&gt;dfun = derivative(f)
dfun(0)&lt;/p&gt;
&lt;p&gt;&gt; 1.0&lt;/p&gt;
&lt;h3 id=&quot;another-example&quot;&gt;Another example**&lt;/h3&gt;
&lt;p&gt;Now we want to calculate and visualize the derivatives of:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;388&quot; height=&quot;31&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-7e1f04a0.DGpBHSBj_vC9q5.webp&quot; srcset=&quot;&quot;&gt;
First, we have to input the function, and the derivative gets calculated automatically:&lt;/p&gt;
&lt;p&gt;f(x) = x^2 - 5x + 6 - 5x^3 - 5 * exp(-50 * x^2)&lt;/p&gt;
&lt;p&gt;df = derivative(f)We can visualize the results by plotting a tangent line:&lt;/p&gt;
&lt;p&gt;using Plots&lt;/p&gt;
&lt;p&gt;I = [-0.7; 0.7]
δ = 0.025
@gif for a = [I[1]:δ:I[2]; I[2]-δ:-δ:I[1]+δ]
L(x) = f(a) + df(a) * (x - a)
plot(f, -1, 1, leg=false)
scatter!([a], [f(a)], m=(:red, 2))
plot!(L, -1, 1, c=:red)
ylims!(-5, 15)
end
&lt;img alt=&quot;Automatic differentiation from scratch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/automatic-differentiation-from-scratch-fe83078a.B4ZOJz_g_Z2lQYqz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;is-this-useful&quot;&gt;Is this useful?&lt;/h2&gt;
&lt;p&gt;Automatic differentiation is particularly useful in the field of Machine Learning, where multidimensional derivatives (better known as gradients) have to be performed as fast and exactly as possible. Said this, automatic differentiation for Machine Learning is usually implemented in a different way, the so-called backward or reverse mode, for efficiency reasons.&lt;/p&gt;
&lt;p&gt;A well-established library for automatic differentiation is &lt;a href=&quot;https://jax.readthedocs.io/en/latest/&quot;&gt;JAX&lt;/a&gt; (for Python). Machine learning frameworks such as &lt;a href=&quot;https://www.tensorflow.org/&quot;&gt;Tensorflow&lt;/a&gt; and &lt;a href=&quot;https://pytorch.org/&quot;&gt;Pytorch&lt;/a&gt; also implement automatic differentiation. For Julia, multiple libraries &lt;a href=&quot;https://juliadiff.org/&quot;&gt;seem to be competing&lt;/a&gt;, but &lt;a href=&quot;https://enzyme.mit.edu/&quot;&gt;Enzyme.jl&lt;/a&gt; seems to be ahead. &lt;a href=&quot;https://juliadiff.org/ForwardDiff.jl/stable/&quot;&gt;Forwarddiff.jl&lt;/a&gt; is also worth taking a look at.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I want to say thanks to my colleague and friend &lt;a href=&quot;https://abelsiqueira.com&quot;&gt;Abel Siqueira&lt;/a&gt;, for kindly introducing me to Julia and reviewing this post, and to &lt;a href=&quot;https://medium.com/@aronpjansen&quot;&gt;Aron Jansen&lt;/a&gt;, for his kind and useful suggestions. A more in-depth introduction can be found in &lt;a href=&quot;https://book.sciml.ai/notes/08-Forward-Mode_Automatic_Differentiation_(AD)_via_High_Dimensional_Algebras/&quot;&gt;this episode&lt;/a&gt; of Chris Rackauckas’ &lt;a href=&quot;https://book.sciml.ai/&quot;&gt;book on scientific machine learning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/mathaddons/tex-math-here&quot;&gt;TeX Math Here&lt;/a&gt; browser add-in also played an important role: it allowed me to transfer my Latex equations from Markdown to Medium in an (almost) painless way.&lt;/p&gt;</content:encoded><media:content url="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAAAZCAYAAADpG6rZAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtGVYSWZJSSoACAAAAAYAEgEDAAEAAAABAAAAGgEFAAEAAABWAAAAGwEFAAEAAABeAAAAKAEDAAEAAAACAAAAEwIDAAEAAAABAAAAaYcEAAEAAABmAAAAAAAAAEgAAAABAAAASAAAAAEAAAAGAACQBwAEAAAAMDIxMAGRBwAEAAAAAQIDAACgBwAEAAAAMDEwMAGgAwABAAAA//8AAAKgBAABAAAAcAAAAAOgBAABAAAAGQAAAAAAAADeQpc6AAADQElEQVR4nN1ajXXiMAyW7rFAV+BGSEeAEXIjcCNwI4QRygjtCM0IzQhkhDKC+j4i94xjJzblJ/H3HhAcx7ItS5Y+h0WEcgMzl0RUi8iRZgJm3hDRioj+mn4zM/63ItKGnvtFmYG7iSjmpDzFloiw8JZWWUNEL8xchB7inCyQO8srReQPzQiqoA/1Gmvn3hMRvRPR2rcos7FA7gZawQXR/ICFB+zcG6q0PSwxawtkZgzwKCL/aGZgZljfk4j8Hqhz0P2xtssXlAGYGfsG9r7gBEy870WE59jrPlnn6EJLbPhD0drE+45IEwoawhuiVFV4lgqsaZ4oVDmD0MXZWPulX4GI5OBvmflTQ3JTXjAzTHiKwUsxpkCMhZkrZn63x+WM71Xbu7QvSTL0d+ULXgJotP5/IIgxH735qWHrh16XWv5q153Kh7q+4WI5UAdj2Oo1ItVPT51qrJ2RflwkQ3PWWBm9dt0g5hQIWEzAUicIDz6nrETX1BOBPSE2HVjha2T/21j5Fcbks7JR1mMEF8kQEVhVLNpeu5Faj14lD7DAqhtG8H5hWQYGj4sXp463PKEPN5cR8jbBNEL9M3KrXeIqmRSk67vpv/EK7n5pypupynAACz9Z8WKM1ZghpziElSb7btRnuMZ6JjK+sQjwctufKE/3zrN8JRHHG1l9qQmxi+KKeeQ9ZDReBaryvGQwwuMEmgrt9MLoBGDhxBLSbUwlPZrp1bfSkJ0duEUk1o+QYQK2Y0+BqjxMek9Jqfmfuo/R5PRKaM3kuTxhAK5lu5N+ihQ987JP8ApJMhJx1vbCCVhqPX/CCjGTUSjRGp1G3BMiUjMzRbhsM2Hf9XTcW+d+4VhGpROOeXi+kYxYnNywXWAs0AQsjcXsG6FQ5NkZ1QTxZgUJXmDvYWbklmBL4IKMW1srcQGesTdBFvsxytD8QEYs8Oy54kNsgFaebP7n9HVDRIfIuoa+Ohublg2xOVVCfy6SMdJm6WN3cjoPPPjOy67YfkoQd7fzzizOAxU733nZNeAe4dwbKr/0nXfmcpxEJijQ92KujW3CicEtECRVsnGhMS8AXQJdEO2j6ETrLTsvuZ+VAsnJZ+dOA1rESnDv/QJBeKCfziT5nwAAAABJRU5ErkJggg==" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!</title><link>https://blog.esciencecenter.nl/posts/2023-11-06---how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chat</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-06---how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chat</guid><description>&lt;p&gt;4&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Are you ready to dive into the captivating world of Orange3 widgets and unleash your inner chatbot whisperer? 🚀✨ Whether you’re a coding connoisseur or a newbie explorer, developing your own widget doesn’t have to be a Herculean task. In fact, with a little sprinkle of curiosity and a dash of HuggingChat magic, you’ll be crafting your own chatbot widget in no time!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;616&quot; height=&quot;229&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-63271872.CxrTmfMj_8LbTW.webp&quot; srcset=&quot;&quot;&gt;
In a future blog &lt;a href=&quot;https://blog.esciencecenter.nl/the-orange3-data-mining-platform-as-a-research-tool-2167336a5c0d&quot;&gt;post&lt;/a&gt; by my colleague, Kody Moodley, you will catch a glimpse of what Orange3 is all about, along with its snazzy uniqueness (if not, seriously, what are you waiting for? Go give it a whirl!). But for now, I bet you’re riding the wave of curiosity mixed with a sprinkle of concern — “Will it be a brain drain, and will I get tangled in the web of complexity while treading the path of development?”&lt;/p&gt;
&lt;p&gt;What I aim to convey through this post is that creating widgets on Orange3 is as easy as pie! However, writing the post takes me some serious brainpower. I’ve been on an epic quest to unravel the secrets of making the content simple, yet captivating. But you know what they say, inspiration strikes in the most unexpected places. Picture this: I’m casually chatting with a friend on the newly released Android client of ChatGPT, and bam! Just like that, it hit me — why not roll up my sleeves and craft my very own chatbot widget on Orange3?&lt;/p&gt;
&lt;p&gt;My initial brainstorm led me straight to a ChatGPT-powered chatbot, but alas, I wear the open-source cape proudly! Thus, I turned my gaze toward the enchanting realm of HuggingChat. 🌟 With a dash of curiosity, I dove into the API docs at lightning speed and spent a solid three hours conjuring up all the magic you’re about to read.&lt;/p&gt;
&lt;h2 id=&quot;before-diving-into-the-core&quot;&gt;Before diving into the core&lt;/h2&gt;
&lt;p&gt;Embarking on a journey is always thrilling, but you might find yourself going, “Where in the world do I begin?” Fret not, for Orange3 has your back with a nifty add-on template. No need to suffer the pains of starting from scratch — just give ’em a friendly clone from &lt;a href=&quot;https://github.com/biolab/orange3-example-addon&quot;&gt;GitHub&lt;/a&gt; to your computer and sprinkle in the required Python libraries.&lt;/p&gt;
&lt;p&gt;#Clone the repo of the example Orange3 add-on
git clone &lt;a href=&quot;https://github.com/biolab/orange3-example-addon.git&quot;&gt;https://github.com/biolab/orange3-example-addon.git&lt;/a&gt;
cd orange3-example-addon&lt;/p&gt;
&lt;p&gt;#Install Orange3 and other required packages
python -m venv orangedev&lt;br&gt;
source orangedev/bin/activate
pip install pyqt6 pyqt6-webengine orange3 hugchatTime for a little detective work! Execute these commands to check if you have everything in the right place.&lt;/p&gt;
&lt;p&gt;#Install the example add-on and open the GUI application of Orange
pip install -e .&lt;br&gt;
python -m Orange.canvas  If everything goes well, you should be able to see the following window popping up, where you can find that your &lt;em&gt;Example&lt;/em&gt; add-on and &lt;em&gt;Hello World&lt;/em&gt; widget are already there.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;520&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-0731634a.BnLglC5T_Z1fmEqy.webp&quot; srcset=&quot;&quot;&gt;
The canvas application with the example add-on installed.&lt;/p&gt;
&lt;h2 id=&quot;the-serious-showdown&quot;&gt;The serious showdown&lt;/h2&gt;
&lt;p&gt;Before we wade into the treacherous waters ahead, let’s take a peek at what awaits from these three hours of dedicated effort.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1232&quot; height=&quot;822&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-e0526449.CWhEQcUE_1eLMh3.webp&quot; srcset=&quot;&quot;&gt;
The chatbot widget.In brief, I have a chatbot that allows me to log in with my own HuggingFace account and password, answer my questions, and record all of the historical conversations. The only thing I did was create a Python file named “HugChat.py*” *and put it in the folder “orange3-example-addon/orangecontrib/example/widgets”. Check the content of my file to get a first impression of how easy the work is.&lt;/p&gt;
&lt;p&gt;#Content of the HugChat.py file
from Orange.data import Table
from Orange.widgets import gui
from Orange.widgets.settings import Setting
from Orange.widgets.widget import OWWidget, Output
from Orange.data.pandas_compat import table_from_frame&lt;/p&gt;
&lt;p&gt;from hugchat.login import Login
from hugchat import hugchat
import textwrap
import pandas as pd&lt;/p&gt;
&lt;p&gt;class HugChat(OWWidget):
name = “Hugging Chatbot”
description = “Orange3 widget instance of HuggingChat.”
icon = “icons/mywidget.svg”
want_main_area = True&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;email = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;passwd = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;query = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class Outputs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data = Output(&quot;Data&quot;, Table)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def __init__(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    super().__init__()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.queries = []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.replies = []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot = None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # control area: login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;email&quot;, label=&quot;Email&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;passwd&quot;, label=&quot;Password&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.button(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;               label=&quot;Login&quot;, callback=self.init_chatbot)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # main area: chatbot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.mainArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;query&quot;, label=&quot;Query&quot;, callback=self.chat)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.reply = gui.WebviewWidget(parent=None, debug=False)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.mainArea.layout().addWidget(self.reply)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def init_chatbot(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sign = Login(self.email, self.passwd) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # cookies setup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cookie_path_dir = &quot;./cookies_snapshot&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sign.saveCookiesToDir(cookie_path_dir)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cookies = sign.login()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # initialize chatbot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot = hugchat.ChatBot(cookies=cookies.get_dict())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # initialize a new conversation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id = self.chatbot.new_conversation()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot.change_conversation(id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def chat(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reply_text = self.chatbot.chat(text=self.query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.reply.setHtml(reply_text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # update the output table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.queries.append(self.query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.replies.append(reply_text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    df_output = pd.DataFrame({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;Query&quot;: self.queries, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;Reply&quot;: self.replies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.Outputs.data.send(table_from_frame(df_output))Now, let’s look at the details. The code above defines a class that contains all the features and functions of our widget. This class is inherited from another class named `OWWidget`, which is the base class of all Orange3 widgets. From there, we can rewrite existing functions and create new functions to satisfy our requirements.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the top of the class, we have a brief description of the widget, including its name, a short text explaining what it does, and a path string pointing to the location of the widget icon. An additional flag called &lt;code&gt;want_main_area&lt;/code&gt; is assigned to be true, which means that we want to present the main area of the widget and show things there.&lt;/p&gt;
&lt;p&gt;name = “Hugging Chatbot”
description = “Orange3 widget instance of HuggingChat.”
icon = “icons/mywidget.svg”
want_main_area = TrueA widget can contain both the control and main area, while the main area is optional. To briefly explain, the control area should contain all of the utilities for preparing the widget, while the main area is for the major functionality.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;438&quot; height=&quot;129&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-92940abc.n9LoFlfw_1iwNgH.webp&quot; srcset=&quot;&quot;&gt;
Sub-interface of our widget that includes both the control and main area.We also have three class attributes defined, which will be used to store the result of interacting with the GUI controls (I will come back to this later). If there are any output tables, they will be defined in an inner class named &lt;code&gt;Outputs&lt;/code&gt;. In our case, we only have one output table for outputting the chatting history.&lt;/p&gt;
&lt;p&gt;email = Setting(&quot;&quot;)
passwd = Setting(&quot;&quot;)
query = Setting(&quot;&quot;)&lt;/p&gt;
&lt;p&gt;class Outputs:
data = Output(“Data”, Table)Next, we defined the &lt;code&gt;__init__&lt;/code&gt; method, where we run &lt;code&gt;__init__&lt;/code&gt; of the parent class, initialize all the instance attributes, and define the GUI of the widget. We got two empty lists, &lt;code&gt;queries&lt;/code&gt; and &lt;code&gt;replies&lt;/code&gt;, for storing the chat history, and &lt;code&gt;chatbot&lt;/code&gt; which is the HuggingChat object. Now, let’s focus on the part of GUI construction.&lt;/p&gt;
&lt;h1 id=&quot;control-area-login&quot;&gt;control area: login&lt;/h1&gt;
&lt;p&gt;gui.lineEdit(widget=self.controlArea, master=self,
value=“email”, label=“Email”)
gui.lineEdit(widget=self.controlArea, master=self,
value=“passwd”, label=“Password”)
gui.button(widget=self.controlArea, master=self,
label=“Login”, callback=self.init_chatbot)&lt;/p&gt;
&lt;h1 id=&quot;main-area-chatbot&quot;&gt;main area: chatbot&lt;/h1&gt;
&lt;p&gt;gui.lineEdit(widget=self.mainArea, master=self,
value=“query”, label=“Query”, callback=self.chat)
self.reply = gui.WebviewWidget(parent=None, debug=False)
self.mainArea.layout().addWidget(self.reply)The above code adds GUI controls to both the control and main area, where GUI controls will be added and placed in the interface by following the order of their definitions in the code. You should be able to find three types of GUI controls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lineEdit&lt;/code&gt; that allows the user to input some text,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;button&lt;/code&gt; that will trigger a pre-defined function by clicking, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WebviewWidget&lt;/code&gt; that will render some HTML content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog, I will not explain everything so that you will have the motivation to check the &lt;a href=&quot;https://orange-widget-base.readthedocs.io/en/latest/gui.html&quot;&gt;documentation&lt;/a&gt; yourselves. To briefly summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the control area, two &lt;code&gt;lineEdit&lt;/code&gt; controls are defined to accept the login information as input and store them in the pre-defined class attributes &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt;. They are followed by a button to trigger the callback method &lt;code&gt;self.init_chatbot&lt;/code&gt; for initializing the chatbot instance.&lt;/li&gt;
&lt;li&gt;In the main area, another &lt;code&gt;lineEdit&lt;/code&gt; control is defined as accepting the user’s query, with the callback &lt;code&gt;self.chat&lt;/code&gt; to send the query to the chatbot instance and get the reply, triggered by enter-clicking. The callback method is also responded to display the reply message in the &lt;code&gt;WebviewWidget&lt;/code&gt; below.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Up to this point, we have thoroughly reviewed the process of defining a widget. In simple terms, it includes widget descriptions, input-output definitions, and GUI control definitions. Although the functionalities of different widgets may vary, the design process is largely similar. Orange3 defines a multitude of foundational classes, standardizes data transfer between widgets, and establishes a comprehensive and efficient workflow engine. This enables developers to better focus on the modular design and development of widget functionalities&lt;/p&gt;
&lt;h2 id=&quot;the-adventure-has-just-begun&quot;&gt;The adventure has just begun&lt;/h2&gt;
&lt;p&gt;So, I bet you’re already getting the hang of developing your own widgets on Orange3, and you’re practically bursting with creative energy – high five to that! But hold your horses, my friend, because this blog post is just the opening scene of our grand adventure. There’s a whole treasure trove of discoveries waiting for you, like defining your very own add-on, crafting widgets that dance with interactive visuals, and even sending your widgets off to the fancy official platform. Don’t panic, though – these aren’t things you need to wrestle with right now. And guess what? You’re not alone on this journey! Craving more Orange3 tales and tech tidbits? Get in touch with us (&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-kody-moodley/&quot;&gt;Kody&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;me&lt;/a&gt;)! Or drop a hint for more juicy insights below this blog! Can’t wait to bump into you again on this wild Orange3 expedition!&lt;/p&gt;
&lt;p&gt;DISCLAIMER: As you probably found out from the start: we also called in some AI support for the creation of this blogpost. We prompted ChatGPT to make the original text ‘more fun to read’. We hope reading it actually sparked some joy for you!*&lt;/p&gt;</description><pubDate>Mon, 06 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;4&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Are you ready to dive into the captivating world of Orange3 widgets and unleash your inner chatbot whisperer? 🚀✨ Whether you’re a coding connoisseur or a newbie explorer, developing your own widget doesn’t have to be a Herculean task. In fact, with a little sprinkle of curiosity and a dash of HuggingChat magic, you’ll be crafting your own chatbot widget in no time!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;616&quot; height=&quot;229&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-63271872.CxrTmfMj_8LbTW.webp&quot; srcset=&quot;&quot;&gt;
In a future blog &lt;a href=&quot;https://blog.esciencecenter.nl/the-orange3-data-mining-platform-as-a-research-tool-2167336a5c0d&quot;&gt;post&lt;/a&gt; by my colleague, Kody Moodley, you will catch a glimpse of what Orange3 is all about, along with its snazzy uniqueness (if not, seriously, what are you waiting for? Go give it a whirl!). But for now, I bet you’re riding the wave of curiosity mixed with a sprinkle of concern — “Will it be a brain drain, and will I get tangled in the web of complexity while treading the path of development?”&lt;/p&gt;
&lt;p&gt;What I aim to convey through this post is that creating widgets on Orange3 is as easy as pie! However, writing the post takes me some serious brainpower. I’ve been on an epic quest to unravel the secrets of making the content simple, yet captivating. But you know what they say, inspiration strikes in the most unexpected places. Picture this: I’m casually chatting with a friend on the newly released Android client of ChatGPT, and bam! Just like that, it hit me — why not roll up my sleeves and craft my very own chatbot widget on Orange3?&lt;/p&gt;
&lt;p&gt;My initial brainstorm led me straight to a ChatGPT-powered chatbot, but alas, I wear the open-source cape proudly! Thus, I turned my gaze toward the enchanting realm of HuggingChat. 🌟 With a dash of curiosity, I dove into the API docs at lightning speed and spent a solid three hours conjuring up all the magic you’re about to read.&lt;/p&gt;
&lt;h2 id=&quot;before-diving-into-the-core&quot;&gt;Before diving into the core&lt;/h2&gt;
&lt;p&gt;Embarking on a journey is always thrilling, but you might find yourself going, “Where in the world do I begin?” Fret not, for Orange3 has your back with a nifty add-on template. No need to suffer the pains of starting from scratch — just give ’em a friendly clone from &lt;a href=&quot;https://github.com/biolab/orange3-example-addon&quot;&gt;GitHub&lt;/a&gt; to your computer and sprinkle in the required Python libraries.&lt;/p&gt;
&lt;p&gt;#Clone the repo of the example Orange3 add-on
git clone &lt;a href=&quot;https://github.com/biolab/orange3-example-addon.git&quot;&gt;https://github.com/biolab/orange3-example-addon.git&lt;/a&gt;
cd orange3-example-addon&lt;/p&gt;
&lt;p&gt;#Install Orange3 and other required packages
python -m venv orangedev&lt;br&gt;
source orangedev/bin/activate
pip install pyqt6 pyqt6-webengine orange3 hugchatTime for a little detective work! Execute these commands to check if you have everything in the right place.&lt;/p&gt;
&lt;p&gt;#Install the example add-on and open the GUI application of Orange
pip install -e .&lt;br&gt;
python -m Orange.canvas  If everything goes well, you should be able to see the following window popping up, where you can find that your &lt;em&gt;Example&lt;/em&gt; add-on and &lt;em&gt;Hello World&lt;/em&gt; widget are already there.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;520&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-0731634a.BnLglC5T_Z1fmEqy.webp&quot; srcset=&quot;&quot;&gt;
The canvas application with the example add-on installed.&lt;/p&gt;
&lt;h2 id=&quot;the-serious-showdown&quot;&gt;The serious showdown&lt;/h2&gt;
&lt;p&gt;Before we wade into the treacherous waters ahead, let’s take a peek at what awaits from these three hours of dedicated effort.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1232&quot; height=&quot;822&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-e0526449.CWhEQcUE_1eLMh3.webp&quot; srcset=&quot;&quot;&gt;
The chatbot widget.In brief, I have a chatbot that allows me to log in with my own HuggingFace account and password, answer my questions, and record all of the historical conversations. The only thing I did was create a Python file named “HugChat.py*” *and put it in the folder “orange3-example-addon/orangecontrib/example/widgets”. Check the content of my file to get a first impression of how easy the work is.&lt;/p&gt;
&lt;p&gt;#Content of the HugChat.py file
from Orange.data import Table
from Orange.widgets import gui
from Orange.widgets.settings import Setting
from Orange.widgets.widget import OWWidget, Output
from Orange.data.pandas_compat import table_from_frame&lt;/p&gt;
&lt;p&gt;from hugchat.login import Login
from hugchat import hugchat
import textwrap
import pandas as pd&lt;/p&gt;
&lt;p&gt;class HugChat(OWWidget):
name = “Hugging Chatbot”
description = “Orange3 widget instance of HuggingChat.”
icon = “icons/mywidget.svg”
want_main_area = True&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;email = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;passwd = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;query = Setting(&quot;&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class Outputs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data = Output(&quot;Data&quot;, Table)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def __init__(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    super().__init__()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.queries = []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.replies = []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot = None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # control area: login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;email&quot;, label=&quot;Email&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;passwd&quot;, label=&quot;Password&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.button(widget=self.controlArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;               label=&quot;Login&quot;, callback=self.init_chatbot)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # main area: chatbot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gui.lineEdit(widget=self.mainArea, master=self, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 value=&quot;query&quot;, label=&quot;Query&quot;, callback=self.chat)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.reply = gui.WebviewWidget(parent=None, debug=False)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.mainArea.layout().addWidget(self.reply)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def init_chatbot(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sign = Login(self.email, self.passwd) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # cookies setup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cookie_path_dir = &quot;./cookies_snapshot&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sign.saveCookiesToDir(cookie_path_dir)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cookies = sign.login()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # initialize chatbot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot = hugchat.ChatBot(cookies=cookies.get_dict())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # initialize a new conversation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id = self.chatbot.new_conversation()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.chatbot.change_conversation(id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def chat(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reply_text = self.chatbot.chat(text=self.query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.reply.setHtml(reply_text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    # update the output table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.queries.append(self.query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.replies.append(reply_text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    df_output = pd.DataFrame({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;Query&quot;: self.queries, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;Reply&quot;: self.replies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    self.Outputs.data.send(table_from_frame(df_output))Now, let’s look at the details. The code above defines a class that contains all the features and functions of our widget. This class is inherited from another class named `OWWidget`, which is the base class of all Orange3 widgets. From there, we can rewrite existing functions and create new functions to satisfy our requirements.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the top of the class, we have a brief description of the widget, including its name, a short text explaining what it does, and a path string pointing to the location of the widget icon. An additional flag called &lt;code&gt;want_main_area&lt;/code&gt; is assigned to be true, which means that we want to present the main area of the widget and show things there.&lt;/p&gt;
&lt;p&gt;name = “Hugging Chatbot”
description = “Orange3 widget instance of HuggingChat.”
icon = “icons/mywidget.svg”
want_main_area = TrueA widget can contain both the control and main area, while the main area is optional. To briefly explain, the control area should contain all of the utilities for preparing the widget, while the main area is for the major functionality.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How Easy It Can Be to Whip Up Your Own Orange3 Widget: A Chatbot Adventure with HuggingChat!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;438&quot; height=&quot;129&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-92940abc.n9LoFlfw_1iwNgH.webp&quot; srcset=&quot;&quot;&gt;
Sub-interface of our widget that includes both the control and main area.We also have three class attributes defined, which will be used to store the result of interacting with the GUI controls (I will come back to this later). If there are any output tables, they will be defined in an inner class named &lt;code&gt;Outputs&lt;/code&gt;. In our case, we only have one output table for outputting the chatting history.&lt;/p&gt;
&lt;p&gt;email = Setting(&quot;&quot;)
passwd = Setting(&quot;&quot;)
query = Setting(&quot;&quot;)&lt;/p&gt;
&lt;p&gt;class Outputs:
data = Output(“Data”, Table)Next, we defined the &lt;code&gt;__init__&lt;/code&gt; method, where we run &lt;code&gt;__init__&lt;/code&gt; of the parent class, initialize all the instance attributes, and define the GUI of the widget. We got two empty lists, &lt;code&gt;queries&lt;/code&gt; and &lt;code&gt;replies&lt;/code&gt;, for storing the chat history, and &lt;code&gt;chatbot&lt;/code&gt; which is the HuggingChat object. Now, let’s focus on the part of GUI construction.&lt;/p&gt;
&lt;h1 id=&quot;control-area-login&quot;&gt;control area: login&lt;/h1&gt;
&lt;p&gt;gui.lineEdit(widget=self.controlArea, master=self,
value=“email”, label=“Email”)
gui.lineEdit(widget=self.controlArea, master=self,
value=“passwd”, label=“Password”)
gui.button(widget=self.controlArea, master=self,
label=“Login”, callback=self.init_chatbot)&lt;/p&gt;
&lt;h1 id=&quot;main-area-chatbot&quot;&gt;main area: chatbot&lt;/h1&gt;
&lt;p&gt;gui.lineEdit(widget=self.mainArea, master=self,
value=“query”, label=“Query”, callback=self.chat)
self.reply = gui.WebviewWidget(parent=None, debug=False)
self.mainArea.layout().addWidget(self.reply)The above code adds GUI controls to both the control and main area, where GUI controls will be added and placed in the interface by following the order of their definitions in the code. You should be able to find three types of GUI controls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lineEdit&lt;/code&gt; that allows the user to input some text,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;button&lt;/code&gt; that will trigger a pre-defined function by clicking, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WebviewWidget&lt;/code&gt; that will render some HTML content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog, I will not explain everything so that you will have the motivation to check the &lt;a href=&quot;https://orange-widget-base.readthedocs.io/en/latest/gui.html&quot;&gt;documentation&lt;/a&gt; yourselves. To briefly summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the control area, two &lt;code&gt;lineEdit&lt;/code&gt; controls are defined to accept the login information as input and store them in the pre-defined class attributes &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt;. They are followed by a button to trigger the callback method &lt;code&gt;self.init_chatbot&lt;/code&gt; for initializing the chatbot instance.&lt;/li&gt;
&lt;li&gt;In the main area, another &lt;code&gt;lineEdit&lt;/code&gt; control is defined as accepting the user’s query, with the callback &lt;code&gt;self.chat&lt;/code&gt; to send the query to the chatbot instance and get the reply, triggered by enter-clicking. The callback method is also responded to display the reply message in the &lt;code&gt;WebviewWidget&lt;/code&gt; below.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Up to this point, we have thoroughly reviewed the process of defining a widget. In simple terms, it includes widget descriptions, input-output definitions, and GUI control definitions. Although the functionalities of different widgets may vary, the design process is largely similar. Orange3 defines a multitude of foundational classes, standardizes data transfer between widgets, and establishes a comprehensive and efficient workflow engine. This enables developers to better focus on the modular design and development of widget functionalities&lt;/p&gt;
&lt;h2 id=&quot;the-adventure-has-just-begun&quot;&gt;The adventure has just begun&lt;/h2&gt;
&lt;p&gt;So, I bet you’re already getting the hang of developing your own widgets on Orange3, and you’re practically bursting with creative energy – high five to that! But hold your horses, my friend, because this blog post is just the opening scene of our grand adventure. There’s a whole treasure trove of discoveries waiting for you, like defining your very own add-on, crafting widgets that dance with interactive visuals, and even sending your widgets off to the fancy official platform. Don’t panic, though – these aren’t things you need to wrestle with right now. And guess what? You’re not alone on this journey! Craving more Orange3 tales and tech tidbits? Get in touch with us (&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-kody-moodley/&quot;&gt;Kody&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;me&lt;/a&gt;)! Or drop a hint for more juicy insights below this blog! Can’t wait to bump into you again on this wild Orange3 expedition!&lt;/p&gt;
&lt;p&gt;DISCLAIMER: As you probably found out from the start: we also called in some AI support for the creation of this blogpost. We prompted ChatGPT to make the original text ‘more fun to read’. We hope reading it actually sparked some joy for you!*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-easy-it-can-be-to-whip-up-your-own-o-63271872.CxrTmfMj.png" medium="image"/><author>Ji Qi</author></item><item><title>Investing in people: anticipating the future of research software</title><link>https://blog.esciencecenter.nl/posts/2023-11-02---investing-in-people-anticipating-the-future-of-research-soft</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-02---investing-in-people-anticipating-the-future-of-research-soft</guid><description>&lt;p&gt;*Authored by &lt;em&gt;&lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;&lt;em&gt;Kim Hartley&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;&lt;em&gt;Michelle Barker&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Investing in people: anticipating the future of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/investing-in-people-anticipating-the-fut-ec87efa8.660bh7id_nX0HL.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Photo credit: ADORE.Software&lt;/em&gt; at the International Research Software Funders WorkshopThis article was cross-posted on &lt;a href=&quot;https://adore.software/2023/10/investing-in-people-anticipating-the-future-of-research-software/&quot;&gt;Adore.software&lt;/a&gt; and reports on the progress of the Amsterdam Declaration on Funding Research Software Sustainability. To read more about this initiative and the initial workshop see &lt;a href=&quot;https://blog.esciencecenter.nl/the-future-of-research-software-602878378c5f&quot;&gt;this blogpost&lt;/a&gt; from November 2022.&lt;/p&gt;
&lt;p&gt;We are proud to report that the second &lt;a href=&quot;https://adore.software/international-research-software-funders-workshop/&quot;&gt;International Research Software Funders Workshop&lt;/a&gt;, co-hosted by the &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; (the Alliance) and the &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;Research Software Alliance&lt;/a&gt; (ReSA) from 18–20 September was a great success. People are at the heart of research software sustainability and funders can lead the way by investing in the people who develop and maintain research software. That is why the workshop theme was “Investing in People: Anticipating the Future of Research Software”. The event aimed to set the future agenda for government, philanthropic, and industry funders to support sustainable research software and communities.&lt;/p&gt;
&lt;p&gt;In total, 50 representatives from more than 35 organisations — including funders and organisations that support research software from around the globe — attended the hybrid workshop held in Montreal, Canada, and virtually. During the three-day workshop, experts explored how research software funders can facilitate capacity building through funder practices; research software platforms, infrastructure, and communities; and new initiatives. Moreover, &lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt;Version 1.0 of the Amsterdam Declaration on Funding Research Software Sustainability (ADORE.software)&lt;/a&gt; was released and is now available for &lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;signing&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background**&lt;/h2&gt;
&lt;p&gt;This second iteration of the funders workshop built on the inaugural &lt;a href=&quot;https://future-of-research-software.org/&quot;&gt;International Funders Workshop: The Future of Research Software&lt;/a&gt;, co-hosted by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and ReSA in November 2022 in Amsterdam. During this first workshop, more than 40 funding organisations gathered to set the agenda for supporting sustainable research software and drafting of the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;ADORE.software&lt;/a&gt;. Following public consultation in 2023 and 19 organisational expressions of interest in becoming signatories,&lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt; Version 1.0 of the Declaration was released&lt;/a&gt; in advance of the Montreal workshop and is now available for &lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;signing&lt;/a&gt;. ADORE.software is the first step towards formalising, on a global level, the basic principles and recommendations related to funding the sustainability of research software, including the people needed to achieve this goal.&lt;/p&gt;
&lt;p&gt;The first workshop marked a further step in the development of the research software community. Stakeholders have continued to build on this momentum through involvement in the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, convened by ReSA, and its funder-led working groups. The Alliance and ReSA, together with the workshop Steering Committee, organised the 2nd International Research Software Funders Workshop to continue this important work and facilitate global collaboration among funders and other key decision makers and influencers across the research software ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;2nd-international-research-software-funders-workshop&quot;&gt;&lt;strong&gt;2nd International Research Software Funders Workshop&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Pre-workshop — September 18&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The event commenced with a pre-workshop, including a session on &lt;a href=&quot;https://docs.google.com/presentation/d/1UP_UGOPxYi0R4UAE5PRpGWoJzrQ2FkVmCdDBILR6t2U/edit#slide=id.g241153165a8_0_0&quot;&gt;How to Explicitly Support Research Software as Part of Your Funding Program&lt;/a&gt;, delivered by ReSA, and a session on &lt;a href=&quot;https://zenodo.org/records/8356278&quot;&gt;CiteSoftware&lt;/a&gt;, led by a group of stakeholders aiming to drive the adoption of a common research software preservation and citation guidance resource for the research community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Investing in people: anticipating the future of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/investing-in-people-anticipating-the-fut-708c46e1.d9EqJ9Ja_274aPE.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Photo credit: ADORE.Software&lt;/em&gt; at the International Research Software Funders Workshop&lt;em&gt;&lt;strong&gt;Workshop Day 1 — September 19&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first day of the workshop included presentations that set the scene for participants to explore the crucial role funders play in supporting sustainable research software and communities.&lt;/p&gt;
&lt;p&gt;Carole Goble from the Software Sustainability Institute (SSI)/ELIXIR-UK/University of Manchester &lt;a href=&quot;https://docs.google.com/presentation/d/1dJrhjm7SAcLA96adZsBT-mFiJiwL3Fby/edit?usp=share_link&amp;#x26;ouid=116347134185833638908&amp;#x26;rtpof=true&amp;#x26;sd=true&quot;&gt;provided an overview&lt;/a&gt; of what research software is and why it is critical to the research endeavour. Carole highlighted that the people who make, use, and resource software are fundamental to research software sustainability. Moreover, research software needs resources and both direct (e.g., money) and indirect (e.g., community, reward, recognition, open-source support, etc.) forms of support for sustainability.&lt;/p&gt;
&lt;p&gt;Josh Greenberg from the Alfred P. Sloan Foundation delivered a &lt;a href=&quot;https://drive.google.com/file/d/1MPQ3LgO1jZdJIaF74oSz71XGye2ZjG64/view?usp=share_link&quot;&gt;keynote&lt;/a&gt; that provided a funder’s perspective. He asked attendees several pertinent questions: How much (and when) should we worry about technical debt? How much attention should we pay to user interface design in research software? Who should do which kinds of software? How central should “open source” be? How can we help institutions build capacity for research software development (and maintenance)?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Funders benefit from investing both before (community/need development) and after (ongoing maintenance and re-use) research software development.&lt;/li&gt;
&lt;li&gt;International collaboration and collective action are critical and valuable (e.g., building a multilateral funding initiative due to the global nature of research software).&lt;/li&gt;
&lt;li&gt;Funders should consider how to support and sustain Research Software Engineers (RSEs) but also incentivise researcher-developers to develop better software engineering practices.&lt;/li&gt;
&lt;li&gt;The research software community needs a set of high-level classes to measure the impact of research software, such as citations and mentions of software maturity, or combining mention analysis and dependency analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Malvika Sharan from The Alan Turing Institute and Open Life Science provided a research software community perspective in her &lt;a href=&quot;https://zenodo.org/records/8361334&quot;&gt;talk&lt;/a&gt; on Exploring ‘Do No Harm’ Principles in Open Research Communities. Malvika’s compelling keynote encouraged funders to become leaders in the research software ecosystem by incentivising and recognising all types of research roles; investing in capacity-building goals that focus on bridging scientific and economic divides; and applying community-oriented frameworks to extend the benefits of research to the broader community that ‘do no harm’, thereby ensuring open science practices enable equitable research and research outcomes.&lt;/p&gt;
&lt;p&gt;During the second breakout session, participants investigated capacity building through research software platforms, infrastructure, and communities. One group explored the role of &lt;a href=&quot;https://www.researchsoft.org/blog/2023-06/&quot;&gt;Open Source Program Offices&lt;/a&gt; (OSPOs), noting that OSPOs as centres of software could ultimately help research institutions understand their software investments. Another group considered why and how to support research software communities, highlighting the need for more evidence-led recommendations and exploring the possibility of reversing the funding mechanism to fund projects after the fact, as a function of how much they were used. In discussing research software in research assessment reform, participants noted that very few research software outputs are being assessed and indicators are fragmented and field-specific. Some solutions include sharing guidance on how software is being evaluated in a single place, sharing job profiles for RSEs, and sharing existing examples of research indicators that include software. Finally, another group highlighted that the environmental impact of research software is an emerging field, and persuading researchers to think about making their code efficient is a challenge.&lt;/p&gt;
&lt;p&gt;Workshop Day 2 — September 20***&lt;/p&gt;
&lt;p&gt;The final breakout session focused on building capacity through new initiatives. Participants explored how funders can implement &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;FAIR for Research Software&lt;/a&gt; (FAIR4RS) in funder policy. As some funders are developing guidance, questions arose about whether funders should create guidance individually or collectively and how the community should help funders do this. Through a discussion on how funders use persistent identifiers (PIDs), the need to engage publishers around software citation has become clear. And building on the theme of software citation, participants explored how the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;, a free open-source platform, supports software citation.&lt;/p&gt;
&lt;p&gt;For the final &lt;a href=&quot;https://drive.google.com/file/d/1tzh5cSKX-3yZpqEqzMx7XtfEM9S6jtQY/view?usp=share_link&quot;&gt;keynote&lt;/a&gt;, Jean-Baptiste Poline from McGill University provided a researcher’s perspective on the impact of funders’ investments in research software. Jean-Baptiste presented the role of research software from multiple viewpoints, offering key takeaways such as the value of building a community of researchers through collaborative projects; the need for community-endorsed standards and practices that support open and FAIR (Findable, Accessible, Interoperable, and Reusable) scientific research (e.g., &lt;a href=&quot;https://www.incf.org/&quot;&gt;INCF Network&lt;/a&gt;) to maximise research value; the importance of addressing incentives first; and the idea of funding new technologies and large labs but giving precedence to well-governed communities more than centralised projects. He recommended creating the tools needed to change culture, improving training and open practices, developing community standards, and changing incentives.&lt;/p&gt;
&lt;p&gt;The workshop culminated with a Do-a-Thon, “a short collaboration where participants from different perspectives and skill sets work together on challenges, projects, or to learn something new” (&lt;a href=&quot;https://opencon-cascadia.github.io/doathon/&quot;&gt;OpenCon Cascadia&lt;/a&gt;). Prior to the workshop, participants were invited to submit do-able ideas. During the Do-a-Thon, attendees worked in small groups on the following topics: the &lt;a href=&quot;https://kumu.io/jstarr/ossci-moss&quot;&gt;Map of Open Source Science&lt;/a&gt;; linking software to community usage; and ten things applicants should do to make it easier to assess the impact of funding programs, to build on &lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9671312/&quot;&gt;Ten simple rules for funding scientific open source software&lt;/a&gt; by Carly Strasser et al. This dynamic collaboration resulted in participants considering next steps, crowdsourcing tips, and determining some practical and generalisable approaches to address the challenges explored.&lt;/p&gt;
&lt;h2 id=&quot;overall-outcomes-and-how-you-can-get-involved&quot;&gt;&lt;strong&gt;Overall outcomes and how you can get involved&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The workshop solidified the importance of international collaboration to support research software. There is a widening group of funders with awareness of the need to support research software and an understanding of how to do this. The &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; has been building momentum since its inception in early 2022; its dedicated funder-led working groups are expanding their reach by engaging with other stakeholders and organisations, such as the &lt;a href=&quot;https://globalresearchcouncil.org/&quot;&gt;Global Research Council&lt;/a&gt;. Moreover, the workshop highlighted areas where coordination by funders would be beneficial, for example, in supporting the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt;. Participants also expressed an interest in exploring opportunities for forums, for example to engage publishers around software citations (along with the existing &lt;a href=&quot;https://www.researchsoft.org/taskforces/&quot;&gt;ReSA Task Force on Code Availability&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We thank all the participants for their engagement during the workshop sessions. We’re grateful to the workshop Steering Committee for their efforts in organising a successful hybrid workshop. A full report, written and edited collectively by workshop participants, is forthcoming.&lt;/p&gt;
&lt;p&gt;To stay up to date on ADORE.software, visit &lt;a href=&quot;http://www.adore.software/&quot;&gt;www.adore.software&lt;/a&gt;. If you want to show your support for the Declaration, you can become a &lt;a href=&quot;https://adore.software/sign/&quot;&gt;signatory&lt;/a&gt; (for funders) or &lt;a href=&quot;https://adore.software/support/&quot;&gt;supporter&lt;/a&gt; (for non-funders) and help share the &lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt;news&lt;/a&gt;. To receive updates on news related to the Declaration and future activities, subscribe to the &lt;a href=&quot;https://landing.mailerlite.com/webforms/landing/i5e1h2&quot;&gt;ReSA newsletter&lt;/a&gt;. Funders are invited to join the (free) &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; by contacting ReSA at &lt;a href=&quot;mailto:info@researchsoft.org&quot;&gt;info@researchsoft.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re interested in learning more about ReSA and its activities, join our next &lt;a href=&quot;https://www.researchsoft.org/events/2022-06/&quot;&gt;Research Software Community Leaders Forum&lt;/a&gt; on 15 November at 20:00 UTC. ReSA’s Community Leaders Forum is open to all, and you can &lt;a href=&quot;https://landing.mailerlite.com/webforms/landing/o1n4v3&quot;&gt;sign up&lt;/a&gt; for calendar invites.&lt;/p&gt;
&lt;p&gt;We would like to express our sincere gratitude to our community, Founding Members, and Organisational Members — without whom none of this work would have been possible.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This project has also been made possible in part by grant 2021–000000 from the &lt;em&gt;&lt;a href=&quot;https://chanzuckerberg.com/&quot;&gt;&lt;em&gt;Chan Zuckerberg Initiative DAF&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, an advised fund of the Silicon Valley Community Foundation; and the &lt;em&gt;&lt;a href=&quot;https://sloan.org/&quot;&gt;&lt;em&gt;Alfred P. Sloan Foundation&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 02 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;*Authored by &lt;em&gt;&lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;&lt;em&gt;Kim Hartley&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;&lt;em&gt;Michelle Barker&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Investing in people: anticipating the future of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/investing-in-people-anticipating-the-fut-ec87efa8.660bh7id_nX0HL.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Photo credit: ADORE.Software&lt;/em&gt; at the International Research Software Funders WorkshopThis article was cross-posted on &lt;a href=&quot;https://adore.software/2023/10/investing-in-people-anticipating-the-future-of-research-software/&quot;&gt;Adore.software&lt;/a&gt; and reports on the progress of the Amsterdam Declaration on Funding Research Software Sustainability. To read more about this initiative and the initial workshop see &lt;a href=&quot;https://blog.esciencecenter.nl/the-future-of-research-software-602878378c5f&quot;&gt;this blogpost&lt;/a&gt; from November 2022.&lt;/p&gt;
&lt;p&gt;We are proud to report that the second &lt;a href=&quot;https://adore.software/international-research-software-funders-workshop/&quot;&gt;International Research Software Funders Workshop&lt;/a&gt;, co-hosted by the &lt;a href=&quot;https://alliancecan.ca/en&quot;&gt;Digital Research Alliance of Canada&lt;/a&gt; (the Alliance) and the &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;Research Software Alliance&lt;/a&gt; (ReSA) from 18–20 September was a great success. People are at the heart of research software sustainability and funders can lead the way by investing in the people who develop and maintain research software. That is why the workshop theme was “Investing in People: Anticipating the Future of Research Software”. The event aimed to set the future agenda for government, philanthropic, and industry funders to support sustainable research software and communities.&lt;/p&gt;
&lt;p&gt;In total, 50 representatives from more than 35 organisations — including funders and organisations that support research software from around the globe — attended the hybrid workshop held in Montreal, Canada, and virtually. During the three-day workshop, experts explored how research software funders can facilitate capacity building through funder practices; research software platforms, infrastructure, and communities; and new initiatives. Moreover, &lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt;Version 1.0 of the Amsterdam Declaration on Funding Research Software Sustainability (ADORE.software)&lt;/a&gt; was released and is now available for &lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;signing&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background**&lt;/h2&gt;
&lt;p&gt;This second iteration of the funders workshop built on the inaugural &lt;a href=&quot;https://future-of-research-software.org/&quot;&gt;International Funders Workshop: The Future of Research Software&lt;/a&gt;, co-hosted by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and ReSA in November 2022 in Amsterdam. During this first workshop, more than 40 funding organisations gathered to set the agenda for supporting sustainable research software and drafting of the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;ADORE.software&lt;/a&gt;. Following public consultation in 2023 and 19 organisational expressions of interest in becoming signatories,&lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt; Version 1.0 of the Declaration was released&lt;/a&gt; in advance of the Montreal workshop and is now available for &lt;a href=&quot;https://adore.software/get-involved/&quot;&gt;signing&lt;/a&gt;. ADORE.software is the first step towards formalising, on a global level, the basic principles and recommendations related to funding the sustainability of research software, including the people needed to achieve this goal.&lt;/p&gt;
&lt;p&gt;The first workshop marked a further step in the development of the research software community. Stakeholders have continued to build on this momentum through involvement in the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, convened by ReSA, and its funder-led working groups. The Alliance and ReSA, together with the workshop Steering Committee, organised the 2nd International Research Software Funders Workshop to continue this important work and facilitate global collaboration among funders and other key decision makers and influencers across the research software ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;2nd-international-research-software-funders-workshop&quot;&gt;&lt;strong&gt;2nd International Research Software Funders Workshop&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Pre-workshop — September 18&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The event commenced with a pre-workshop, including a session on &lt;a href=&quot;https://docs.google.com/presentation/d/1UP_UGOPxYi0R4UAE5PRpGWoJzrQ2FkVmCdDBILR6t2U/edit#slide=id.g241153165a8_0_0&quot;&gt;How to Explicitly Support Research Software as Part of Your Funding Program&lt;/a&gt;, delivered by ReSA, and a session on &lt;a href=&quot;https://zenodo.org/records/8356278&quot;&gt;CiteSoftware&lt;/a&gt;, led by a group of stakeholders aiming to drive the adoption of a common research software preservation and citation guidance resource for the research community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Investing in people: anticipating the future of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/investing-in-people-anticipating-the-fut-708c46e1.d9EqJ9Ja_274aPE.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Photo credit: ADORE.Software&lt;/em&gt; at the International Research Software Funders Workshop&lt;em&gt;&lt;strong&gt;Workshop Day 1 — September 19&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first day of the workshop included presentations that set the scene for participants to explore the crucial role funders play in supporting sustainable research software and communities.&lt;/p&gt;
&lt;p&gt;Carole Goble from the Software Sustainability Institute (SSI)/ELIXIR-UK/University of Manchester &lt;a href=&quot;https://docs.google.com/presentation/d/1dJrhjm7SAcLA96adZsBT-mFiJiwL3Fby/edit?usp=share_link&amp;#x26;ouid=116347134185833638908&amp;#x26;rtpof=true&amp;#x26;sd=true&quot;&gt;provided an overview&lt;/a&gt; of what research software is and why it is critical to the research endeavour. Carole highlighted that the people who make, use, and resource software are fundamental to research software sustainability. Moreover, research software needs resources and both direct (e.g., money) and indirect (e.g., community, reward, recognition, open-source support, etc.) forms of support for sustainability.&lt;/p&gt;
&lt;p&gt;Josh Greenberg from the Alfred P. Sloan Foundation delivered a &lt;a href=&quot;https://drive.google.com/file/d/1MPQ3LgO1jZdJIaF74oSz71XGye2ZjG64/view?usp=share_link&quot;&gt;keynote&lt;/a&gt; that provided a funder’s perspective. He asked attendees several pertinent questions: How much (and when) should we worry about technical debt? How much attention should we pay to user interface design in research software? Who should do which kinds of software? How central should “open source” be? How can we help institutions build capacity for research software development (and maintenance)?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Funders benefit from investing both before (community/need development) and after (ongoing maintenance and re-use) research software development.&lt;/li&gt;
&lt;li&gt;International collaboration and collective action are critical and valuable (e.g., building a multilateral funding initiative due to the global nature of research software).&lt;/li&gt;
&lt;li&gt;Funders should consider how to support and sustain Research Software Engineers (RSEs) but also incentivise researcher-developers to develop better software engineering practices.&lt;/li&gt;
&lt;li&gt;The research software community needs a set of high-level classes to measure the impact of research software, such as citations and mentions of software maturity, or combining mention analysis and dependency analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Malvika Sharan from The Alan Turing Institute and Open Life Science provided a research software community perspective in her &lt;a href=&quot;https://zenodo.org/records/8361334&quot;&gt;talk&lt;/a&gt; on Exploring ‘Do No Harm’ Principles in Open Research Communities. Malvika’s compelling keynote encouraged funders to become leaders in the research software ecosystem by incentivising and recognising all types of research roles; investing in capacity-building goals that focus on bridging scientific and economic divides; and applying community-oriented frameworks to extend the benefits of research to the broader community that ‘do no harm’, thereby ensuring open science practices enable equitable research and research outcomes.&lt;/p&gt;
&lt;p&gt;During the second breakout session, participants investigated capacity building through research software platforms, infrastructure, and communities. One group explored the role of &lt;a href=&quot;https://www.researchsoft.org/blog/2023-06/&quot;&gt;Open Source Program Offices&lt;/a&gt; (OSPOs), noting that OSPOs as centres of software could ultimately help research institutions understand their software investments. Another group considered why and how to support research software communities, highlighting the need for more evidence-led recommendations and exploring the possibility of reversing the funding mechanism to fund projects after the fact, as a function of how much they were used. In discussing research software in research assessment reform, participants noted that very few research software outputs are being assessed and indicators are fragmented and field-specific. Some solutions include sharing guidance on how software is being evaluated in a single place, sharing job profiles for RSEs, and sharing existing examples of research indicators that include software. Finally, another group highlighted that the environmental impact of research software is an emerging field, and persuading researchers to think about making their code efficient is a challenge.&lt;/p&gt;
&lt;p&gt;Workshop Day 2 — September 20***&lt;/p&gt;
&lt;p&gt;The final breakout session focused on building capacity through new initiatives. Participants explored how funders can implement &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;FAIR for Research Software&lt;/a&gt; (FAIR4RS) in funder policy. As some funders are developing guidance, questions arose about whether funders should create guidance individually or collectively and how the community should help funders do this. Through a discussion on how funders use persistent identifiers (PIDs), the need to engage publishers around software citation has become clear. And building on the theme of software citation, participants explored how the &lt;a href=&quot;https://research-software-directory.org/&quot;&gt;Research Software Directory&lt;/a&gt;, a free open-source platform, supports software citation.&lt;/p&gt;
&lt;p&gt;For the final &lt;a href=&quot;https://drive.google.com/file/d/1tzh5cSKX-3yZpqEqzMx7XtfEM9S6jtQY/view?usp=share_link&quot;&gt;keynote&lt;/a&gt;, Jean-Baptiste Poline from McGill University provided a researcher’s perspective on the impact of funders’ investments in research software. Jean-Baptiste presented the role of research software from multiple viewpoints, offering key takeaways such as the value of building a community of researchers through collaborative projects; the need for community-endorsed standards and practices that support open and FAIR (Findable, Accessible, Interoperable, and Reusable) scientific research (e.g., &lt;a href=&quot;https://www.incf.org/&quot;&gt;INCF Network&lt;/a&gt;) to maximise research value; the importance of addressing incentives first; and the idea of funding new technologies and large labs but giving precedence to well-governed communities more than centralised projects. He recommended creating the tools needed to change culture, improving training and open practices, developing community standards, and changing incentives.&lt;/p&gt;
&lt;p&gt;The workshop culminated with a Do-a-Thon, “a short collaboration where participants from different perspectives and skill sets work together on challenges, projects, or to learn something new” (&lt;a href=&quot;https://opencon-cascadia.github.io/doathon/&quot;&gt;OpenCon Cascadia&lt;/a&gt;). Prior to the workshop, participants were invited to submit do-able ideas. During the Do-a-Thon, attendees worked in small groups on the following topics: the &lt;a href=&quot;https://kumu.io/jstarr/ossci-moss&quot;&gt;Map of Open Source Science&lt;/a&gt;; linking software to community usage; and ten things applicants should do to make it easier to assess the impact of funding programs, to build on &lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9671312/&quot;&gt;Ten simple rules for funding scientific open source software&lt;/a&gt; by Carly Strasser et al. This dynamic collaboration resulted in participants considering next steps, crowdsourcing tips, and determining some practical and generalisable approaches to address the challenges explored.&lt;/p&gt;
&lt;h2 id=&quot;overall-outcomes-and-how-you-can-get-involved&quot;&gt;&lt;strong&gt;Overall outcomes and how you can get involved&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The workshop solidified the importance of international collaboration to support research software. There is a widening group of funders with awareness of the need to support research software and an understanding of how to do this. The &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; has been building momentum since its inception in early 2022; its dedicated funder-led working groups are expanding their reach by engaging with other stakeholders and organisations, such as the &lt;a href=&quot;https://globalresearchcouncil.org/&quot;&gt;Global Research Council&lt;/a&gt;. Moreover, the workshop highlighted areas where coordination by funders would be beneficial, for example, in supporting the &lt;a href=&quot;https://adore.software/declaration/&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt;. Participants also expressed an interest in exploring opportunities for forums, for example to engage publishers around software citations (along with the existing &lt;a href=&quot;https://www.researchsoft.org/taskforces/&quot;&gt;ReSA Task Force on Code Availability&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We thank all the participants for their engagement during the workshop sessions. We’re grateful to the workshop Steering Committee for their efforts in organising a successful hybrid workshop. A full report, written and edited collectively by workshop participants, is forthcoming.&lt;/p&gt;
&lt;p&gt;To stay up to date on ADORE.software, visit &lt;a href=&quot;http://www.adore.software/&quot;&gt;www.adore.software&lt;/a&gt;. If you want to show your support for the Declaration, you can become a &lt;a href=&quot;https://adore.software/sign/&quot;&gt;signatory&lt;/a&gt; (for funders) or &lt;a href=&quot;https://adore.software/support/&quot;&gt;supporter&lt;/a&gt; (for non-funders) and help share the &lt;a href=&quot;https://adore.software/2023/09/adore-software-is-ready-for-signing/&quot;&gt;news&lt;/a&gt;. To receive updates on news related to the Declaration and future activities, subscribe to the &lt;a href=&quot;https://landing.mailerlite.com/webforms/landing/i5e1h2&quot;&gt;ReSA newsletter&lt;/a&gt;. Funders are invited to join the (free) &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; by contacting ReSA at &lt;a href=&quot;mailto:info@researchsoft.org&quot;&gt;info@researchsoft.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re interested in learning more about ReSA and its activities, join our next &lt;a href=&quot;https://www.researchsoft.org/events/2022-06/&quot;&gt;Research Software Community Leaders Forum&lt;/a&gt; on 15 November at 20:00 UTC. ReSA’s Community Leaders Forum is open to all, and you can &lt;a href=&quot;https://landing.mailerlite.com/webforms/landing/o1n4v3&quot;&gt;sign up&lt;/a&gt; for calendar invites.&lt;/p&gt;
&lt;p&gt;We would like to express our sincere gratitude to our community, Founding Members, and Organisational Members — without whom none of this work would have been possible.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This project has also been made possible in part by grant 2021–000000 from the &lt;em&gt;&lt;a href=&quot;https://chanzuckerberg.com/&quot;&gt;&lt;em&gt;Chan Zuckerberg Initiative DAF&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, an advised fund of the Silicon Valley Community Foundation; and the &lt;em&gt;&lt;a href=&quot;https://sloan.org/&quot;&gt;&lt;em&gt;Alfred P. Sloan Foundation&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/investing-in-people-anticipating-the-fut-708c46e1.d9EqJ9Ja.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>The Orange3 data mining platform for the Social Sciences and Humanities</title><link>https://blog.esciencecenter.nl/posts/2023-11-02---the-orange3-data-mining-platform-for-the-social-sciences-and</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-11-02---the-orange3-data-mining-platform-for-the-social-sciences-and</guid><description>&lt;h1 id=&quot;the-orange3-data-mining-platform-for-the-social-sciences-and-humanities&quot;&gt;&lt;em&gt;The Orange3 data mining platform for the Social Sciences and Humanities&lt;/em&gt;&lt;/h1&gt;
&lt;h2 id=&quot;why-arent-more-ssh-researchers-using-and-extending-the-platform&quot;&gt;Why aren’t more SSH researchers using and extending the platform?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://orangedatamining.com/&quot;&gt;Orange&lt;/a&gt; is an open-source &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;-based &lt;a href=&quot;https://www.britannica.com/technology/data-structure&quot;&gt;data mining&lt;/a&gt; application with a graphical user interface (GUI). It allows people with no knowledge of programming to apply Machine Learning as well as advanced data processing, analysis, and visualization using a point-and-click, drag-and-drop interface. Those who have seen &lt;a href=&quot;https://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt; will be familiar with this mode of interaction, although Orange is more advanced and is used for data mining, rather than educational programming. The following screenshot shows what a typical Orange &lt;a href=&quot;https://orangedatamining.com/workflows/&quot;&gt;workflow&lt;/a&gt; looks like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;396&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-9fc38229.CnwyeOCH_ZuG0x0.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of an example data mining workflow in Orange3The three small circles labeled ‘File’, ‘Data Table’, and ‘Scatter Plot’ in the image above, are called Orange &lt;a href=&quot;https://docs.biolab.si/orange/2/widgets/rst/index.html&quot;&gt;widgets&lt;/a&gt;. They are the basic building blocks of a data analysis workflow (or pipeline) in Orange. Each widget is a software unit that performs some sort of data processing, analysis, or visualization and potentially has a set of inputs and outputs. You can connect the outputs of some widgets to the inputs of others to create a chain of processing and analysis operations. A great feature of Orange is its extensibility. There are loads of custom plugins for Orange (called &lt;em&gt;add-ons&lt;/em&gt;) developed by researchers and the Orange user community. Add-ons usually comprise multiple widgets. Two mature and extensively used Orange add-ons are &lt;a href=&quot;https://orange3-text.readthedocs.io/en/latest/&quot;&gt;Orange-Text&lt;/a&gt; and &lt;a href=&quot;https://orange3-network.readthedocs.io/en/latest/&quot;&gt;Network&lt;/a&gt; which are used for &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_theory&quot;&gt;network analysis &lt;/a&gt;respectively.&lt;/p&gt;
&lt;p&gt;Story Navigator: a custom Orange add-on I am developing**&lt;/p&gt;
&lt;p&gt;I am currently in the process of developing an add-on as part of a project with researchers at the &lt;a href=&quot;https://www.utwente.nl/&quot;&gt;University of Twente&lt;/a&gt; in the Netherlands. The add-on is called the &lt;a href=&quot;https://github.com/navigating-stories/orange-story-navigator&quot;&gt;Story Navigator&lt;/a&gt;. The aim of the Story Navigator is to enable computer-aided analysis of written stories for students and researchers who study &lt;a href=&quot;https://en.wikipedia.org/wiki/Narrative_psychology&quot;&gt;narrative psychology&lt;/a&gt;. The add-on has several widgets to analyse different aspects of a story. It uses a combination of &lt;a href=&quot;https://encyclopediaofmath.org/wiki/Natural_language_processing&quot;&gt;natural language processing&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt;, and general data analysis techniques to implement theories in narrative psychology, such as &lt;a href=&quot;https://natureofwriting.com/courses/introduction-to-rhetoric/lessons/burkes-pentad/&quot;&gt;Burke’s pentad&lt;/a&gt;. Here’s a screen:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;348&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-4f3fee29.BjVBybBx_ZxVMsq.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of the Story Navigator add-on (not yet released) for Orange3.The add-on works by first importing textual stories into the workflow using the existing &lt;a href=&quot;https://orangedatamining.com/widget-catalog/text-mining/importdocuments/&quot;&gt;“Import Documents”&lt;/a&gt; widget from the Orange-Text add-on. Thereafter the researcher can choose a widget from the add-on for analysing some aspects of the imported stories. The actor analysis widget, for example, highlights potential characters in the stories; shows which kinds of actions (verbs) the characters are associated with; and calculates different measures for how central specific characters are to the stories.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;422&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-7e54b23a.GDy6a0Pm_ZtLkmE.webp&quot; srcset=&quot;&quot;&gt;
Quantitative story analysis widgets from the Story Navigator add-on for Orange3.While it did take some time to develop the widgets for this add-on, what surprised me is that it took me only about two hours, from scratch, with no prior knowledge of Orange, to develop my first widget that showed up in the Orange3 interface when I started it up. Granted, the widget did not do anything except display. But the return on my two-hour investment was that I could now free up my creativity to develop whatever functionality I wanted in the widget, without having to create my own GUI. In doing so, I got to take advantage of a myriad of benefits including being able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make my add-on available for anyone to use regardless of their programming knowledge&lt;/li&gt;
&lt;li&gt;Receive development and usage feedback from an existing Orange community about my add-on (without having to further promote the add-on or build another community myself from scratch)&lt;/li&gt;
&lt;li&gt;Demo my plugin to anyone, thanks to the GUI&lt;/li&gt;
&lt;li&gt;Share data analyses made with my add-on with other Orange users — enabling reproducibility (currently &lt;a href=&quot;https://www.nature.com/articles/d41586-019-00067-3&quot;&gt;undergoing a crisis&lt;/a&gt; in science)&lt;/li&gt;
&lt;li&gt;Forget about writing installation instructions — they’re already &lt;a href=&quot;https://orangedatamining.com/blog/2012/11/30/the-easy-way-to-install-add-ons/&quot;&gt;here&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite what some readers might think at this point, I am not an Orange evangelist. In fact, I am not swooning over the capabilities and potential of Orange specifically. Orange does have competing platforms that try to do similar things such as &lt;a href=&quot;https://www.knime.com/&quot;&gt;KNIME&lt;/a&gt; and &lt;a href=&quot;https://www.cs.waikato.ac.nz/ml/weka/&quot;&gt;WEKA&lt;/a&gt; which are both &lt;a href=&quot;https://www.java.com/en/&quot;&gt;Java&lt;/a&gt;-based and therefore inherit some concerns due to &lt;a href=&quot;https://www.tiobe.com/tiobe-index/&quot;&gt;Java’s declining popularity&lt;/a&gt;. Orange itself also has some clear disadvantages, not least of which are the &lt;a href=&quot;https://orangedatamining.com/blog/2012/01/03/parallel-orange/&quot;&gt;scalability issues&lt;/a&gt; and the &lt;a href=&quot;https://orange3-example-addon.readthedocs.io/en/latest/&quot;&gt;add-on development documentation&lt;/a&gt; (the latter is not very accessible for less experienced developers).&lt;/p&gt;
&lt;p&gt;But the point I am trying to make is that I am mostly just inspired by the philosophy behind platforms like these: people coming together to develop and share an extensible “workbench-style” software platform with a user-friendly interface. When I refer to software I don’t mean software that has a highly niche purpose, but software that aims to be an ever-evolving toolbox with the potential to address a multitude of research problems. Where your own creativity is the only limit in terms of contributing to it. Where the knowledge barriers to be able to contribute to it are super low, and where there are no qualifying criteria for those who can experience and benefit from the contributions.&lt;/p&gt;
&lt;p&gt;Orange was developed at the &lt;a href=&quot;https://fri.uni-lj.si/en/laboratory/biolab&quot;&gt;Laboratory for Bioinformatics&lt;/a&gt; at the University of Ljubljana. It makes sense then that most of its user base uses it for data mining in &lt;a href=&quot;https://www.britannica.com/science/bioinformatics&quot;&gt;bioinformatics&lt;/a&gt; (see for instance &lt;a href=&quot;https://www.mdpi.com/2076-3417/11/5/2218&quot;&gt;this study&lt;/a&gt; using Orange for early diagnosis of diabetes). But Orange itself is not at all designed to be domain-specific. Its add-ons and widgets are designed for domain-agnostic data mining (&lt;a href=&quot;https://www.mdpi.com/2076-3417/10/11/3894&quot;&gt;here’s a study&lt;/a&gt; using Orange to predict student performance in higher education). This begs the question, why aren’t more researchers in the Social Sciences and Humanities using it, extending it, or building similar platforms?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bethesda.net/dashboard&quot;&gt;Bethesda Softworks&lt;/a&gt; is a US-based video game development company that is famous for its many franchises, one of which is “&lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;Elder Scrolls&lt;/a&gt;”. The games in this franchise are “&lt;a href=&quot;https://en.wikipedia.org/wiki/Role-playing_game&quot;&gt;RPGs&lt;/a&gt;” that put the player in control of a character from a fictional fantasy world with the goal to… wait for it… save the world from destruction (if you’re new to the term RPGs imagine a video game based on &lt;a href=&quot;https://www.hbo.com/game-of-thrones&quot;&gt;Game of Thrones&lt;/a&gt; and you’ll get the gist). In 2002, Bethesda released its third installment of Elder Scrolls, called “&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Elder_Scrolls_III:_Morrowind&quot;&gt;Morrowind&lt;/a&gt;”. The super interesting part is that they also released software called the &lt;a href=&quot;https://cs.elderscrolls.com/index.php?title=Main_Page&quot;&gt;Elder Scrolls Construction Set&lt;/a&gt; alongside the game. This software allowed players to make customizations to their own copy of the game. They could do things such as create new clothing, buildings, and other items; create their own character voices; make new quests, and customize the color of the sky. These modifications (mods *as they are now commonly referred to) vary in terms of how much software literacy is required in order to build them, but many of them require no more knowledge than being able to install a program and click a few buttons.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;367&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-8e688f2b.2Iv0nc2J_1lSNPy.webp&quot; srcset=&quot;&quot;&gt;
Fancy introducing Spiderman-suited creatures crawling around a medieval town into your video-gaming experience? Well, someone &lt;a href=&quot;https://www.nexusmods.com/skyrim/mods/4308&quot;&gt;has already created a mod for this&lt;/a&gt; in &lt;a href=&quot;https://elderscrolls.bethesda.net/en/skyrim&quot;&gt;Skyrim&lt;/a&gt;.Twenty years later, and Bethesda has become known and celebrated for giving its customers the freedom to customize their gaming experience. &lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; is one of the prominent hubs for hosting large collections of player-created mods for games by Bethesda and other major video game companies. I quote some jaw-dropping statistics from this site here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“We host 477,145 mods for 2,342 games from 118,005 authors serving 41,902,274 members with 8,184,840,124 downloads to date.”&lt;/p&gt;
&lt;p&gt;In academia, terms like “outputs”, “impact”, “community building” and “community engagement” are often bandied about as performance goals and metrics for work. However, despite their purported importance, these terms are hard to define and measure. But when I look at those numbers, I feel like we don’t need unambiguous definitions for those terms in order to verify that the mod concept ticks all those boxes and then some.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;254&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-caf3ed3a.-Gb9CStu_M5Dvq.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; demonstrates that the mod concept is a winner.“Okay Kody, what does this all have to do with Orange?”, you may ask. Well, in some ways there are parallels in this story to the concept of Orange as a software platform.&lt;/p&gt;
&lt;p&gt;First, there is a &lt;em&gt;product that many people enjoy&lt;/em&gt; (or find useful). In Bethesda’s case, it is the “vanilla” Elder Scrolls games. In Orange’s case, it is a data mining platform which is a generic tool that is useful regardless of the research domain and data. The GUI aspect of Orange also opens it up to a much larger user base (not just a small group of researchers with development experience working in a niche field).&lt;/p&gt;
&lt;p&gt;Second, there is the *enabling of customization. *In Bethesda’s case, it is the provision of customization software such as the &lt;a href=&quot;https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/&quot;&gt;Skyrim Creation Kit&lt;/a&gt;; in the case of Orange, it is the release of the code under an open-source license with reusable example code and plugin-writing tutorials.&lt;/p&gt;
&lt;p&gt;Thirdly, and what I find to be the most critical, is *making it easy to customize. *In Bethesda’s case, they have made user-friendly software that does not require extremely specialized skills to use. Almost anyone can create a mod. In Orange’s case, you still need to know how to program to develop add-ons. But you don’t need advanced knowledge of the GUI frameworks that Orange uses — &lt;a href=&quot;https://en.wikipedia.org/wiki/Qt_(software)&quot;&gt;Qt&lt;/a&gt; and &lt;a href=&quot;https://wiki.python.org/moin/PyQt&quot;&gt;PyQt&lt;/a&gt;. In other words, if you know how to create any kind of computational script or software in Python, you can easily create an Orange widget to “house” or “wrap” its functionality. Furthermore, others, regardless of their technical nous, will be able to use it and “chain” your widget with other software in an Orange workflow.&lt;/p&gt;
&lt;p&gt;What I have experienced and want to emphasize, is that plugging your software into existing platforms like Orange (especially ones that have a nice GUI) can increase its visibility and usage, over publishing it solely in a code repository. Decently designed GUIs help users to more quickly understand what your software does which goes a long way to maximizing its value. Platforms like Orange provide a mechanism by which developers can take advantage of these GUI benefits “for free” (well, not really for free, but with &lt;em&gt;much&lt;/em&gt; less time investment than building and designing GUIs from scratch). It frees them up to use their creativity to solve research problems through widget development; it exposes their software to a much wider audience; and it allows users to interact with their software in a more intuitive way.&lt;/p&gt;
&lt;p&gt;In short, platforms like Orange can be extremely useful both for researchers who want to quickly apply computational analyses in the SSH fields (without writing code) and for developers who want to increase the usability, visibility, and sustainability of their software. While it does, to some extent, tie the success of your software to the success of Orange, you are not “putting all your eggs in one basket”. Due to the modularity and already-in-place Python package structure of Orange add-ons and widgets, you can very easily strip the GUI out of your code and release your work as a stand-alone package, or migrate it to another platform.&lt;/p&gt;
&lt;p&gt;If you are interested, my colleague &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;Ji Qi&lt;/a&gt; has written a &lt;a href=&quot;https://medium.com/escience-center/how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chatbot-adventure-with-huggingchat-ded982ac0ef4&quot;&gt;post&lt;/a&gt; about how to get started with Orange add-on development — be sure to check it out!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take home messages&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Orange is an open-source extensible data mining platform that is usable by people with little to no technical experience. If you are a researcher in SSH consider using it for your research. If it doesn’t have a feature you need, &lt;a href=&quot;https://github.com/biolab/orange3/issues&quot;&gt;ask the developers if they can add it as a default feature to Orange&lt;/a&gt;. If they can’t add it, and if you or a colleague has Python experience, consider &lt;a href=&quot;http://jiblogpost&quot;&gt;creating a custom add-on&lt;/a&gt;. It is surprisingly quick and easy to create one if you know a bit of Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1903.06039.pdf&quot;&gt;Research software sustainability is a challenge&lt;/a&gt;. Building and maintaining communities around the development of research software is hard. Don’t let your software become JAG (&lt;strong&gt;J&lt;/strong&gt;ust-&lt;strong&gt;A&lt;/strong&gt;nother-&lt;strong&gt;G&lt;/strong&gt;ithub repo). Take inspiration for how to avoid this from platforms like Orange. This does not mean that you need to create a graphical user interface for your software. It means: &lt;em&gt;find a home for your software&lt;/em&gt; or &lt;em&gt;find an existing toolbox in which to integrate your software, before creating your own toolbox&lt;/em&gt;. Integrating into existing platforms or packages will probably increase its usage and visibility over publishing as a stand-alone item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #1:&lt;/strong&gt; From the start, consider building software that solves &lt;em&gt;generic&lt;/em&gt; problems in your field. i.e., problems that are shared by others in the field as well, rather than for highly specialized use cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #2:&lt;/strong&gt; Make your software easy to use by as many &lt;em&gt;types&lt;/em&gt; of people as possible. Not just for experienced developers. Also, ensure that someone can rapidly understand what your software does.&lt;/li&gt;
&lt;li&gt;**Inspiration point #3: **Make it easy for as many people as possible to customize and extend your software.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Thu, 02 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;the-orange3-data-mining-platform-for-the-social-sciences-and-humanities&quot;&gt;&lt;em&gt;The Orange3 data mining platform for the Social Sciences and Humanities&lt;/em&gt;&lt;/h1&gt;
&lt;h2 id=&quot;why-arent-more-ssh-researchers-using-and-extending-the-platform&quot;&gt;Why aren’t more SSH researchers using and extending the platform?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://orangedatamining.com/&quot;&gt;Orange&lt;/a&gt; is an open-source &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;-based &lt;a href=&quot;https://www.britannica.com/technology/data-structure&quot;&gt;data mining&lt;/a&gt; application with a graphical user interface (GUI). It allows people with no knowledge of programming to apply Machine Learning as well as advanced data processing, analysis, and visualization using a point-and-click, drag-and-drop interface. Those who have seen &lt;a href=&quot;https://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt; will be familiar with this mode of interaction, although Orange is more advanced and is used for data mining, rather than educational programming. The following screenshot shows what a typical Orange &lt;a href=&quot;https://orangedatamining.com/workflows/&quot;&gt;workflow&lt;/a&gt; looks like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;396&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-9fc38229.CnwyeOCH_ZuG0x0.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of an example data mining workflow in Orange3The three small circles labeled ‘File’, ‘Data Table’, and ‘Scatter Plot’ in the image above, are called Orange &lt;a href=&quot;https://docs.biolab.si/orange/2/widgets/rst/index.html&quot;&gt;widgets&lt;/a&gt;. They are the basic building blocks of a data analysis workflow (or pipeline) in Orange. Each widget is a software unit that performs some sort of data processing, analysis, or visualization and potentially has a set of inputs and outputs. You can connect the outputs of some widgets to the inputs of others to create a chain of processing and analysis operations. A great feature of Orange is its extensibility. There are loads of custom plugins for Orange (called &lt;em&gt;add-ons&lt;/em&gt;) developed by researchers and the Orange user community. Add-ons usually comprise multiple widgets. Two mature and extensively used Orange add-ons are &lt;a href=&quot;https://orange3-text.readthedocs.io/en/latest/&quot;&gt;Orange-Text&lt;/a&gt; and &lt;a href=&quot;https://orange3-network.readthedocs.io/en/latest/&quot;&gt;Network&lt;/a&gt; which are used for &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_theory&quot;&gt;network analysis &lt;/a&gt;respectively.&lt;/p&gt;
&lt;p&gt;Story Navigator: a custom Orange add-on I am developing**&lt;/p&gt;
&lt;p&gt;I am currently in the process of developing an add-on as part of a project with researchers at the &lt;a href=&quot;https://www.utwente.nl/&quot;&gt;University of Twente&lt;/a&gt; in the Netherlands. The add-on is called the &lt;a href=&quot;https://github.com/navigating-stories/orange-story-navigator&quot;&gt;Story Navigator&lt;/a&gt;. The aim of the Story Navigator is to enable computer-aided analysis of written stories for students and researchers who study &lt;a href=&quot;https://en.wikipedia.org/wiki/Narrative_psychology&quot;&gt;narrative psychology&lt;/a&gt;. The add-on has several widgets to analyse different aspects of a story. It uses a combination of &lt;a href=&quot;https://encyclopediaofmath.org/wiki/Natural_language_processing&quot;&gt;natural language processing&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt;, and general data analysis techniques to implement theories in narrative psychology, such as &lt;a href=&quot;https://natureofwriting.com/courses/introduction-to-rhetoric/lessons/burkes-pentad/&quot;&gt;Burke’s pentad&lt;/a&gt;. Here’s a screen:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;348&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-4f3fee29.BjVBybBx_ZxVMsq.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of the Story Navigator add-on (not yet released) for Orange3.The add-on works by first importing textual stories into the workflow using the existing &lt;a href=&quot;https://orangedatamining.com/widget-catalog/text-mining/importdocuments/&quot;&gt;“Import Documents”&lt;/a&gt; widget from the Orange-Text add-on. Thereafter the researcher can choose a widget from the add-on for analysing some aspects of the imported stories. The actor analysis widget, for example, highlights potential characters in the stories; shows which kinds of actions (verbs) the characters are associated with; and calculates different measures for how central specific characters are to the stories.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;422&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-7e54b23a.GDy6a0Pm_ZtLkmE.webp&quot; srcset=&quot;&quot;&gt;
Quantitative story analysis widgets from the Story Navigator add-on for Orange3.While it did take some time to develop the widgets for this add-on, what surprised me is that it took me only about two hours, from scratch, with no prior knowledge of Orange, to develop my first widget that showed up in the Orange3 interface when I started it up. Granted, the widget did not do anything except display. But the return on my two-hour investment was that I could now free up my creativity to develop whatever functionality I wanted in the widget, without having to create my own GUI. In doing so, I got to take advantage of a myriad of benefits including being able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make my add-on available for anyone to use regardless of their programming knowledge&lt;/li&gt;
&lt;li&gt;Receive development and usage feedback from an existing Orange community about my add-on (without having to further promote the add-on or build another community myself from scratch)&lt;/li&gt;
&lt;li&gt;Demo my plugin to anyone, thanks to the GUI&lt;/li&gt;
&lt;li&gt;Share data analyses made with my add-on with other Orange users — enabling reproducibility (currently &lt;a href=&quot;https://www.nature.com/articles/d41586-019-00067-3&quot;&gt;undergoing a crisis&lt;/a&gt; in science)&lt;/li&gt;
&lt;li&gt;Forget about writing installation instructions — they’re already &lt;a href=&quot;https://orangedatamining.com/blog/2012/11/30/the-easy-way-to-install-add-ons/&quot;&gt;here&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite what some readers might think at this point, I am not an Orange evangelist. In fact, I am not swooning over the capabilities and potential of Orange specifically. Orange does have competing platforms that try to do similar things such as &lt;a href=&quot;https://www.knime.com/&quot;&gt;KNIME&lt;/a&gt; and &lt;a href=&quot;https://www.cs.waikato.ac.nz/ml/weka/&quot;&gt;WEKA&lt;/a&gt; which are both &lt;a href=&quot;https://www.java.com/en/&quot;&gt;Java&lt;/a&gt;-based and therefore inherit some concerns due to &lt;a href=&quot;https://www.tiobe.com/tiobe-index/&quot;&gt;Java’s declining popularity&lt;/a&gt;. Orange itself also has some clear disadvantages, not least of which are the &lt;a href=&quot;https://orangedatamining.com/blog/2012/01/03/parallel-orange/&quot;&gt;scalability issues&lt;/a&gt; and the &lt;a href=&quot;https://orange3-example-addon.readthedocs.io/en/latest/&quot;&gt;add-on development documentation&lt;/a&gt; (the latter is not very accessible for less experienced developers).&lt;/p&gt;
&lt;p&gt;But the point I am trying to make is that I am mostly just inspired by the philosophy behind platforms like these: people coming together to develop and share an extensible “workbench-style” software platform with a user-friendly interface. When I refer to software I don’t mean software that has a highly niche purpose, but software that aims to be an ever-evolving toolbox with the potential to address a multitude of research problems. Where your own creativity is the only limit in terms of contributing to it. Where the knowledge barriers to be able to contribute to it are super low, and where there are no qualifying criteria for those who can experience and benefit from the contributions.&lt;/p&gt;
&lt;p&gt;Orange was developed at the &lt;a href=&quot;https://fri.uni-lj.si/en/laboratory/biolab&quot;&gt;Laboratory for Bioinformatics&lt;/a&gt; at the University of Ljubljana. It makes sense then that most of its user base uses it for data mining in &lt;a href=&quot;https://www.britannica.com/science/bioinformatics&quot;&gt;bioinformatics&lt;/a&gt; (see for instance &lt;a href=&quot;https://www.mdpi.com/2076-3417/11/5/2218&quot;&gt;this study&lt;/a&gt; using Orange for early diagnosis of diabetes). But Orange itself is not at all designed to be domain-specific. Its add-ons and widgets are designed for domain-agnostic data mining (&lt;a href=&quot;https://www.mdpi.com/2076-3417/10/11/3894&quot;&gt;here’s a study&lt;/a&gt; using Orange to predict student performance in higher education). This begs the question, why aren’t more researchers in the Social Sciences and Humanities using it, extending it, or building similar platforms?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bethesda.net/dashboard&quot;&gt;Bethesda Softworks&lt;/a&gt; is a US-based video game development company that is famous for its many franchises, one of which is “&lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;Elder Scrolls&lt;/a&gt;”. The games in this franchise are “&lt;a href=&quot;https://en.wikipedia.org/wiki/Role-playing_game&quot;&gt;RPGs&lt;/a&gt;” that put the player in control of a character from a fictional fantasy world with the goal to… wait for it… save the world from destruction (if you’re new to the term RPGs imagine a video game based on &lt;a href=&quot;https://www.hbo.com/game-of-thrones&quot;&gt;Game of Thrones&lt;/a&gt; and you’ll get the gist). In 2002, Bethesda released its third installment of Elder Scrolls, called “&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Elder_Scrolls_III:_Morrowind&quot;&gt;Morrowind&lt;/a&gt;”. The super interesting part is that they also released software called the &lt;a href=&quot;https://cs.elderscrolls.com/index.php?title=Main_Page&quot;&gt;Elder Scrolls Construction Set&lt;/a&gt; alongside the game. This software allowed players to make customizations to their own copy of the game. They could do things such as create new clothing, buildings, and other items; create their own character voices; make new quests, and customize the color of the sky. These modifications (mods *as they are now commonly referred to) vary in terms of how much software literacy is required in order to build them, but many of them require no more knowledge than being able to install a program and click a few buttons.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;367&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-8e688f2b.2Iv0nc2J_1lSNPy.webp&quot; srcset=&quot;&quot;&gt;
Fancy introducing Spiderman-suited creatures crawling around a medieval town into your video-gaming experience? Well, someone &lt;a href=&quot;https://www.nexusmods.com/skyrim/mods/4308&quot;&gt;has already created a mod for this&lt;/a&gt; in &lt;a href=&quot;https://elderscrolls.bethesda.net/en/skyrim&quot;&gt;Skyrim&lt;/a&gt;.Twenty years later, and Bethesda has become known and celebrated for giving its customers the freedom to customize their gaming experience. &lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; is one of the prominent hubs for hosting large collections of player-created mods for games by Bethesda and other major video game companies. I quote some jaw-dropping statistics from this site here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;“We host 477,145 mods for 2,342 games from 118,005 authors serving 41,902,274 members with 8,184,840,124 downloads to date.”&lt;/p&gt;
&lt;p&gt;In academia, terms like “outputs”, “impact”, “community building” and “community engagement” are often bandied about as performance goals and metrics for work. However, despite their purported importance, these terms are hard to define and measure. But when I look at those numbers, I feel like we don’t need unambiguous definitions for those terms in order to verify that the mod concept ticks all those boxes and then some.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Orange3 data mining platform for the Social Sciences and Humanities&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;254&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-caf3ed3a.-Gb9CStu_M5Dvq.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; demonstrates that the mod concept is a winner.“Okay Kody, what does this all have to do with Orange?”, you may ask. Well, in some ways there are parallels in this story to the concept of Orange as a software platform.&lt;/p&gt;
&lt;p&gt;First, there is a &lt;em&gt;product that many people enjoy&lt;/em&gt; (or find useful). In Bethesda’s case, it is the “vanilla” Elder Scrolls games. In Orange’s case, it is a data mining platform which is a generic tool that is useful regardless of the research domain and data. The GUI aspect of Orange also opens it up to a much larger user base (not just a small group of researchers with development experience working in a niche field).&lt;/p&gt;
&lt;p&gt;Second, there is the *enabling of customization. *In Bethesda’s case, it is the provision of customization software such as the &lt;a href=&quot;https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/&quot;&gt;Skyrim Creation Kit&lt;/a&gt;; in the case of Orange, it is the release of the code under an open-source license with reusable example code and plugin-writing tutorials.&lt;/p&gt;
&lt;p&gt;Thirdly, and what I find to be the most critical, is *making it easy to customize. *In Bethesda’s case, they have made user-friendly software that does not require extremely specialized skills to use. Almost anyone can create a mod. In Orange’s case, you still need to know how to program to develop add-ons. But you don’t need advanced knowledge of the GUI frameworks that Orange uses — &lt;a href=&quot;https://en.wikipedia.org/wiki/Qt_(software)&quot;&gt;Qt&lt;/a&gt; and &lt;a href=&quot;https://wiki.python.org/moin/PyQt&quot;&gt;PyQt&lt;/a&gt;. In other words, if you know how to create any kind of computational script or software in Python, you can easily create an Orange widget to “house” or “wrap” its functionality. Furthermore, others, regardless of their technical nous, will be able to use it and “chain” your widget with other software in an Orange workflow.&lt;/p&gt;
&lt;p&gt;What I have experienced and want to emphasize, is that plugging your software into existing platforms like Orange (especially ones that have a nice GUI) can increase its visibility and usage, over publishing it solely in a code repository. Decently designed GUIs help users to more quickly understand what your software does which goes a long way to maximizing its value. Platforms like Orange provide a mechanism by which developers can take advantage of these GUI benefits “for free” (well, not really for free, but with &lt;em&gt;much&lt;/em&gt; less time investment than building and designing GUIs from scratch). It frees them up to use their creativity to solve research problems through widget development; it exposes their software to a much wider audience; and it allows users to interact with their software in a more intuitive way.&lt;/p&gt;
&lt;p&gt;In short, platforms like Orange can be extremely useful both for researchers who want to quickly apply computational analyses in the SSH fields (without writing code) and for developers who want to increase the usability, visibility, and sustainability of their software. While it does, to some extent, tie the success of your software to the success of Orange, you are not “putting all your eggs in one basket”. Due to the modularity and already-in-place Python package structure of Orange add-ons and widgets, you can very easily strip the GUI out of your code and release your work as a stand-alone package, or migrate it to another platform.&lt;/p&gt;
&lt;p&gt;If you are interested, my colleague &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;Ji Qi&lt;/a&gt; has written a &lt;a href=&quot;https://medium.com/escience-center/how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chatbot-adventure-with-huggingchat-ded982ac0ef4&quot;&gt;post&lt;/a&gt; about how to get started with Orange add-on development — be sure to check it out!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take home messages&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Orange is an open-source extensible data mining platform that is usable by people with little to no technical experience. If you are a researcher in SSH consider using it for your research. If it doesn’t have a feature you need, &lt;a href=&quot;https://github.com/biolab/orange3/issues&quot;&gt;ask the developers if they can add it as a default feature to Orange&lt;/a&gt;. If they can’t add it, and if you or a colleague has Python experience, consider &lt;a href=&quot;http://jiblogpost&quot;&gt;creating a custom add-on&lt;/a&gt;. It is surprisingly quick and easy to create one if you know a bit of Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1903.06039.pdf&quot;&gt;Research software sustainability is a challenge&lt;/a&gt;. Building and maintaining communities around the development of research software is hard. Don’t let your software become JAG (&lt;strong&gt;J&lt;/strong&gt;ust-&lt;strong&gt;A&lt;/strong&gt;nother-&lt;strong&gt;G&lt;/strong&gt;ithub repo). Take inspiration for how to avoid this from platforms like Orange. This does not mean that you need to create a graphical user interface for your software. It means: &lt;em&gt;find a home for your software&lt;/em&gt; or &lt;em&gt;find an existing toolbox in which to integrate your software, before creating your own toolbox&lt;/em&gt;. Integrating into existing platforms or packages will probably increase its usage and visibility over publishing as a stand-alone item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #1:&lt;/strong&gt; From the start, consider building software that solves &lt;em&gt;generic&lt;/em&gt; problems in your field. i.e., problems that are shared by others in the field as well, rather than for highly specialized use cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #2:&lt;/strong&gt; Make your software easy to use by as many &lt;em&gt;types&lt;/em&gt; of people as possible. Not just for experienced developers. Also, ensure that someone can rapidly understand what your software does.&lt;/li&gt;
&lt;li&gt;**Inspiration point #3: **Make it easy for as many people as possible to customize and extend your software.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-orange3-data-mining-platform-for-the-9fc38229.CnwyeOCH.png" medium="image"/><author>Kody Moodley</author></item><item><title>Open Science Festival: What infrastructures do we need to preserve research software?</title><link>https://blog.esciencecenter.nl/posts/2023-10-26---open-science-festival-what-infrastructures-do-we-need-to-pre</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-10-26---open-science-festival-what-infrastructures-do-we-need-to-pre</guid><description>&lt;p&gt;*written by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-luisa-orozco/&quot;&gt;&lt;em&gt;Luisa Orozco&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;http://www.linkedin.com/in/danielagawehns/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and *&lt;a href=&quot;https://medium.com/@c.martinez&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Open Science Festival: What infrastructures do we need to preserve research software?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/open-science-festival-what-infrastructur-9069ad56.Bg1b7T0q_biUgK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this year, the 2023 edition of the Dutch &lt;a href=&quot;https://opensciencefestival.nl/&quot;&gt;Open Science Festival&lt;/a&gt; was held. We (the eScience Center and Leiden University) organised the session “National infrastructure for sustainable research software”. In this session we discussed the benefits and limits of available software preservation platforms (or infrastructures) and if national infrastructures for research software development are feasible and desirable.&lt;/p&gt;
&lt;p&gt;Research software increasingly forms a critically important element of many research projects across a wide array of domains. To achieve truly sustainable and reproducible research, not only the software itself but also the computational environment it depends on needs to be preserved. Different types of infrastructure are required to support these preservation activities.&lt;/p&gt;
&lt;p&gt;One user-friendly example of a friendly way to package computational environmetns are Docker containers. These containers can be archived on privately owned platforms like Docker Hub and GitHub or on publicly funded archives such as Zenodo. Such platforms become part of the infrastructure needed to rerun and reuse research code associated with research results.&lt;/p&gt;
&lt;h2 id=&quot;panel-composition-and-pitches&quot;&gt;Panel composition and pitches&lt;/h2&gt;
&lt;p&gt;The session was organised as a series of panel pitches, followed by a group discussion. The panel shared their insights and experiences, as we explored current issues with container storage platforms and related infrastructure and the role the Dutch research landscape can take as a provider of independent and government funded infrastructure for sustainable research software.&lt;/p&gt;
&lt;p&gt;The panel was composed of national and international experts from different domains and backgrounds to contribute (researcher, software engineer, administrator of research servers, science funders). Panellists were John Swinbank from ASTRON, Niki van Stein from LIACS, Leiden University, Matthijs Moed from SURF and Jeremy Cohen from Imperial College London.&lt;/p&gt;
&lt;p&gt;Panellists were asked to prepare a short pitch with their view on the following question:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Which infrastructures (version control, containers publication, Zenodo, testing infrastructure, any other?) are most important to the work your organisation does?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a summary of the pitches from each panellist:&lt;/p&gt;
&lt;h2 id=&quot;john-swinbank-astron&quot;&gt;John Swinbank, ASTRON&lt;/h2&gt;
&lt;p&gt;ASTRON works on a regime of big data. We are already working with tens of petabytes of data from telescopes like LOFAR, and that will increase to the order of 1 Exabyte per year when SKA (Ed.: a &lt;a href=&quot;https://www.astron.nl/category/telescopes/ska/&quot;&gt;new radio telescope&lt;/a&gt;) comes online later this decade. Our task is to make sure this volume of data is in a format that is usable for astronomers. The astronomical community has been working towards full reproducibility, but it is not yet completely embedded in the culture. In terms of infrastructure, we have a local GitLab instance for code sharing;using containers and publishing on Zenodo is not yet universally accepted.&lt;/p&gt;
&lt;h2 id=&quot;niki-van-stein-liacs-leiden-university&quot;&gt;Niki van Stein, LIACS, Leiden University&lt;/h2&gt;
&lt;p&gt;In my group reproducibility is a big thing. Both to verify research results from us and other groups and also to build and document on code developed by master and PhD students. We use version control, and docker. Code alone is not enough, we aim to share the whole environment. But this is challenging when the code requires multiple CPUs and GPUs, you cannot easily put that in a docker container!&lt;/p&gt;
&lt;h2 id=&quot;matthijs-moed-surf&quot;&gt;Matthijs Moed, SURF&lt;/h2&gt;
&lt;p&gt;At SURF, we build tools that fit in the workflow of researchers. Our biggest challenge is finding out what researchers actually need and how they can use our tools in their work. We work not only with organisations like Astron, who need very special infrastructure, but also for the majority of researchers who use computational methods but are not specialists in using them. Offering the right tools to them involves sometimes knowing their needs without them being able to formulate them. Meeting researchers where they are is key to developing sustainable research software.&lt;/p&gt;
&lt;h2 id=&quot;jeremy-cohen-imperial-college-london&quot;&gt;Jeremy Cohen, Imperial College London&lt;/h2&gt;
&lt;p&gt;Infrastructure to support software, such as version control, is particularly important in my work and that of people I collaborate with. Containers are becoming more important in the research community as a method to help support reproducibility and address challenges such as working across different computing platforms. Continuous integration (CI) (Ed: continuously testing code while expanding its functionality) is also growing in importance. At Imperial College London, as in many other research institutions, we have access to such services, but of course, as the use of software and computing infrastructure in research continues to grow, there are frequently new opportunities emerging to improve the offerings and infrastructure that are provided to researchers. This is something that I aim to help support as a leader of our local research software community.&lt;/p&gt;
&lt;h2 id=&quot;discussion-session&quot;&gt;Discussion session&lt;/h2&gt;
&lt;p&gt;While we had prepared some questions for the panellists, we also allowed the discussion to flow organically. Members of the audience were also invited to ask their own questions. This is a summary of some of these questions and the panel’s responses.&lt;/p&gt;
&lt;p&gt;How is national infrastructure organised in the UK, and how does it compare to the Netherlands?***&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jeremy&lt;/em&gt;: While there is national research computing infrastructure in the UK, many resources are also provided at a local or regional level. There is wide use of commercial services for managing code, such as GitHub. I feel that there is scope for improvement in the context of providing coordinated research software infrastructure at a national level but it can be difficult to assess the value of this and how to make it available. A key discussion point is who pays for such infrastructure and how? And how do we make sure people have equal access to these resources particularly when they are paid services?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Matthijs:&lt;/em&gt; at SURF we provide national infrastructure. There are technical difficulties like federation (Ed: sharing resources across multiple organisations), but we probably need to revisit some of these limitations and see what is possible as technology changes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: One thing we notice is that the barrier to external contributors is high with our local GitLab instance — working on GitHub makes it easier for astronomers around the world to collaborate, and some of our collaborators are based around the world, in places such as the USA and China.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Audience member #1&lt;/em&gt;: National infrastructure also creates fragmentation. Maybe we need a roadmap / strategy, not only infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;In your opinion, which infrastructures are missing, that you/your organisation would benefit if they were available?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This question sparked a short discussion and several audience members contributed to it: One audience member said that guidance on HPC resources is very valuable. They have HPC resources available from SURF (Lisa, Research Cloud, etc.) but still need some guidance on when to use which one. Another audience member experienced SURF as an invaluable resource for navigating the different solutions available for their research needs. Another point that was raised were generic skills that would help all researchers working with high computational needs, like basic GPU and CPU programing. The audience member mentioned that there is a hurdle to getting to know all these systems, while, at the same time, a bit of speedup in your results is indeed an invaluable resource.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;How about the code itself? Are there quality criteria applicable to all code, making it FAIR and sustainable? Should we educate all researchers?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jeremy&lt;/em&gt;: Not every researcher should be a computer scientist, but some level of understanding on code quality and how to think about writing your code is still valuable. For example, how you think about the problem. Software being considered a first class output would make researchers see more value in producing good code. Architecture of code makes code more sustainable. Good quality documentation should provide the information users will need. Documenting decisions on choices of libraries used is also useful.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: At ASTRON there are some practices we follow to make code better, and we should do more. We have professional engineers who are not (necessarily) astronomers. In this group we encourage good practices like code reviews. I am curious about using Sonarqube (Ed: an &lt;a href=&quot;https://www.sonarsource.com/products/sonarqube/&quot;&gt;open-source platform for continuous analysis of code quality&lt;/a&gt;), but just playing with it at the moment. One thing that resonated from what Jeremy said, is that there are astronomers who get really involved in developing code (such as astropy), but it does not get recognition — it will not get you tenure. This is a problem for the sustainability of astropy. And we do not have funding models for it, such as turning packages into part of the infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Are we creating walls around science? “To be an astronomer you need to know a long list of things”?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: You do need to have some level of knowledge. We have been using things like mentoring or google summer of code to develop some of these skills on people who use them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Audience&lt;/em&gt;: what I find interesting are the collaborations for example in digital humanities: computer scientists &amp;#x26; historians, more collaboration is the way to go.&lt;/p&gt;
&lt;p&gt;It is in a way similar to a chemistry lab: at the lab you have materials available, and protocols you need to follow to use those materials. Researchers get trained on how to use those materials, but they do not need to build them themselves. Research software is similar to those materials, researchers need to be trained on how to use them, but they can work together with research software engineers that can help them build those materials.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Most important points/Key Message&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During our panel session on infrastructure for sustainable research software, we discussed several services for tracking changes, sharing computational environments and high performance computing. Interestingly, the discussion quickly moved from technical solutions towards a more broader view of what constitutes infrastructure:&lt;/p&gt;
&lt;p&gt;The panel and audience agreed that it should be acknowledged that infrastructure is not only facilities and services, but that people, and in some cases software, can also be a critical part of infrastructure.&lt;/p&gt;
&lt;p&gt;For the panel session itself, we cannot say that the panellists and audience agreed on which services exactly are critical or absolutely essential to be offered at national level. What the audience and panellists agreed on was that we need a national strategy or roadmap to organise infrastructure in a way that is technically sound, as well as useful for the end users. And not just the technical infrastructure, but also the organisational infrastructure and personnel to provide better support to researchers by providing consultancy, training and implementation. Furthermore, everyone in the room saw the need to include the points of view from a diverse set of users when deciding on the infrastructure. Not all users will want or need to have a say in what type of services are offered, but they will want to be informed on how to use and access those services when needed.&lt;/p&gt;</description><pubDate>Thu, 26 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;*written by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-luisa-orozco/&quot;&gt;&lt;em&gt;Luisa Orozco&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;http://www.linkedin.com/in/danielagawehns/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and *&lt;a href=&quot;https://medium.com/@c.martinez&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Open Science Festival: What infrastructures do we need to preserve research software?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/open-science-festival-what-infrastructur-9069ad56.Bg1b7T0q_biUgK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this year, the 2023 edition of the Dutch &lt;a href=&quot;https://opensciencefestival.nl/&quot;&gt;Open Science Festival&lt;/a&gt; was held. We (the eScience Center and Leiden University) organised the session “National infrastructure for sustainable research software”. In this session we discussed the benefits and limits of available software preservation platforms (or infrastructures) and if national infrastructures for research software development are feasible and desirable.&lt;/p&gt;
&lt;p&gt;Research software increasingly forms a critically important element of many research projects across a wide array of domains. To achieve truly sustainable and reproducible research, not only the software itself but also the computational environment it depends on needs to be preserved. Different types of infrastructure are required to support these preservation activities.&lt;/p&gt;
&lt;p&gt;One user-friendly example of a friendly way to package computational environmetns are Docker containers. These containers can be archived on privately owned platforms like Docker Hub and GitHub or on publicly funded archives such as Zenodo. Such platforms become part of the infrastructure needed to rerun and reuse research code associated with research results.&lt;/p&gt;
&lt;h2 id=&quot;panel-composition-and-pitches&quot;&gt;Panel composition and pitches&lt;/h2&gt;
&lt;p&gt;The session was organised as a series of panel pitches, followed by a group discussion. The panel shared their insights and experiences, as we explored current issues with container storage platforms and related infrastructure and the role the Dutch research landscape can take as a provider of independent and government funded infrastructure for sustainable research software.&lt;/p&gt;
&lt;p&gt;The panel was composed of national and international experts from different domains and backgrounds to contribute (researcher, software engineer, administrator of research servers, science funders). Panellists were John Swinbank from ASTRON, Niki van Stein from LIACS, Leiden University, Matthijs Moed from SURF and Jeremy Cohen from Imperial College London.&lt;/p&gt;
&lt;p&gt;Panellists were asked to prepare a short pitch with their view on the following question:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Which infrastructures (version control, containers publication, Zenodo, testing infrastructure, any other?) are most important to the work your organisation does?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a summary of the pitches from each panellist:&lt;/p&gt;
&lt;h2 id=&quot;john-swinbank-astron&quot;&gt;John Swinbank, ASTRON&lt;/h2&gt;
&lt;p&gt;ASTRON works on a regime of big data. We are already working with tens of petabytes of data from telescopes like LOFAR, and that will increase to the order of 1 Exabyte per year when SKA (Ed.: a &lt;a href=&quot;https://www.astron.nl/category/telescopes/ska/&quot;&gt;new radio telescope&lt;/a&gt;) comes online later this decade. Our task is to make sure this volume of data is in a format that is usable for astronomers. The astronomical community has been working towards full reproducibility, but it is not yet completely embedded in the culture. In terms of infrastructure, we have a local GitLab instance for code sharing;using containers and publishing on Zenodo is not yet universally accepted.&lt;/p&gt;
&lt;h2 id=&quot;niki-van-stein-liacs-leiden-university&quot;&gt;Niki van Stein, LIACS, Leiden University&lt;/h2&gt;
&lt;p&gt;In my group reproducibility is a big thing. Both to verify research results from us and other groups and also to build and document on code developed by master and PhD students. We use version control, and docker. Code alone is not enough, we aim to share the whole environment. But this is challenging when the code requires multiple CPUs and GPUs, you cannot easily put that in a docker container!&lt;/p&gt;
&lt;h2 id=&quot;matthijs-moed-surf&quot;&gt;Matthijs Moed, SURF&lt;/h2&gt;
&lt;p&gt;At SURF, we build tools that fit in the workflow of researchers. Our biggest challenge is finding out what researchers actually need and how they can use our tools in their work. We work not only with organisations like Astron, who need very special infrastructure, but also for the majority of researchers who use computational methods but are not specialists in using them. Offering the right tools to them involves sometimes knowing their needs without them being able to formulate them. Meeting researchers where they are is key to developing sustainable research software.&lt;/p&gt;
&lt;h2 id=&quot;jeremy-cohen-imperial-college-london&quot;&gt;Jeremy Cohen, Imperial College London&lt;/h2&gt;
&lt;p&gt;Infrastructure to support software, such as version control, is particularly important in my work and that of people I collaborate with. Containers are becoming more important in the research community as a method to help support reproducibility and address challenges such as working across different computing platforms. Continuous integration (CI) (Ed: continuously testing code while expanding its functionality) is also growing in importance. At Imperial College London, as in many other research institutions, we have access to such services, but of course, as the use of software and computing infrastructure in research continues to grow, there are frequently new opportunities emerging to improve the offerings and infrastructure that are provided to researchers. This is something that I aim to help support as a leader of our local research software community.&lt;/p&gt;
&lt;h2 id=&quot;discussion-session&quot;&gt;Discussion session&lt;/h2&gt;
&lt;p&gt;While we had prepared some questions for the panellists, we also allowed the discussion to flow organically. Members of the audience were also invited to ask their own questions. This is a summary of some of these questions and the panel’s responses.&lt;/p&gt;
&lt;p&gt;How is national infrastructure organised in the UK, and how does it compare to the Netherlands?***&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jeremy&lt;/em&gt;: While there is national research computing infrastructure in the UK, many resources are also provided at a local or regional level. There is wide use of commercial services for managing code, such as GitHub. I feel that there is scope for improvement in the context of providing coordinated research software infrastructure at a national level but it can be difficult to assess the value of this and how to make it available. A key discussion point is who pays for such infrastructure and how? And how do we make sure people have equal access to these resources particularly when they are paid services?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Matthijs:&lt;/em&gt; at SURF we provide national infrastructure. There are technical difficulties like federation (Ed: sharing resources across multiple organisations), but we probably need to revisit some of these limitations and see what is possible as technology changes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: One thing we notice is that the barrier to external contributors is high with our local GitLab instance — working on GitHub makes it easier for astronomers around the world to collaborate, and some of our collaborators are based around the world, in places such as the USA and China.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Audience member #1&lt;/em&gt;: National infrastructure also creates fragmentation. Maybe we need a roadmap / strategy, not only infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;In your opinion, which infrastructures are missing, that you/your organisation would benefit if they were available?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This question sparked a short discussion and several audience members contributed to it: One audience member said that guidance on HPC resources is very valuable. They have HPC resources available from SURF (Lisa, Research Cloud, etc.) but still need some guidance on when to use which one. Another audience member experienced SURF as an invaluable resource for navigating the different solutions available for their research needs. Another point that was raised were generic skills that would help all researchers working with high computational needs, like basic GPU and CPU programing. The audience member mentioned that there is a hurdle to getting to know all these systems, while, at the same time, a bit of speedup in your results is indeed an invaluable resource.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;How about the code itself? Are there quality criteria applicable to all code, making it FAIR and sustainable? Should we educate all researchers?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jeremy&lt;/em&gt;: Not every researcher should be a computer scientist, but some level of understanding on code quality and how to think about writing your code is still valuable. For example, how you think about the problem. Software being considered a first class output would make researchers see more value in producing good code. Architecture of code makes code more sustainable. Good quality documentation should provide the information users will need. Documenting decisions on choices of libraries used is also useful.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: At ASTRON there are some practices we follow to make code better, and we should do more. We have professional engineers who are not (necessarily) astronomers. In this group we encourage good practices like code reviews. I am curious about using Sonarqube (Ed: an &lt;a href=&quot;https://www.sonarsource.com/products/sonarqube/&quot;&gt;open-source platform for continuous analysis of code quality&lt;/a&gt;), but just playing with it at the moment. One thing that resonated from what Jeremy said, is that there are astronomers who get really involved in developing code (such as astropy), but it does not get recognition — it will not get you tenure. This is a problem for the sustainability of astropy. And we do not have funding models for it, such as turning packages into part of the infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Are we creating walls around science? “To be an astronomer you need to know a long list of things”?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John&lt;/em&gt;: You do need to have some level of knowledge. We have been using things like mentoring or google summer of code to develop some of these skills on people who use them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Audience&lt;/em&gt;: what I find interesting are the collaborations for example in digital humanities: computer scientists &amp;#x26; historians, more collaboration is the way to go.&lt;/p&gt;
&lt;p&gt;It is in a way similar to a chemistry lab: at the lab you have materials available, and protocols you need to follow to use those materials. Researchers get trained on how to use those materials, but they do not need to build them themselves. Research software is similar to those materials, researchers need to be trained on how to use them, but they can work together with research software engineers that can help them build those materials.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Most important points/Key Message&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During our panel session on infrastructure for sustainable research software, we discussed several services for tracking changes, sharing computational environments and high performance computing. Interestingly, the discussion quickly moved from technical solutions towards a more broader view of what constitutes infrastructure:&lt;/p&gt;
&lt;p&gt;The panel and audience agreed that it should be acknowledged that infrastructure is not only facilities and services, but that people, and in some cases software, can also be a critical part of infrastructure.&lt;/p&gt;
&lt;p&gt;For the panel session itself, we cannot say that the panellists and audience agreed on which services exactly are critical or absolutely essential to be offered at national level. What the audience and panellists agreed on was that we need a national strategy or roadmap to organise infrastructure in a way that is technically sound, as well as useful for the end users. And not just the technical infrastructure, but also the organisational infrastructure and personnel to provide better support to researchers by providing consultancy, training and implementation. Furthermore, everyone in the room saw the need to include the points of view from a diverse set of users when deciding on the infrastructure. Not all users will want or need to have a say in what type of services are offered, but they will want to be informed on how to use and access those services when needed.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/open-science-festival-what-infrastructur-9069ad56.Bg1b7T0q.jpeg" medium="image"/><author>Carlos Martinez-Ortiz</author></item><item><title>The Utopic Git History</title><link>https://blog.esciencecenter.nl/posts/2023-10-25---the-utopic-git-history</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-10-25---the-utopic-git-history</guid><description>&lt;p&gt;&lt;em&gt;If you love this article and can’t wait to read more about The Utopic Git History, please see &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/achieving-utopic-git-history-4cc2a1fd3107?sk=88f3dac86d55ac1833f66165bc6634c2&quot;&gt;&lt;em&gt;this follow-up article&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; by Abel.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A quick way to create discord among a group of developers is to discuss Git. More specifically, whether to merge, rebase, or squash. There are many arguments around this, simply because it involves opinions on whether the end result is good or bad. Some of these arguments verge from bad experiences with extreme cases. The most common case that I encounter is the dreadful huge pull request**.&lt;/p&gt;
&lt;p&gt;“Mm… can you review this for me?” — Cthulhu (Generated by DALL-E, modified by me)A very large pull request is one containing changes in many files, possibly with many commits. Even if best practices are followed — which we will discuss here — it is a big endeavor to review such a pull request. If best practices are not followed, then it is a nightmare, and the end result is ugly. Some common issues with the result are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequential commits that seem unrelated.&lt;/li&gt;
&lt;li&gt;Many commits “fixing” the same thing.&lt;/li&gt;
&lt;li&gt;One huge (probably squashed) commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s discuss how to avoid this issue, and touch on the merge vs rebase vs squash debate on the way there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Target audience: This post should be useful for anyone interested in best practices with Git, or intermediate/advanced usage of Git. It also contains opinions on Git rebase and squash, so it might trigger some people.&lt;/p&gt;
&lt;h2 id=&quot;ugh--utopic-git-history&quot;&gt;UGH — Utopic Git History&lt;/h2&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note: UGH should be pronounced with disdain and eye-rolling.&lt;/p&gt;
&lt;p&gt;The main idea behind what I will call UGH workflow is **atomic git commits. **This is not a new subject, you can find a few blog posts about it — in fact, I just found out about the &lt;a href=&quot;https://www.youtube.com/watch?v=_e5oq4JT4_8&quot;&gt;Git Legit&lt;/a&gt; talk by Pauline Vos and I strongly recommend watching it.&lt;/p&gt;
&lt;p&gt;If you haven’t heard of atomic git commits, let me give you a short introduction. The basic idea of an atomic git commit is that it contains the shortest amount of work that does what it is supposed to do. That is, less work would not be enough to do the task, and more work would be going out of scope.&lt;/p&gt;
&lt;p&gt;Pauline describes three features of an atomic git commit, the first is what I just described. I normally like to think of the other two separately because they are good practices that we should follow even if we don’t do atomic git commits: (i) make sure that new commits do not break the code and (ii) have a clear and concise commit message. However, I understand the need to explicitly mention them, so that’s why I just explicitly mentioned them as well.&lt;/p&gt;
&lt;p&gt;If every commit is an atomic commit, then we have a beautiful git history. Every commit passes tests, so we can easily navigate around. Every commit has a non-creeping purpose, so we can cherry-pick them more easily. Every commit is self-contained, so we can revert them trivially. It is almost utopic, but it is actually attainable.&lt;/p&gt;
&lt;p&gt;If a pull request made of atomic git commits passes our way, we can review each commit individually, making our life easier. Then, what is the end result of our three merging strategies (as given by GitHub)?&lt;/p&gt;
&lt;h3 id=&quot;merge-commit&quot;&gt;Merge commit&lt;/h3&gt;
&lt;p&gt;A merge commit will be a new commit with a message like &lt;em&gt;“Merging PR #123 from branch featureX”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Visualization of Git merge with a new commit. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)Here&quot;&gt;https://doi.org/10.5281/zenodo.8032313)Here&lt;/a&gt; is an example from a real GitHub repository:&lt;/p&gt;
&lt;p&gt;A main branch up top and many branches that were merged with merge commit. Source: GitHub network graph of &lt;a href=&quot;https://github.com/abelsiqueira/perprof-py&quot;&gt;https://github.com/abelsiqueira/perprof-py&lt;/a&gt;.Personally, I don’t think that this extra commit is very useful. Even when all commits in the branch are pristine, passing, and having a great message, we still have this “parallel” development, which does not add any useful information. Furthermore, the merge commits themselves are not atomic.&lt;/p&gt;
&lt;h3 id=&quot;squash&quot;&gt;Squash&lt;/h3&gt;
&lt;p&gt;Squashing is simply creating a single commit with the content of all commits, and rebasing the result.&lt;/p&gt;
&lt;p&gt;Visualization of merging with squash. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)The&quot;&gt;https://doi.org/10.5281/zenodo.8032313)The&lt;/a&gt; default commit message will change the title of the commit to something like &lt;em&gt;“Title of the pull request (#pr)”&lt;/em&gt;, and then the old commit messages will be aggregated into a single commit message. This is a problem because now we have taken all atomic git commits and thrown their &lt;em&gt;atomicity&lt;/em&gt; away.&lt;/p&gt;
&lt;p&gt;The squash frequently comes into play when the pull request **does not **contain atomic git commits. Then it might be better to squash and have a single commit than a larger mess. If the resulting commit is atomic, then that is great. Otherwise, we have scope creep.&lt;/p&gt;
&lt;h3 id=&quot;rebase-and-dont-squash&quot;&gt;Rebase and don’t squash&lt;/h3&gt;
&lt;p&gt;Rebasing without squashing means rebasing the current branch on top of the current &lt;code&gt;main&lt;/code&gt; and merging with &lt;code&gt;fast-forward&lt;/code&gt;, i.e., not creating any new commit and simply updating &lt;code&gt;main&lt;/code&gt;’s pointer.&lt;/p&gt;
&lt;p&gt;Visualization of Git rebase. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)Here&quot;&gt;https://doi.org/10.5281/zenodo.8032313)Here&lt;/a&gt; is an example from the same GitHub repository, from a later date:&lt;/p&gt;
&lt;p&gt;Main branch and no other branches. Source: GitHub network graph of &lt;a href=&quot;https://github.com/abelsiqueira/perprof-py&quot;&gt;https://github.com/abelsiqueira/perprof-py&lt;/a&gt;.The end result contains only &lt;code&gt;main&lt;/code&gt;. There is no information that there ever was a feature branch.&lt;/p&gt;
&lt;p&gt;This strategy was shown for last because it is my preference, but also because it is the only one of the three that will consistently keep the commits atomic — assuming that we have achieved a pull request with atomic commits.&lt;/p&gt;
&lt;h2 id=&quot;how-to-achieve-atomic-git-commits&quot;&gt;How to achieve atomic git commits&lt;/h2&gt;
&lt;p&gt;Here are some tips to make pull requests with atomic git commits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there are too many commits, use &lt;code&gt;git rebase -i&lt;/code&gt; to reorder, fix, squash or edit commits.&lt;/li&gt;
&lt;li&gt;If there is uncommitted work that touches more than one topic, use &lt;code&gt;git add -p&lt;/code&gt; to add the parts that make sense for a single commit.&lt;/li&gt;
&lt;li&gt;If there are commits from different scopes, &lt;code&gt;rebase&lt;/code&gt; into new branches.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git commit --amend&lt;/code&gt; to fix the current commit.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git push --force&lt;/code&gt; to update the branch online (the &lt;code&gt;main&lt;/code&gt; branch can be protected so &lt;code&gt;main&lt;/code&gt; is not accidentally rewritten).&lt;/li&gt;
&lt;li&gt;Use a &lt;a href=&quot;http://pre-commit.com&quot;&gt;pre-commit hook&lt;/a&gt; to avoid having to create extra “fix linter” commits.&lt;/li&gt;
&lt;li&gt;Be prescient and write perfect commits — but you knew that already ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once again I recommend Pauline’s &lt;a href=&quot;https://www.youtube.com/watch?v=_e5oq4JT4_8&quot;&gt;Git Legit&lt;/a&gt; talk for more detailed examples but feel free to leave a comment here if you think of a situation that needs more care.&lt;/p&gt;
&lt;h2 id=&quot;more-utopia-please&quot;&gt;More utopia, please&lt;/h2&gt;
&lt;p&gt;The second part of the UGH workflow is to do the same for branches, and therefore, pull requests. In other words, the pull request must have the least amount of commits necessary to do what it is supposed to do. You can read a blog post about this by &lt;a href=&quot;https://fagnerbrack.com/one-pull-request-one-concern-e84a27dfe9f1&quot;&gt;Fagner Brack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If each commit tells a story, and they are in an order that makes sense, reviewing the pull request is much easier. Even if the pull request is still huge, it can be reviewed one commit at a time.&lt;/p&gt;
&lt;p&gt;When reviewing, or receiving reviews, we should be vigilant of scope creep. The PR should do only what it is supposed to do.&lt;/p&gt;
&lt;h3 id=&quot;but-what-is-the-pr-supposed-to-do&quot;&gt;But what is the PR supposed to do?&lt;/h3&gt;
&lt;p&gt;This is the harder part because it is not just git anymore. There are different approaches to determining what is a PR, but the one I have the most experience with is to relate them with issues. In other words, the issue defines the topic, or scope, of the PR. Following this approach, an atomic definition would be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each pull request should close one, and only one issue.&lt;/li&gt;
&lt;li&gt;Each issue should be small enough to not creep into more than one topic.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Clarification: not every issue leads to a pull request, but every pull request requires an issue.&lt;/p&gt;
&lt;p&gt;To achieve this, one has to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Break issues into smaller issues.&lt;/li&gt;
&lt;li&gt;Create new issues for every desired change.&lt;/li&gt;
&lt;li&gt;Merge incomplete issues and close duplicates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The actual size of the issue depends on how the team works, and who creates the issues. Some issues are user stories that involve many tasks. Some are bug reports. Some are tech-debt opportunities. Some are users’ questions.&lt;/p&gt;
&lt;p&gt;Issues that involve many tasks are sometimes called epics. *One way of dealing with epic issues is to create separate issues for each task — see the next section — but you could just as well have a larger pull request with one commit for each task. There is no one-size-fits-all solution.&lt;/p&gt;
&lt;p&gt;I find that it helps a lot to work on an epic issue as a whole, then split it into smaller parts &lt;em&gt;a posteriori&lt;/em&gt;. Then I make separate branches and create pull requests one at a time. One shortcoming of this approach is that if the reviewer makes big suggestions to one pull request, the other branches might be heavily affected.&lt;/p&gt;
&lt;h2 id=&quot;extreme-ugh&quot;&gt;Extreme UGH&lt;/h2&gt;
&lt;p&gt;What if we take these atomic definitions to the extreme?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;One commit per pull request.&lt;/p&gt;
&lt;p&gt;Since the issue is minimal, then it should be fixable with a single commit, right? Otherwise, the issue would not be minimal.&lt;/p&gt;
&lt;p&gt;Why is this extreme?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The reviewer and the developer must share the context. For instance, there might be dependencies between pull requests by the same developer. If the reviewer does not have that clear, then the pull request can actually be harder to understand than a single larger PR.&lt;/li&gt;
&lt;li&gt;It can be hard to know beforehand how to break an epic issue. Sometimes we only know how to break an issue after working on it. But what if we are not the ones responsible for updating the issue? Then we need to create a demand for the issue to be broken and wait until work can be restarted.&lt;/li&gt;
&lt;li&gt;Sometimes the code base is not modular enough. We might need API changes for a different part of the code. Scope creep might be unavoidable due to technical debt. If there is time, though, trying to pay this debt as a separate issue might be better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be aware of these limitations. Trying to achieve UGH can lead to loss of friends, or worst, productivity (this is a joke, managers).&lt;/p&gt;
&lt;h2 id=&quot;self-inflicted-ugh&quot;&gt;Self-inflicted UGH&lt;/h2&gt;
&lt;p&gt;A good way of starting using UGH is to follow the workflow on your own, before trying to enforce it on the team.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure that your pull requests are atomic, even if nobody is enforcing UGH.&lt;/li&gt;
&lt;li&gt;As long as you’re the only one touching your branch, force-pushing won’t break anybody’s work.&lt;/li&gt;
&lt;li&gt;When you have to update your pull request because of conflicts with &lt;code&gt;main&lt;/code&gt;, you can rebase your branch instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This helps you practice and might help your team to see the benefits.&lt;/p&gt;
&lt;p&gt;Finally, I chose the name Utopic Git History (UGH) to remind us of two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It can be very obnoxious to insist on the workflow (hence the ugh sound), especially when reviewing pull requests.&lt;/li&gt;
&lt;li&gt;It is utopic in the sense of being unattainable in practice (for extended periods of time). Take parts of the idea and test them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best way to achieve UGH is to create a good culture first.&lt;/p&gt;
&lt;p&gt;I actually don’t have any project that fully follows the UGH workflow, but I try to follow it with my personal commits, and I use rebase in many repositories. I spent a decent chunk of time helping people to update their workspace after their pull request was rebased (sometimes deleting everything and starting over was the chosen solution). It is not trivial to adopt this strategy for the whole project, but I can certainly say that it helped me learn more about Git.&lt;/p&gt;
&lt;p&gt;Let us know if you (try to) use UGH or similar for your projects.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/sander-van-rijn-msc/&quot;&gt;&lt;em&gt;Sander van Rijn&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez-Sánchez&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-candace-makeda-moore-md/&quot;&gt;&lt;em&gt;Candace Makeda Moore&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Wed, 25 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;If you love this article and can’t wait to read more about The Utopic Git History, please see &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/achieving-utopic-git-history-4cc2a1fd3107?sk=88f3dac86d55ac1833f66165bc6634c2&quot;&gt;&lt;em&gt;this follow-up article&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; by Abel.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A quick way to create discord among a group of developers is to discuss Git. More specifically, whether to merge, rebase, or squash. There are many arguments around this, simply because it involves opinions on whether the end result is good or bad. Some of these arguments verge from bad experiences with extreme cases. The most common case that I encounter is the dreadful huge pull request**.&lt;/p&gt;
&lt;p&gt;“Mm… can you review this for me?” — Cthulhu (Generated by DALL-E, modified by me)A very large pull request is one containing changes in many files, possibly with many commits. Even if best practices are followed — which we will discuss here — it is a big endeavor to review such a pull request. If best practices are not followed, then it is a nightmare, and the end result is ugly. Some common issues with the result are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequential commits that seem unrelated.&lt;/li&gt;
&lt;li&gt;Many commits “fixing” the same thing.&lt;/li&gt;
&lt;li&gt;One huge (probably squashed) commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s discuss how to avoid this issue, and touch on the merge vs rebase vs squash debate on the way there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Target audience: This post should be useful for anyone interested in best practices with Git, or intermediate/advanced usage of Git. It also contains opinions on Git rebase and squash, so it might trigger some people.&lt;/p&gt;
&lt;h2 id=&quot;ugh--utopic-git-history&quot;&gt;UGH — Utopic Git History&lt;/h2&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note: UGH should be pronounced with disdain and eye-rolling.&lt;/p&gt;
&lt;p&gt;The main idea behind what I will call UGH workflow is **atomic git commits. **This is not a new subject, you can find a few blog posts about it — in fact, I just found out about the &lt;a href=&quot;https://www.youtube.com/watch?v=_e5oq4JT4_8&quot;&gt;Git Legit&lt;/a&gt; talk by Pauline Vos and I strongly recommend watching it.&lt;/p&gt;
&lt;p&gt;If you haven’t heard of atomic git commits, let me give you a short introduction. The basic idea of an atomic git commit is that it contains the shortest amount of work that does what it is supposed to do. That is, less work would not be enough to do the task, and more work would be going out of scope.&lt;/p&gt;
&lt;p&gt;Pauline describes three features of an atomic git commit, the first is what I just described. I normally like to think of the other two separately because they are good practices that we should follow even if we don’t do atomic git commits: (i) make sure that new commits do not break the code and (ii) have a clear and concise commit message. However, I understand the need to explicitly mention them, so that’s why I just explicitly mentioned them as well.&lt;/p&gt;
&lt;p&gt;If every commit is an atomic commit, then we have a beautiful git history. Every commit passes tests, so we can easily navigate around. Every commit has a non-creeping purpose, so we can cherry-pick them more easily. Every commit is self-contained, so we can revert them trivially. It is almost utopic, but it is actually attainable.&lt;/p&gt;
&lt;p&gt;If a pull request made of atomic git commits passes our way, we can review each commit individually, making our life easier. Then, what is the end result of our three merging strategies (as given by GitHub)?&lt;/p&gt;
&lt;h3 id=&quot;merge-commit&quot;&gt;Merge commit&lt;/h3&gt;
&lt;p&gt;A merge commit will be a new commit with a message like &lt;em&gt;“Merging PR #123 from branch featureX”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Visualization of Git merge with a new commit. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)Here&quot;&gt;https://doi.org/10.5281/zenodo.8032313)Here&lt;/a&gt; is an example from a real GitHub repository:&lt;/p&gt;
&lt;p&gt;A main branch up top and many branches that were merged with merge commit. Source: GitHub network graph of &lt;a href=&quot;https://github.com/abelsiqueira/perprof-py&quot;&gt;https://github.com/abelsiqueira/perprof-py&lt;/a&gt;.Personally, I don’t think that this extra commit is very useful. Even when all commits in the branch are pristine, passing, and having a great message, we still have this “parallel” development, which does not add any useful information. Furthermore, the merge commits themselves are not atomic.&lt;/p&gt;
&lt;h3 id=&quot;squash&quot;&gt;Squash&lt;/h3&gt;
&lt;p&gt;Squashing is simply creating a single commit with the content of all commits, and rebasing the result.&lt;/p&gt;
&lt;p&gt;Visualization of merging with squash. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)The&quot;&gt;https://doi.org/10.5281/zenodo.8032313)The&lt;/a&gt; default commit message will change the title of the commit to something like &lt;em&gt;“Title of the pull request (#pr)”&lt;/em&gt;, and then the old commit messages will be aggregated into a single commit message. This is a problem because now we have taken all atomic git commits and thrown their &lt;em&gt;atomicity&lt;/em&gt; away.&lt;/p&gt;
&lt;p&gt;The squash frequently comes into play when the pull request **does not **contain atomic git commits. Then it might be better to squash and have a single commit than a larger mess. If the resulting commit is atomic, then that is great. Otherwise, we have scope creep.&lt;/p&gt;
&lt;h3 id=&quot;rebase-and-dont-squash&quot;&gt;Rebase and don’t squash&lt;/h3&gt;
&lt;p&gt;Rebasing without squashing means rebasing the current branch on top of the current &lt;code&gt;main&lt;/code&gt; and merging with &lt;code&gt;fast-forward&lt;/code&gt;, i.e., not creating any new commit and simply updating &lt;code&gt;main&lt;/code&gt;’s pointer.&lt;/p&gt;
&lt;p&gt;Visualization of Git rebase. (&lt;a href=&quot;https://doi.org/10.5281/zenodo.8032313)Here&quot;&gt;https://doi.org/10.5281/zenodo.8032313)Here&lt;/a&gt; is an example from the same GitHub repository, from a later date:&lt;/p&gt;
&lt;p&gt;Main branch and no other branches. Source: GitHub network graph of &lt;a href=&quot;https://github.com/abelsiqueira/perprof-py&quot;&gt;https://github.com/abelsiqueira/perprof-py&lt;/a&gt;.The end result contains only &lt;code&gt;main&lt;/code&gt;. There is no information that there ever was a feature branch.&lt;/p&gt;
&lt;p&gt;This strategy was shown for last because it is my preference, but also because it is the only one of the three that will consistently keep the commits atomic — assuming that we have achieved a pull request with atomic commits.&lt;/p&gt;
&lt;h2 id=&quot;how-to-achieve-atomic-git-commits&quot;&gt;How to achieve atomic git commits&lt;/h2&gt;
&lt;p&gt;Here are some tips to make pull requests with atomic git commits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there are too many commits, use &lt;code&gt;git rebase -i&lt;/code&gt; to reorder, fix, squash or edit commits.&lt;/li&gt;
&lt;li&gt;If there is uncommitted work that touches more than one topic, use &lt;code&gt;git add -p&lt;/code&gt; to add the parts that make sense for a single commit.&lt;/li&gt;
&lt;li&gt;If there are commits from different scopes, &lt;code&gt;rebase&lt;/code&gt; into new branches.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git commit --amend&lt;/code&gt; to fix the current commit.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git push --force&lt;/code&gt; to update the branch online (the &lt;code&gt;main&lt;/code&gt; branch can be protected so &lt;code&gt;main&lt;/code&gt; is not accidentally rewritten).&lt;/li&gt;
&lt;li&gt;Use a &lt;a href=&quot;http://pre-commit.com&quot;&gt;pre-commit hook&lt;/a&gt; to avoid having to create extra “fix linter” commits.&lt;/li&gt;
&lt;li&gt;Be prescient and write perfect commits — but you knew that already ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once again I recommend Pauline’s &lt;a href=&quot;https://www.youtube.com/watch?v=_e5oq4JT4_8&quot;&gt;Git Legit&lt;/a&gt; talk for more detailed examples but feel free to leave a comment here if you think of a situation that needs more care.&lt;/p&gt;
&lt;h2 id=&quot;more-utopia-please&quot;&gt;More utopia, please&lt;/h2&gt;
&lt;p&gt;The second part of the UGH workflow is to do the same for branches, and therefore, pull requests. In other words, the pull request must have the least amount of commits necessary to do what it is supposed to do. You can read a blog post about this by &lt;a href=&quot;https://fagnerbrack.com/one-pull-request-one-concern-e84a27dfe9f1&quot;&gt;Fagner Brack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If each commit tells a story, and they are in an order that makes sense, reviewing the pull request is much easier. Even if the pull request is still huge, it can be reviewed one commit at a time.&lt;/p&gt;
&lt;p&gt;When reviewing, or receiving reviews, we should be vigilant of scope creep. The PR should do only what it is supposed to do.&lt;/p&gt;
&lt;h3 id=&quot;but-what-is-the-pr-supposed-to-do&quot;&gt;But what is the PR supposed to do?&lt;/h3&gt;
&lt;p&gt;This is the harder part because it is not just git anymore. There are different approaches to determining what is a PR, but the one I have the most experience with is to relate them with issues. In other words, the issue defines the topic, or scope, of the PR. Following this approach, an atomic definition would be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each pull request should close one, and only one issue.&lt;/li&gt;
&lt;li&gt;Each issue should be small enough to not creep into more than one topic.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Clarification: not every issue leads to a pull request, but every pull request requires an issue.&lt;/p&gt;
&lt;p&gt;To achieve this, one has to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Break issues into smaller issues.&lt;/li&gt;
&lt;li&gt;Create new issues for every desired change.&lt;/li&gt;
&lt;li&gt;Merge incomplete issues and close duplicates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The actual size of the issue depends on how the team works, and who creates the issues. Some issues are user stories that involve many tasks. Some are bug reports. Some are tech-debt opportunities. Some are users’ questions.&lt;/p&gt;
&lt;p&gt;Issues that involve many tasks are sometimes called epics. *One way of dealing with epic issues is to create separate issues for each task — see the next section — but you could just as well have a larger pull request with one commit for each task. There is no one-size-fits-all solution.&lt;/p&gt;
&lt;p&gt;I find that it helps a lot to work on an epic issue as a whole, then split it into smaller parts &lt;em&gt;a posteriori&lt;/em&gt;. Then I make separate branches and create pull requests one at a time. One shortcoming of this approach is that if the reviewer makes big suggestions to one pull request, the other branches might be heavily affected.&lt;/p&gt;
&lt;h2 id=&quot;extreme-ugh&quot;&gt;Extreme UGH&lt;/h2&gt;
&lt;p&gt;What if we take these atomic definitions to the extreme?&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;One commit per pull request.&lt;/p&gt;
&lt;p&gt;Since the issue is minimal, then it should be fixable with a single commit, right? Otherwise, the issue would not be minimal.&lt;/p&gt;
&lt;p&gt;Why is this extreme?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The reviewer and the developer must share the context. For instance, there might be dependencies between pull requests by the same developer. If the reviewer does not have that clear, then the pull request can actually be harder to understand than a single larger PR.&lt;/li&gt;
&lt;li&gt;It can be hard to know beforehand how to break an epic issue. Sometimes we only know how to break an issue after working on it. But what if we are not the ones responsible for updating the issue? Then we need to create a demand for the issue to be broken and wait until work can be restarted.&lt;/li&gt;
&lt;li&gt;Sometimes the code base is not modular enough. We might need API changes for a different part of the code. Scope creep might be unavoidable due to technical debt. If there is time, though, trying to pay this debt as a separate issue might be better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be aware of these limitations. Trying to achieve UGH can lead to loss of friends, or worst, productivity (this is a joke, managers).&lt;/p&gt;
&lt;h2 id=&quot;self-inflicted-ugh&quot;&gt;Self-inflicted UGH&lt;/h2&gt;
&lt;p&gt;A good way of starting using UGH is to follow the workflow on your own, before trying to enforce it on the team.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure that your pull requests are atomic, even if nobody is enforcing UGH.&lt;/li&gt;
&lt;li&gt;As long as you’re the only one touching your branch, force-pushing won’t break anybody’s work.&lt;/li&gt;
&lt;li&gt;When you have to update your pull request because of conflicts with &lt;code&gt;main&lt;/code&gt;, you can rebase your branch instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This helps you practice and might help your team to see the benefits.&lt;/p&gt;
&lt;p&gt;Finally, I chose the name Utopic Git History (UGH) to remind us of two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It can be very obnoxious to insist on the workflow (hence the ugh sound), especially when reviewing pull requests.&lt;/li&gt;
&lt;li&gt;It is utopic in the sense of being unattainable in practice (for extended periods of time). Take parts of the idea and test them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best way to achieve UGH is to create a good culture first.&lt;/p&gt;
&lt;p&gt;I actually don’t have any project that fully follows the UGH workflow, but I try to follow it with my personal commits, and I use rebase in many repositories. I spent a decent chunk of time helping people to update their workspace after their pull request was rebased (sometimes deleting everything and starting over was the chosen solution). It is not trivial to adopt this strategy for the whole project, but I can certainly say that it helped me learn more about Git.&lt;/p&gt;
&lt;p&gt;Let us know if you (try to) use UGH or similar for your projects.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/sander-van-rijn-msc/&quot;&gt;&lt;em&gt;Sander van Rijn&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez-Sánchez&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-candace-makeda-moore-md/&quot;&gt;&lt;em&gt;Candace Makeda Moore&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><author>Abel Soares Siqueira</author></item><item><title>Achieving Utopic Git History</title><link>https://blog.esciencecenter.nl/posts/2023-10-19---achieving-utopic-git-history</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-10-19---achieving-utopic-git-history</guid><description>&lt;h2 id=&quot;aka-being-ughly&quot;&gt;AKA being UGHly&lt;/h2&gt;
&lt;p&gt;In a previous blog post, we defined &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;The Utopic Git History&lt;/a&gt; (UGH). To refresh our memory, a simple definition of a UGH is&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Atomic git commits (smallest commit that completes the task)&lt;/li&gt;
&lt;li&gt;Passing tests&lt;/li&gt;
&lt;li&gt;Linear Git history&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In that post, I mentioned that the easiest way to achieve UGH is to squash a self-contained pull request into a single commit. Otherwise, you have to use more advanced git commands to achieve UGH. This blog post deals with that.&lt;/p&gt;
&lt;p&gt;The target audience for this post is Git users who want to learn intermediate and advanced commands that splice, merge, and fix commits. If you need a refresher on some of the concepts used, please take a look at the &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;animations in my previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The ideal way of achieving UGH is to write exactly what you have to write, and then commit that. This kind of insight is hard to come by when your task is large, so instead let’s focus on what happens in practice, which involves getting our hands dirty.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Meme. Left image shows dirty hands with a caption “My hands look like this” and right image shows git branches being transformed into linear git history with a caption “So my git history can look like this.”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_w6RS2UcGCMtyvWSI2Eg7Ow-c5a1c936.CDnJLX_-_Z2uSccu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Getting your hands dirty. Left photo by Jeremy Bishop on Unsplash. Modifications by me.&lt;/p&gt;
&lt;h2 id=&quot;before-committing&quot;&gt;Before committing&lt;/h2&gt;
&lt;p&gt;The first thing that we can control is what to commit. So let’s assume that we got to a point where we have a lot of modifications because task A turned out to be too large and now we’re thinking of splitting it into A1 and A2 (maybe more).&lt;/p&gt;
&lt;p&gt;Here, &lt;code&gt;git add -p&lt;/code&gt; comes into play. &lt;code&gt;git add -p&lt;/code&gt; lets us add &lt;strong&gt;patches&lt;/strong&gt; of code separately. So if our file has modifications for tasks A1 and A2, we can add only the first one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If there is an untracked file that we want to selectively add, it can be included using &lt;code&gt;git add -N FILE&lt;/code&gt;. This will tell git to track the file, but it doesn’t stage it.&lt;/p&gt;
&lt;p&gt;When we run &lt;code&gt;git add -p FILES&lt;/code&gt;, we see something like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;diff &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Something&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Something&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;n) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Stage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; this hunk [y,n,q,a,d,s,e,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pressing &lt;code&gt;?&lt;/code&gt; will show the help. There are four commands that matter a lot to us. The first two are y and n, for yes and no. If we say yes, the “hunk” (a piece of code shown in this diff) will be staged. Remember, when we &lt;code&gt;git commit&lt;/code&gt; (no &lt;code&gt;-a&lt;/code&gt; flag), the staged part of the code will be added to the commit. If we say no, then it just moves on to the next hunk.&lt;/p&gt;
&lt;p&gt;The third command is the best: s, for split. If the hunk that we see on the screen is too large, or if it involves parts A1 and A2, then we want to split it. Git will try to find a place to split this code and give you smaller hunks. Then we can decide whether to add or not those new smaller hunks individually.&lt;/p&gt;
&lt;p&gt;Split doesn’t always work, so what we can do instead is use the command e, for edit. Editing will open an editor, so if you don’t like Vim (the default), you can change it with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git config &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--local core.editor &quot;code --wait&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the command above, &lt;code&gt;code --wait&lt;/code&gt; will open VSCode. Change it to your preference. Also, you can configure it globally using &lt;code&gt;--global&lt;/code&gt; instead of &lt;code&gt;--local&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After running &lt;code&gt;git add -p&lt;/code&gt; and selecting the command e, we will get to the editor with the same diff open and some additional information.&lt;/p&gt;
&lt;p&gt;The first column of the hunk can be empty, to indicate that the code doesn’t change, &lt;code&gt;#&lt;/code&gt; to indicate a comment that will be ignored by git add, a &lt;code&gt;-&lt;/code&gt; to indicate that the line should be removed, and a &lt;code&gt;+&lt;/code&gt; to indicate a new line replacing the old one.&lt;/p&gt;
&lt;p&gt;Now, we can manually decide on each individual addition. Let’s look at an example:&lt;/p&gt;
&lt;p&gt;Our initial code is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, our task A1 is to rename y to p, and task A2 is to change all additions to subtractions.&lt;/p&gt;
&lt;p&gt;The resulting code after doing both tasks is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diff, which we will see when we enter edit mode, is the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# Manual hunk edit mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, tasks A1 and A2 are mixed and can’t be split. So instead, we manually change the diff. Since we want only A1 applied, we change the diff to&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change &lt;code&gt;-w = x + 1&lt;/code&gt; to &lt;code&gt;[space]w = x + 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove line &lt;code&gt;+w = x - 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move the two + lines one line up&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;+z = x - p&lt;/code&gt; to &lt;code&gt;+z = x + p&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please notice that the lines starting with a minus sign can’t be modified, because they must match with the current code. If you want to make modifications to a line that has a minus, look for the corresponding plus and change that instead. If there is no corresponding plus, it means that the line is simply being removed, so you can add a line with a plus yourself.&lt;/p&gt;
&lt;p&gt;Now, if we look at your git status, we will see the same file appearing in and out of the staged section. We can use &lt;code&gt;git diff --staged&lt;/code&gt; to check the result.&lt;/p&gt;
&lt;h2 id=&quot;oops-too-late-one-commit-with-multiple-tasks&quot;&gt;Oops, too late (one commit with multiple tasks)&lt;/h2&gt;
&lt;p&gt;Let’s say that we have one commit with multiple tasks, i.e., one commit that should be split into more than one.&lt;/p&gt;
&lt;p&gt;For instance, we might have spent 10 minutes meticulously editing what should be staged using the &lt;code&gt;git add -p&lt;/code&gt; command, when by mistake we use &lt;code&gt;git commit -a&lt;/code&gt; and add every unstaged modification in the commit as well, wasting all this work. Completely hypothetical, mind you.&lt;/p&gt;
&lt;p&gt;There is a quick way to “fix” this which is to run &lt;code&gt;git reset HEAD~1&lt;/code&gt;. This will remove the commit and go back to the modified state. To be clear, we don’t lose the modifications made in the commit, as they will be back into the modified state, but we lose the previously staged information in those 10 minutes of work.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;git reset HEAD~1&lt;/code&gt; command assumes that the latest commit is the one that we are fixing. If that is not the case, check the next session.&lt;/p&gt;
&lt;p&gt;As a rule, &lt;strong&gt;always back up your branch&lt;/strong&gt; whenever you run reset and rebase until you are confident that you can get yourself out of tricky situations. Backup, in this case, means creating a new branch, e.g., &lt;code&gt;git branch backup-some-name&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;too-many-commits&quot;&gt;Too many commits&lt;/h2&gt;
&lt;p&gt;Let’s say that we ended up making too many commits. For instance, we were trying to follow the idea above, but noticed some bugs that should be part of task A1, and ended up creating another commit to fix that. Or that we realized that we introduced a bug that had no test when doing A2.&lt;/p&gt;
&lt;p&gt;As an example, consider the following initial state of a file &lt;code&gt;main.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return w&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the following git history:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hash00: Older stuff &lt;em&gt;← Where we are right now&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;hash01: Rename variable y to p&lt;/li&gt;
&lt;li&gt;hash02: Change + to -&lt;/li&gt;
&lt;li&gt;hash03: Rename y to p and change + to — in function &lt;code&gt;bar&lt;/code&gt; also&lt;/li&gt;
&lt;li&gt;hash04: Fix linting issue (add spaces around operators)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;hash01&lt;/code&gt; and &lt;code&gt;hash02&lt;/code&gt; commits are the ones we did in the previous sections. The &lt;code&gt;hash03&lt;/code&gt; commit is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the &lt;code&gt;hash04&lt;/code&gt; commit is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This git history is not great. We still only have two tasks (A1 and A2), but 4 commits. What we want to do is redistribute the work done in these 4 commits into 2 commits. For that, we use &lt;code&gt;git rebase -i&lt;/code&gt;, i.e., interactive rebase.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: There is an alternative to rebasing here, which is to run &lt;code&gt;reset hash00&lt;/code&gt;, so that we remove all the commits but none of the modifications. From there we will have to manually add the changes using &lt;code&gt;git add -p&lt;/code&gt; and then make individual commits. I prefer the rebase strategy. What are your thoughts about these two strategies?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The interactive rebase command allows us to reorder and squash commits, change the commit messages, and stop during rebasing to make additional changes (such as splitting older commits).&lt;/p&gt;
&lt;p&gt;The first thing that we need to do is find that git history. If you use a visual tool, you can just look at the graph. Otherwise, we can issue the command&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git log &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--graph --oneline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will produce a graph of the commits, one per line, which should be easy to read. It should be something like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash04&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This assumes that we branched out of &lt;code&gt;main&lt;/code&gt; into a branch called &lt;code&gt;feat_br&lt;/code&gt;. Now, to start rebasing, we can issue&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;i main feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, it is just the normal rebase command, but now we add the &lt;code&gt;-i&lt;/code&gt; flag to have more options on how to rebase.&lt;/p&gt;
&lt;p&gt;This command should open an editor with the list of commits preceded by a keyword &lt;code&gt;pick&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash04 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the commit at &lt;code&gt;main&lt;/code&gt; is not included, as expected.&lt;/p&gt;
&lt;p&gt;What we can do now is change the order of these commits as we see fit and change the keyword to the action that we want. Notice that the order of the commits is top-to-bottom.&lt;/p&gt;
&lt;p&gt;The main options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pick: Use this commit. It will be applied, and the message will be used.&lt;/li&gt;
&lt;li&gt;drop: Don’t use the commit. It will be lost.&lt;/li&gt;
&lt;li&gt;reword: Use this commit, but open the editor to modify the commit message.&lt;/li&gt;
&lt;li&gt;squash: Merge the contents of this commit in the previous commit and then open the editor for editing the commit message. By default, it appends the commit messages of squashed commits.&lt;/li&gt;
&lt;li&gt;fixup: Like squash, merge the contents into the previous commit, but ignore the message.&lt;/li&gt;
&lt;li&gt;edit: Use this commit and the message, but after the commit is done, stop so we can make edits.&lt;/li&gt;
&lt;li&gt;break: Use by itself in a new line. It will drop us in the terminal to do whatever we want.&lt;/li&gt;
&lt;li&gt;exec: Use by itself followed by a command. It will run the command, and if there is an error, drops us in the terminal to do whatever we want.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whenever we are dropped in the terminal during rebase, we can always issue &lt;code&gt;git rebase --abort&lt;/code&gt; to stop the rebase completely and go back to where we were.&lt;/p&gt;
&lt;p&gt;If we were dropped in the terminal because there is a problem, for instance, a conflict, then we must fix it.&lt;/p&gt;
&lt;p&gt;After fixing whatever caused us to be dropped into the terminal (check with &lt;code&gt;git status&lt;/code&gt; ) we have to use &lt;code&gt;git rebase --continue&lt;/code&gt; to continue rebasing.&lt;/p&gt;
&lt;p&gt;Going back to our example, the first thing that we’ll do is split the &lt;code&gt;hash03&lt;/code&gt; commit. To do that, we simply change we &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;edit&lt;/code&gt;, save and close.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;edit hash03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash04 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will drop us in the terminal with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Stopped&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at hash03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;You&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; can amend the commit now, with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git commit &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--amend &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Once&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; you are satisfied with your changes, run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--continue&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will use &lt;code&gt;reset&lt;/code&gt; to undo this single commit and add only the change for task A1.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git reset &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HEAD&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git add &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the first commit diff look like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the second looks like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can run &lt;code&gt;git rebase --continue&lt;/code&gt; and &lt;code&gt;git log --graph --oneline&lt;/code&gt; again to obtain:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the hashes changed only after we effectively rebased.&lt;/p&gt;
&lt;p&gt;Now, we will use &lt;code&gt;git rebase -i main feat_br&lt;/code&gt; again, but this time we will move things around and change &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;fixup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We start with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And change to&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will apply the first commit and then fix it, leaving only a single commit. Then, it will apply the second commit and fix it twice. None of these changes led to conflicts.&lt;/p&gt;
&lt;p&gt;At the end of this process, our log is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; more02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; more01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, we have achieved UGH for this branch.&lt;/p&gt;
&lt;h2 id=&quot;splitting-a-branch-into-many-branches&quot;&gt;Splitting a branch into many branches&lt;/h2&gt;
&lt;p&gt;Now that we have two commits, one for each task, it makes sense to actually have two branches: one for each commit.&lt;/p&gt;
&lt;p&gt;Since the commits are atomic, this is actually very easy to do &lt;strong&gt;unless&lt;/strong&gt; the branches depend on each other.&lt;/p&gt;
&lt;p&gt;The first task is just the first commit in our case, so we only need to give it a branch name:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git branch feature_taskA more01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, we are creating a branch called &lt;code&gt;feature_taskA&lt;/code&gt; at the commit with hash &lt;code&gt;more01&lt;/code&gt;. Push this branch&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u origin feature_taskA&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can be reviewed and rebased.&lt;/p&gt;
&lt;p&gt;Now, let’s split into two situations.&lt;/p&gt;
&lt;h3 id=&quot;splitting-independent-branches&quot;&gt;Splitting independent branches&lt;/h3&gt;
&lt;p&gt;If the commits are independent, we just have so now where they start and rebase rooted there.&lt;/p&gt;
&lt;p&gt;Normally, we are rooted in main, as in our example above. So we can issue&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--onto=main feature_taskA feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we are saying “Take all commits after &lt;code&gt;feature_taskA&lt;/code&gt; (exclusive) that are part of branch &lt;code&gt;feat_br&lt;/code&gt;, and reapply them on top of the branch &lt;code&gt;main&lt;/code&gt;.” We can use a hash instead of &lt;code&gt;main&lt;/code&gt;, if necessary.&lt;/p&gt;
&lt;p&gt;This can lead to conflicts, even if there is no real dependency between the commits. If the conflicts are significant, then it is better to treat them as dependents. The conflicts that appear here will reappear when we try to merge these two branches into main.&lt;/p&gt;
&lt;h3 id=&quot;splitting-dependent-branches&quot;&gt;Splitting dependent branches&lt;/h3&gt;
&lt;p&gt;If the branches are dependent, then we should actually wait until the first part is merged before rebasing.&lt;/p&gt;
&lt;p&gt;When the first part is merged (let’s assume with GitHub’s rebase), then we now have a new &lt;code&gt;main&lt;/code&gt;, with other commit hashes. In that case, we can simply issue a rebase and the commits that already appeared on the merged branch will be skipped, by default.&lt;/p&gt;
&lt;p&gt;However, this depends on configuration values, so it is safer to just use exactly the same commands as before, but don’t forget to update your main branch.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git fetch &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git merge &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--ff-only upstream/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--onto=main feature_taskA feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, the only difference between the independent and dependent cases is &lt;strong&gt;when&lt;/strong&gt; to rebase. If the branches are independent, you can split and push both, since they can be reviewed and merged independently. If the branches are dependent, then we wait until the first branch is merged and rebase after updating main.&lt;/p&gt;
&lt;h2 id=&quot;remote-changes&quot;&gt;Remote changes&lt;/h2&gt;
&lt;p&gt;The last thing to discuss is the changes that could be happening in the remotes while we’re making changes.&lt;/p&gt;
&lt;p&gt;Let’s assume in this section that we have two remotes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;upstream&lt;/code&gt;: Points to the main repo, e.g., the organization’s repo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;origin&lt;/code&gt;: Points to our fork.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First of all, my preferred way to work is to make sure that my atomic commit is up to date with the remote branch. So first of all, I fetch everything, update &lt;code&gt;main&lt;/code&gt; with the fast-forward option, and &lt;strong&gt;branch from main&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git fetch &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git merge &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--ff-only upstream/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the merge had conflicts, it means that we made commits to &lt;code&gt;main&lt;/code&gt;, and we shouldn’t. We fix this by creating the branch now and resetting main:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git branch featureX &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; just creates, does not switch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git reset &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--hard upstream/main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, after working on branch &lt;code&gt;featureX&lt;/code&gt;, we check for updates on &lt;code&gt;main &lt;/code&gt; again, using &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;merge --ff-only&lt;/code&gt;. If there were any changes to main, we rebase after pushing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase main featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We might have conflicts, but since our branch is atomic, they should be few and far between.&lt;/p&gt;
&lt;p&gt;After rebasing, we push:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u origin featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s say that we had to make changes because of the review. After making our changes, we use interactive rebase to make sure that the commits are atomic again. Our branch will not be in sync with the remote branch anymore, because the commits have changed (either in content or in hash).&lt;/p&gt;
&lt;p&gt;That means that we now have to force-push our branch:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--force featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should be enough to update the pull request.&lt;/p&gt;
&lt;h3 id=&quot;final-remarks&quot;&gt;Final remarks&lt;/h3&gt;
&lt;p&gt;These commands should help you handle most git situations. They are not easy to master, so I hope that this post serves as a quick way to remember what each command does. Let us know what other Git needs you have.&lt;/p&gt;
&lt;p&gt;Be UGHly, my friend.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-barbara-veede/&quot;&gt;&lt;em&gt;Barbara Vreede&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez-Sánchez&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 19 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;aka-being-ughly&quot;&gt;AKA being UGHly&lt;/h2&gt;
&lt;p&gt;In a previous blog post, we defined &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;The Utopic Git History&lt;/a&gt; (UGH). To refresh our memory, a simple definition of a UGH is&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Atomic git commits (smallest commit that completes the task)&lt;/li&gt;
&lt;li&gt;Passing tests&lt;/li&gt;
&lt;li&gt;Linear Git history&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In that post, I mentioned that the easiest way to achieve UGH is to squash a self-contained pull request into a single commit. Otherwise, you have to use more advanced git commands to achieve UGH. This blog post deals with that.&lt;/p&gt;
&lt;p&gt;The target audience for this post is Git users who want to learn intermediate and advanced commands that splice, merge, and fix commits. If you need a refresher on some of the concepts used, please take a look at the &lt;a href=&quot;https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593&quot;&gt;animations in my previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The ideal way of achieving UGH is to write exactly what you have to write, and then commit that. This kind of insight is hard to come by when your task is large, so instead let’s focus on what happens in practice, which involves getting our hands dirty.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Meme. Left image shows dirty hands with a caption “My hands look like this” and right image shows git branches being transformed into linear git history with a caption “So my git history can look like this.”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_w6RS2UcGCMtyvWSI2Eg7Ow-c5a1c936.CDnJLX_-_Z2uSccu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Getting your hands dirty. Left photo by Jeremy Bishop on Unsplash. Modifications by me.&lt;/p&gt;
&lt;h2 id=&quot;before-committing&quot;&gt;Before committing&lt;/h2&gt;
&lt;p&gt;The first thing that we can control is what to commit. So let’s assume that we got to a point where we have a lot of modifications because task A turned out to be too large and now we’re thinking of splitting it into A1 and A2 (maybe more).&lt;/p&gt;
&lt;p&gt;Here, &lt;code&gt;git add -p&lt;/code&gt; comes into play. &lt;code&gt;git add -p&lt;/code&gt; lets us add &lt;strong&gt;patches&lt;/strong&gt; of code separately. So if our file has modifications for tasks A1 and A2, we can add only the first one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If there is an untracked file that we want to selectively add, it can be included using &lt;code&gt;git add -N FILE&lt;/code&gt;. This will tell git to track the file, but it doesn’t stage it.&lt;/p&gt;
&lt;p&gt;When we run &lt;code&gt;git add -p FILES&lt;/code&gt;, we see something like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;diff &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Something&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Something&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;n) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Stage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; this hunk [y,n,q,a,d,s,e,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pressing &lt;code&gt;?&lt;/code&gt; will show the help. There are four commands that matter a lot to us. The first two are y and n, for yes and no. If we say yes, the “hunk” (a piece of code shown in this diff) will be staged. Remember, when we &lt;code&gt;git commit&lt;/code&gt; (no &lt;code&gt;-a&lt;/code&gt; flag), the staged part of the code will be added to the commit. If we say no, then it just moves on to the next hunk.&lt;/p&gt;
&lt;p&gt;The third command is the best: s, for split. If the hunk that we see on the screen is too large, or if it involves parts A1 and A2, then we want to split it. Git will try to find a place to split this code and give you smaller hunks. Then we can decide whether to add or not those new smaller hunks individually.&lt;/p&gt;
&lt;p&gt;Split doesn’t always work, so what we can do instead is use the command e, for edit. Editing will open an editor, so if you don’t like Vim (the default), you can change it with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git config &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--local core.editor &quot;code --wait&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the command above, &lt;code&gt;code --wait&lt;/code&gt; will open VSCode. Change it to your preference. Also, you can configure it globally using &lt;code&gt;--global&lt;/code&gt; instead of &lt;code&gt;--local&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After running &lt;code&gt;git add -p&lt;/code&gt; and selecting the command e, we will get to the editor with the same diff open and some additional information.&lt;/p&gt;
&lt;p&gt;The first column of the hunk can be empty, to indicate that the code doesn’t change, &lt;code&gt;#&lt;/code&gt; to indicate a comment that will be ignored by git add, a &lt;code&gt;-&lt;/code&gt; to indicate that the line should be removed, and a &lt;code&gt;+&lt;/code&gt; to indicate a new line replacing the old one.&lt;/p&gt;
&lt;p&gt;Now, we can manually decide on each individual addition. Let’s look at an example:&lt;/p&gt;
&lt;p&gt;Our initial code is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, our task A1 is to rename y to p, and task A2 is to change all additions to subtractions.&lt;/p&gt;
&lt;p&gt;The resulting code after doing both tasks is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diff, which we will see when we enter edit mode, is the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# Manual hunk edit mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, tasks A1 and A2 are mixed and can’t be split. So instead, we manually change the diff. Since we want only A1 applied, we change the diff to&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change &lt;code&gt;-w = x + 1&lt;/code&gt; to &lt;code&gt;[space]w = x + 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove line &lt;code&gt;+w = x - 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move the two + lines one line up&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;+z = x - p&lt;/code&gt; to &lt;code&gt;+z = x + p&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please notice that the lines starting with a minus sign can’t be modified, because they must match with the current code. If you want to make modifications to a line that has a minus, look for the corresponding plus and change that instead. If there is no corresponding plus, it means that the line is simply being removed, so you can add a line with a plus yourself.&lt;/p&gt;
&lt;p&gt;Now, if we look at your git status, we will see the same file appearing in and out of the staged section. We can use &lt;code&gt;git diff --staged&lt;/code&gt; to check the result.&lt;/p&gt;
&lt;h2 id=&quot;oops-too-late-one-commit-with-multiple-tasks&quot;&gt;Oops, too late (one commit with multiple tasks)&lt;/h2&gt;
&lt;p&gt;Let’s say that we have one commit with multiple tasks, i.e., one commit that should be split into more than one.&lt;/p&gt;
&lt;p&gt;For instance, we might have spent 10 minutes meticulously editing what should be staged using the &lt;code&gt;git add -p&lt;/code&gt; command, when by mistake we use &lt;code&gt;git commit -a&lt;/code&gt; and add every unstaged modification in the commit as well, wasting all this work. Completely hypothetical, mind you.&lt;/p&gt;
&lt;p&gt;There is a quick way to “fix” this which is to run &lt;code&gt;git reset HEAD~1&lt;/code&gt;. This will remove the commit and go back to the modified state. To be clear, we don’t lose the modifications made in the commit, as they will be back into the modified state, but we lose the previously staged information in those 10 minutes of work.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;git reset HEAD~1&lt;/code&gt; command assumes that the latest commit is the one that we are fixing. If that is not the case, check the next session.&lt;/p&gt;
&lt;p&gt;As a rule, &lt;strong&gt;always back up your branch&lt;/strong&gt; whenever you run reset and rebase until you are confident that you can get yourself out of tricky situations. Backup, in this case, means creating a new branch, e.g., &lt;code&gt;git branch backup-some-name&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;too-many-commits&quot;&gt;Too many commits&lt;/h2&gt;
&lt;p&gt;Let’s say that we ended up making too many commits. For instance, we were trying to follow the idea above, but noticed some bugs that should be part of task A1, and ended up creating another commit to fix that. Or that we realized that we introduced a bug that had no test when doing A2.&lt;/p&gt;
&lt;p&gt;As an example, consider the following initial state of a file &lt;code&gt;main.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return w&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the following git history:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hash00: Older stuff &lt;em&gt;← Where we are right now&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;hash01: Rename variable y to p&lt;/li&gt;
&lt;li&gt;hash02: Change + to -&lt;/li&gt;
&lt;li&gt;hash03: Rename y to p and change + to — in function &lt;code&gt;bar&lt;/code&gt; also&lt;/li&gt;
&lt;li&gt;hash04: Fix linting issue (add spaces around operators)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;hash01&lt;/code&gt; and &lt;code&gt;hash02&lt;/code&gt; commits are the ones we did in the previous sections. The &lt;code&gt;hash03&lt;/code&gt; commit is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the &lt;code&gt;hash04&lt;/code&gt; commit is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This git history is not great. We still only have two tasks (A1 and A2), but 4 commits. What we want to do is redistribute the work done in these 4 commits into 2 commits. For that, we use &lt;code&gt;git rebase -i&lt;/code&gt;, i.e., interactive rebase.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: There is an alternative to rebasing here, which is to run &lt;code&gt;reset hash00&lt;/code&gt;, so that we remove all the commits but none of the modifications. From there we will have to manually add the changes using &lt;code&gt;git add -p&lt;/code&gt; and then make individual commits. I prefer the rebase strategy. What are your thoughts about these two strategies?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The interactive rebase command allows us to reorder and squash commits, change the commit messages, and stop during rebasing to make additional changes (such as splitting older commits).&lt;/p&gt;
&lt;p&gt;The first thing that we need to do is find that git history. If you use a visual tool, you can just look at the graph. Otherwise, we can issue the command&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git log &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--graph --oneline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will produce a graph of the commits, one per line, which should be easy to read. It should be something like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash04&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This assumes that we branched out of &lt;code&gt;main&lt;/code&gt; into a branch called &lt;code&gt;feat_br&lt;/code&gt;. Now, to start rebasing, we can issue&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;i main feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, it is just the normal rebase command, but now we add the &lt;code&gt;-i&lt;/code&gt; flag to have more options on how to rebase.&lt;/p&gt;
&lt;p&gt;This command should open an editor with the list of commits preceded by a keyword &lt;code&gt;pick&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash04 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the commit at &lt;code&gt;main&lt;/code&gt; is not included, as expected.&lt;/p&gt;
&lt;p&gt;What we can do now is change the order of these commits as we see fit and change the keyword to the action that we want. Notice that the order of the commits is top-to-bottom.&lt;/p&gt;
&lt;p&gt;The main options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pick: Use this commit. It will be applied, and the message will be used.&lt;/li&gt;
&lt;li&gt;drop: Don’t use the commit. It will be lost.&lt;/li&gt;
&lt;li&gt;reword: Use this commit, but open the editor to modify the commit message.&lt;/li&gt;
&lt;li&gt;squash: Merge the contents of this commit in the previous commit and then open the editor for editing the commit message. By default, it appends the commit messages of squashed commits.&lt;/li&gt;
&lt;li&gt;fixup: Like squash, merge the contents into the previous commit, but ignore the message.&lt;/li&gt;
&lt;li&gt;edit: Use this commit and the message, but after the commit is done, stop so we can make edits.&lt;/li&gt;
&lt;li&gt;break: Use by itself in a new line. It will drop us in the terminal to do whatever we want.&lt;/li&gt;
&lt;li&gt;exec: Use by itself followed by a command. It will run the command, and if there is an error, drops us in the terminal to do whatever we want.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whenever we are dropped in the terminal during rebase, we can always issue &lt;code&gt;git rebase --abort&lt;/code&gt; to stop the rebase completely and go back to where we were.&lt;/p&gt;
&lt;p&gt;If we were dropped in the terminal because there is a problem, for instance, a conflict, then we must fix it.&lt;/p&gt;
&lt;p&gt;After fixing whatever caused us to be dropped into the terminal (check with &lt;code&gt;git status&lt;/code&gt; ) we have to use &lt;code&gt;git rebase --continue&lt;/code&gt; to continue rebasing.&lt;/p&gt;
&lt;p&gt;Going back to our example, the first thing that we’ll do is split the &lt;code&gt;hash03&lt;/code&gt; commit. To do that, we simply change we &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;edit&lt;/code&gt;, save and close.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;edit hash03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash04 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will drop us in the terminal with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Stopped&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at hash03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p and change &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function bar also&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;You&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; can amend the commit now, with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git commit &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--amend &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Once&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; you are satisfied with your changes, run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--continue&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will use &lt;code&gt;reset&lt;/code&gt; to undo this single commit and add only the change for task A1.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git reset &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HEAD&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git add &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the first commit diff look like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the second looks like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def bar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can run &lt;code&gt;git rebase --continue&lt;/code&gt; and &lt;code&gt;git log --graph --oneline&lt;/code&gt; again to obtain:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh03&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newh01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the hashes changed only after we effectively rebased.&lt;/p&gt;
&lt;p&gt;Now, we will use &lt;code&gt;git rebase -i main feat_br&lt;/code&gt; again, but this time we will move things around and change &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;fixup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We start with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick newh03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And change to&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh01 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pick hash02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh02 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fixing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;A2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;fixup newh03 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Fix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; linting issue (add spaces around operators)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will apply the first commit and then fix it, leaving only a single commit. Then, it will apply the second commit and fix it twice. None of these changes led to conflicts.&lt;/p&gt;
&lt;p&gt;At the end of this process, our log is&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; more02&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (feat_br) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Change&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; more01&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rename&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y to p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (main) &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Older&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stuff&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, we have achieved UGH for this branch.&lt;/p&gt;
&lt;h2 id=&quot;splitting-a-branch-into-many-branches&quot;&gt;Splitting a branch into many branches&lt;/h2&gt;
&lt;p&gt;Now that we have two commits, one for each task, it makes sense to actually have two branches: one for each commit.&lt;/p&gt;
&lt;p&gt;Since the commits are atomic, this is actually very easy to do &lt;strong&gt;unless&lt;/strong&gt; the branches depend on each other.&lt;/p&gt;
&lt;p&gt;The first task is just the first commit in our case, so we only need to give it a branch name:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git branch feature_taskA more01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, we are creating a branch called &lt;code&gt;feature_taskA&lt;/code&gt; at the commit with hash &lt;code&gt;more01&lt;/code&gt;. Push this branch&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u origin feature_taskA&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can be reviewed and rebased.&lt;/p&gt;
&lt;p&gt;Now, let’s split into two situations.&lt;/p&gt;
&lt;h3 id=&quot;splitting-independent-branches&quot;&gt;Splitting independent branches&lt;/h3&gt;
&lt;p&gt;If the commits are independent, we just have so now where they start and rebase rooted there.&lt;/p&gt;
&lt;p&gt;Normally, we are rooted in main, as in our example above. So we can issue&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--onto=main feature_taskA feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we are saying “Take all commits after &lt;code&gt;feature_taskA&lt;/code&gt; (exclusive) that are part of branch &lt;code&gt;feat_br&lt;/code&gt;, and reapply them on top of the branch &lt;code&gt;main&lt;/code&gt;.” We can use a hash instead of &lt;code&gt;main&lt;/code&gt;, if necessary.&lt;/p&gt;
&lt;p&gt;This can lead to conflicts, even if there is no real dependency between the commits. If the conflicts are significant, then it is better to treat them as dependents. The conflicts that appear here will reappear when we try to merge these two branches into main.&lt;/p&gt;
&lt;h3 id=&quot;splitting-dependent-branches&quot;&gt;Splitting dependent branches&lt;/h3&gt;
&lt;p&gt;If the branches are dependent, then we should actually wait until the first part is merged before rebasing.&lt;/p&gt;
&lt;p&gt;When the first part is merged (let’s assume with GitHub’s rebase), then we now have a new &lt;code&gt;main&lt;/code&gt;, with other commit hashes. In that case, we can simply issue a rebase and the commits that already appeared on the merged branch will be skipped, by default.&lt;/p&gt;
&lt;p&gt;However, this depends on configuration values, so it is safer to just use exactly the same commands as before, but don’t forget to update your main branch.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git fetch &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git merge &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--ff-only upstream/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--onto=main feature_taskA feat_br&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, the only difference between the independent and dependent cases is &lt;strong&gt;when&lt;/strong&gt; to rebase. If the branches are independent, you can split and push both, since they can be reviewed and merged independently. If the branches are dependent, then we wait until the first branch is merged and rebase after updating main.&lt;/p&gt;
&lt;h2 id=&quot;remote-changes&quot;&gt;Remote changes&lt;/h2&gt;
&lt;p&gt;The last thing to discuss is the changes that could be happening in the remotes while we’re making changes.&lt;/p&gt;
&lt;p&gt;Let’s assume in this section that we have two remotes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;upstream&lt;/code&gt;: Points to the main repo, e.g., the organization’s repo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;origin&lt;/code&gt;: Points to our fork.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First of all, my preferred way to work is to make sure that my atomic commit is up to date with the remote branch. So first of all, I fetch everything, update &lt;code&gt;main&lt;/code&gt; with the fast-forward option, and &lt;strong&gt;branch from main&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git fetch &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git merge &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--ff-only upstream/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the merge had conflicts, it means that we made commits to &lt;code&gt;main&lt;/code&gt;, and we shouldn’t. We fix this by creating the branch now and resetting main:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git switch main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git branch featureX &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; just creates, does not switch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git reset &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--hard upstream/main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, after working on branch &lt;code&gt;featureX&lt;/code&gt;, we check for updates on &lt;code&gt;main &lt;/code&gt; again, using &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;merge --ff-only&lt;/code&gt;. If there were any changes to main, we rebase after pushing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git rebase main featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We might have conflicts, but since our branch is atomic, they should be few and far between.&lt;/p&gt;
&lt;p&gt;After rebasing, we push:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u origin featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s say that we had to make changes because of the review. After making our changes, we use interactive rebase to make sure that the commits are atomic again. Our branch will not be in sync with the remote branch anymore, because the commits have changed (either in content or in hash).&lt;/p&gt;
&lt;p&gt;That means that we now have to force-push our branch:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git push &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--force featureX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should be enough to update the pull request.&lt;/p&gt;
&lt;h3 id=&quot;final-remarks&quot;&gt;Final remarks&lt;/h3&gt;
&lt;p&gt;These commands should help you handle most git situations. They are not easy to master, so I hope that this post serves as a quick way to remember what each command does. Let us know what other Git needs you have.&lt;/p&gt;
&lt;p&gt;Be UGHly, my friend.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-barbara-veede/&quot;&gt;&lt;em&gt;Barbara Vreede&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-rodriguez-sanchez/&quot;&gt;&lt;em&gt;Pablo Rodríguez-Sánchez&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_w6RS2UcGCMtyvWSI2Eg7Ow-c5a1c936.CDnJLX_-.gif" medium="image"/><author>Abel Soares Siqueira</author></item><item><title>the orange3 data mining platform as a research tool</title><link>https://blog.esciencecenter.nl/posts/2023-10-12---the-orange3-data-mining-platform-as-a-research-tool</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-10-12---the-orange3-data-mining-platform-as-a-research-tool</guid><description>&lt;h2 id=&quot;why-arent-more-ssh-researchers-using-and-extending-the-platform&quot;&gt;Why aren’t more SSH researchers using and extending the platform?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://orangedatamining.com/&quot;&gt;Orange&lt;/a&gt; is an open-source &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt; -based &lt;a href=&quot;https://www.britannica.com/technology/data-structure&quot;&gt;data mining&lt;/a&gt; application with a graphical user interface (GUI). It allows people with no knowledge of programming to apply Machine Learning as well as advanced data processing, analysis, and visualization using a point-and-click, drag-and-drop interface. Those who have seen &lt;a href=&quot;https://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt; will be familiar with this mode of interaction, although Orange is more advanced and is used for data mining, rather than educational programming. The following screenshot shows what a typical Orange &lt;a href=&quot;https://orangedatamining.com/workflows/&quot;&gt;workflow&lt;/a&gt; looks like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of the Orange3 interface. To the left of screen is the list of loaded add-ons (Toolboxes for data mining). To the right of screen is an example data mining workflow I created consisting of three Orange widgets: one to load data, one to display it in a table format and one for visualising it.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;793&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_P63Kn6BcFaxp2mzdYM-KGw-3d971242.BA8M75pr_Z1sj8eG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of an example data mining workflow in Orange3&lt;/p&gt;
&lt;p&gt;The three small circles labeled ‘File’, ‘Data Table’, and ‘Scatter Plot’ in the image above, are called Orange &lt;a href=&quot;https://docs.biolab.si/orange/2/widgets/rst/index.html&quot;&gt;widgets&lt;/a&gt;. They are the basic building blocks of a data analysis workflow (or pipeline) in Orange. Each widget is a software unit that performs some sort of data processing, analysis, or visualization and potentially has a set of inputs and outputs. You can connect the outputs of some widgets to the inputs of others to create a chain of processing and analysis operations. A great feature of Orange is its extensibility. There are loads of custom plugins for Orange (called &lt;em&gt;add-ons&lt;/em&gt;) developed by researchers and the Orange user community. Add-ons usually comprise multiple widgets. Two mature and extensively used Orange add-ons are &lt;a href=&quot;https://orange3-text.readthedocs.io/en/latest/&quot;&gt;Orange-Text&lt;/a&gt; and &lt;a href=&quot;https://orange3-network.readthedocs.io/en/latest/&quot;&gt;Network&lt;/a&gt; which are used for &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_theory&quot;&gt;network analysis&lt;/a&gt; respectively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Story Navigator: a custom Orange add-on I am developing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am currently in the process of developing an add-on as part of a project with researchers at the &lt;a href=&quot;https://www.utwente.nl/&quot;&gt;University of Twente&lt;/a&gt; in the Netherlands. The add-on is called the &lt;a href=&quot;https://github.com/navigating-stories/orange-story-navigator&quot;&gt;Story Navigator&lt;/a&gt;. The aim of the Story Navigator is to enable computer-aided analysis of written stories for students and researchers who study &lt;a href=&quot;https://en.wikipedia.org/wiki/Narrative_psychology&quot;&gt;narrative psychology&lt;/a&gt;. The add-on has several widgets to analyse different aspects of a story. It uses a combination of &lt;a href=&quot;https://encyclopediaofmath.org/wiki/Natural_language_processing&quot;&gt;natural language processing&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt;, and general data analysis techniques to implement theories in narrative psychology, such as &lt;a href=&quot;https://natureofwriting.com/courses/introduction-to-rhetoric/lessons/burkes-pentad/&quot;&gt;Burke’s pentad&lt;/a&gt;. Here’s a screen:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_bzPwFl1nsKeO-G9zDQzSpg-a1858653.Av62JrBZ_ZNscwQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of the Story Navigator add-on (not yet released) for Orange3.&lt;/p&gt;
&lt;p&gt;The add-on works by first importing textual stories into the workflow using the existing &lt;a href=&quot;https://orangedatamining.com/widget-catalog/text-mining/importdocuments/&quot;&gt;“Import Documents”&lt;/a&gt; widget from the Orange-Text add-on. Thereafter the researcher can choose a widget from the add-on for analysing some aspects of the imported stories. The actor analysis widget, for example, highlights potential characters in the stories; shows which kinds of actions (verbs) the characters are associated with; and calculates different measures for how central specific characters are to the stories.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;958&quot; height=&quot;578&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_JXuPlOl9CDyxWFD10paxgA-03e51f84.DYhSNI_J_Z2fQd8z.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Quantitative story analysis widgets from the Story Navigator add-on for Orange3.&lt;/p&gt;
&lt;p&gt;While it did take some time to develop the widgets for this add-on, what surprised me is that it took me only about two hours, from scratch, with no prior knowledge of Orange, to develop my first widget that showed up in the Orange3 interface when I started it up. Granted, the widget did not do anything except display. But the return on my two-hour investment was that I could now free up my creativity to develop whatever functionality I wanted in the widget, without having to create my own GUI. In doing so, I got to take advantage of a myriad of benefits including being able to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make my add-on available for anyone to use regardless of their programming knowledge&lt;/li&gt;
&lt;li&gt;Receive development and usage feedback from an existing Orange community about my add-on (without having to further promote the add-on or build another community myself from scratch)&lt;/li&gt;
&lt;li&gt;Demo my plugin to anyone, thanks to the GUI&lt;/li&gt;
&lt;li&gt;Share data analyses made with my add-on with other Orange users — enabling reproducibility (currently &lt;a href=&quot;https://www.nature.com/articles/d41586-019-00067-3&quot;&gt;undergoing a crisis&lt;/a&gt; in science)&lt;/li&gt;
&lt;li&gt;Forget about writing installation instructions — they’re already &lt;a href=&quot;https://orangedatamining.com/blog/2012/11/30/the-easy-way-to-install-add-ons/&quot;&gt;here&lt;/a&gt;!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Despite what some readers might think at this point, I am not an Orange evangelist. In fact, I am not swooning over the capabilities and potential of Orange specifically. Orange does have competing platforms that try to do similar things such as &lt;a href=&quot;https://www.knime.com/&quot;&gt;KNIME&lt;/a&gt; and &lt;a href=&quot;https://www.cs.waikato.ac.nz/ml/weka/&quot;&gt;WEKA&lt;/a&gt; which are both &lt;a href=&quot;https://www.java.com/en/&quot;&gt;Java&lt;/a&gt; -based and therefore inherit some concerns due to &lt;a href=&quot;https://www.tiobe.com/tiobe-index/&quot;&gt;Java’s declining popularity&lt;/a&gt;. Orange itself also has some clear disadvantages, not least of which are the &lt;a href=&quot;https://orangedatamining.com/blog/2012/01/03/parallel-orange/&quot;&gt;scalability issues&lt;/a&gt; and the &lt;a href=&quot;https://orange3-example-addon.readthedocs.io/en/latest/&quot;&gt;add-on development documentation&lt;/a&gt; (the latter is not very accessible for less experienced developers).&lt;/p&gt;
&lt;p&gt;But the point I am trying to make is that I am mostly just inspired by the philosophy behind platforms like these: people coming together to develop and share an extensible “workbench-style” software platform with a user-friendly interface. When I refer to software I don’t mean software that has a highly niche purpose, but software that aims to be an ever-evolving toolbox with the potential to address a multitude of research problems. Where your own creativity is the only limit in terms of contributing to it. Where the knowledge barriers to be able to contribute to it are super low, and where there are no qualifying criteria for those who can experience and benefit from the contributions.&lt;/p&gt;
&lt;p&gt;Orange was developed at the &lt;a href=&quot;https://fri.uni-lj.si/en/laboratory/biolab&quot;&gt;Laboratory for Bioinformatics&lt;/a&gt; at the University of Ljubljana. It makes sense then that most of its user base uses it for data mining in &lt;a href=&quot;https://www.britannica.com/science/bioinformatics&quot;&gt;bioinformatics&lt;/a&gt; (see for instance &lt;a href=&quot;https://www.mdpi.com/2076-3417/11/5/2218&quot;&gt;this study&lt;/a&gt; using Orange for early diagnosis of diabetes). But Orange itself is not at all designed to be domain-specific. Its add-ons and widgets are designed for domain-agnostic data mining (&lt;a href=&quot;https://www.mdpi.com/2076-3417/10/11/3894&quot;&gt;here’s a study&lt;/a&gt; using Orange to predict student performance in higher education). This begs the question, why aren’t more researchers in the Social Sciences and Humanities using it, extending it, or building similar platforms?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What the popular video game&lt;/strong&gt; &lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;&lt;strong&gt;Elder Scrolls&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;has to do with Orange&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bethesda.net/dashboard&quot;&gt;Bethesda Softworks&lt;/a&gt; is a US-based video game development company that is famous for its many franchises, one of which is “ &lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;Elder Scrolls&lt;/a&gt; ”. The games in this franchise are “ &lt;a href=&quot;https://en.wikipedia.org/wiki/Role-playing_game&quot;&gt;RPGs&lt;/a&gt; ” that put the player in control of a character from a fictional fantasy world with the goal to… wait for it… save the world from destruction (if you’re new to the term RPGs imagine a video game based on &lt;a href=&quot;https://www.hbo.com/game-of-thrones&quot;&gt;Game of Thrones&lt;/a&gt; and you’ll get the gist). In 2002, Bethesda released its third installment of Elder Scrolls, called “ &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Elder_Scrolls_III:_Morrowind&quot;&gt;Morrowind&lt;/a&gt; ”. The super interesting part is that they also released software called the &lt;a href=&quot;https://cs.elderscrolls.com/index.php?title=Main_Page&quot;&gt;Elder Scrolls Construction Set&lt;/a&gt; alongside the game. This software allowed players to make customizations to their own copy of the game. They could do things such as create new clothing, buildings, and other items; create their own character voices; make new quests, and customize the color of the sky. These modifications (&lt;em&gt;mods&lt;/em&gt; as they are now commonly referred to) vary in terms of how much software literacy is required in order to build them, but many of them require no more knowledge than being able to install a program and click a few buttons.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;978&quot; height=&quot;513&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_7pZdxrP9AKjQ3F7p-911a47a7.D7mMaqOF_ZoyG2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Fancy introducing Spiderman-suited creatures crawling around a medieval town into your video-gaming experience? Well, someone has already created a mod for this in Skyrim.&lt;/p&gt;
&lt;p&gt;Twenty years later, and Bethesda has become known and celebrated for giving its customers the freedom to customize their gaming experience. &lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; is one of the prominent hubs for hosting large collections of player-created mods for games by Bethesda and other major video game companies. I quote some jaw-dropping statistics from this site here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We host 477,145 mods for 2,342 games from 118,005 authors serving 41,902,274 members with 8,184,840,124 downloads to date.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In academia, terms like “outputs”, “impact”, “community building” and “community engagement” are often bandied about as performance goals and metrics for work. However, despite their purported importance, these terms are hard to define and measure. But when I look at those numbers, I feel like we don’t need unambiguous definitions for those terms in order to verify that the mod concept ticks all those boxes and then some.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;507&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SayaBHWxNn7HCpmaU0YmQA-a7da4685.D8UAVMwc_Z1a8U89.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Nexusmods demonstrates that the mod concept is a winner.&lt;/p&gt;
&lt;p&gt;“Okay Kody, what does this all have to do with Orange?”, you may ask. Well, in some ways there are parallels in this story to the concept of Orange as a software platform.&lt;/p&gt;
&lt;p&gt;First, there is a &lt;em&gt;product that many people enjoy&lt;/em&gt; (or find useful). In Bethesda’s case, it is the “vanilla” Elder Scrolls games. In Orange’s case, it is a data mining platform which is a generic tool that is useful regardless of the research domain and data. The GUI aspect of Orange also opens it up to a much larger user base (not just a small group of researchers with development experience working in a niche field).&lt;/p&gt;
&lt;p&gt;Second, there is the &lt;em&gt;enabling of customization.&lt;/em&gt; In Bethesda’s case, it is the provision of customization software such as the &lt;a href=&quot;https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/&quot;&gt;Skyrim Creation Kit&lt;/a&gt;; in the case of Orange, it is the release of the code under an open-source license with reusable example code and plugin-writing tutorials.&lt;/p&gt;
&lt;p&gt;Thirdly, and what I find to be the most critical, is &lt;em&gt;making it easy to customize.&lt;/em&gt; In Bethesda’s case, they have made user-friendly software that does not require extremely specialized skills to use. Almost anyone can create a mod. In Orange’s case, you still need to know how to program to develop add-ons. But you don’t need advanced knowledge of the GUI frameworks that Orange uses — &lt;a href=&quot;https://en.wikipedia.org/wiki/Qt_(software)&quot;&gt;Qt&lt;/a&gt; and &lt;a href=&quot;https://wiki.python.org/moin/PyQt&quot;&gt;PyQt&lt;/a&gt;. In other words, if you know how to create any kind of computational script or software in Python, you can easily create an Orange widget to “house” or “wrap” its functionality. Furthermore, others, regardless of their technical nous, will be able to use it and “chain” your widget with other software in an Orange workflow.&lt;/p&gt;
&lt;p&gt;What I have experienced and want to emphasize, is that plugging your software into existing platforms like Orange (especially ones that have a nice GUI) can increase its visibility and usage, over publishing it solely in a code repository. Decently designed GUIs help users to more quickly understand what your software does which goes a long way to maximizing its value. Platforms like Orange provide a mechanism by which developers can take advantage of these GUI benefits “for free” (well, not really for free, but with &lt;em&gt;much&lt;/em&gt; less time investment than building and designing GUIs from scratch). It frees them up to use their creativity to solve research problems through widget development; it exposes their software to a much wider audience; and it allows users to interact with their software in a more intuitive way.&lt;/p&gt;
&lt;p&gt;In short, platforms like Orange can be extremely useful both for researchers who want to quickly apply computational analyses in the SSH fields (without writing code) and for developers who want to increase the usability, visibility, and sustainability of their software. While it does, to some extent, tie the success of your software to the success of Orange, you are not “putting all your eggs in one basket”. Due to the modularity and already-in-place Python package structure of Orange add-ons and widgets, you can very easily strip the GUI out of your code and release your work as a stand-alone package, or migrate it to another platform.&lt;/p&gt;
&lt;p&gt;If you are interested, my colleague &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;Ji Qi&lt;/a&gt; has written a &lt;a href=&quot;https://medium.com/escience-center/how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chatbot-adventure-with-huggingchat-ded982ac0ef4&quot;&gt;post&lt;/a&gt; about how to get started with Orange add-on development — be sure to check it out!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take home messages&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Orange is an open-source extensible data mining platform that is usable by people with little to no technical experience. If you are a researcher in SSH consider using it for your research. If it doesn’t have a feature you need, &lt;a href=&quot;https://github.com/biolab/orange3/issues&quot;&gt;ask the developers if they can add it as a default feature to Orange&lt;/a&gt;. If they can’t add it, and if you or a colleague has Python experience, consider &lt;a href=&quot;http://jiblogpost/&quot;&gt;creating a custom add-on&lt;/a&gt;. It is surprisingly quick and easy to create one if you know a bit of Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1903.06039.pdf&quot;&gt;Research software sustainability is a challenge&lt;/a&gt;. Building and maintaining communities around the development of research software is hard. Don’t let your software become JAG (&lt;strong&gt;J&lt;/strong&gt; ust- &lt;strong&gt;A&lt;/strong&gt; nother- &lt;strong&gt;G&lt;/strong&gt; ithub repo). Take inspiration for how to avoid this from platforms like Orange. This does not mean that you need to create a graphical user interface for your software. It means: &lt;em&gt;find a home for your software&lt;/em&gt; or &lt;em&gt;find an existing toolbox in which to integrate your software, before creating your own toolbox&lt;/em&gt;. Integrating into existing platforms or packages will probably increase its usage and visibility over publishing as a stand-alone item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #1:&lt;/strong&gt; From the start, consider building software that solves &lt;em&gt;generic&lt;/em&gt; problems in your field. i.e., problems that are shared by others in the field as well, rather than for highly specialized use cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #2:&lt;/strong&gt; Make your software easy to use by as many &lt;em&gt;types&lt;/em&gt; of people as possible. Not just for experienced developers. Also, ensure that someone can rapidly understand what your software does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #3:&lt;/strong&gt; Make it easy for as many people as possible to customize and extend your software.&lt;/li&gt;
&lt;/ol&gt;</description><pubDate>Thu, 12 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;why-arent-more-ssh-researchers-using-and-extending-the-platform&quot;&gt;Why aren’t more SSH researchers using and extending the platform?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://orangedatamining.com/&quot;&gt;Orange&lt;/a&gt; is an open-source &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt; -based &lt;a href=&quot;https://www.britannica.com/technology/data-structure&quot;&gt;data mining&lt;/a&gt; application with a graphical user interface (GUI). It allows people with no knowledge of programming to apply Machine Learning as well as advanced data processing, analysis, and visualization using a point-and-click, drag-and-drop interface. Those who have seen &lt;a href=&quot;https://scratch.mit.edu/&quot;&gt;Scratch&lt;/a&gt; will be familiar with this mode of interaction, although Orange is more advanced and is used for data mining, rather than educational programming. The following screenshot shows what a typical Orange &lt;a href=&quot;https://orangedatamining.com/workflows/&quot;&gt;workflow&lt;/a&gt; looks like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of the Orange3 interface. To the left of screen is the list of loaded add-ons (Toolboxes for data mining). To the right of screen is an example data mining workflow I created consisting of three Orange widgets: one to load data, one to display it in a table format and one for visualising it.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;793&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_P63Kn6BcFaxp2mzdYM-KGw-3d971242.BA8M75pr_Z1sj8eG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of an example data mining workflow in Orange3&lt;/p&gt;
&lt;p&gt;The three small circles labeled ‘File’, ‘Data Table’, and ‘Scatter Plot’ in the image above, are called Orange &lt;a href=&quot;https://docs.biolab.si/orange/2/widgets/rst/index.html&quot;&gt;widgets&lt;/a&gt;. They are the basic building blocks of a data analysis workflow (or pipeline) in Orange. Each widget is a software unit that performs some sort of data processing, analysis, or visualization and potentially has a set of inputs and outputs. You can connect the outputs of some widgets to the inputs of others to create a chain of processing and analysis operations. A great feature of Orange is its extensibility. There are loads of custom plugins for Orange (called &lt;em&gt;add-ons&lt;/em&gt;) developed by researchers and the Orange user community. Add-ons usually comprise multiple widgets. Two mature and extensively used Orange add-ons are &lt;a href=&quot;https://orange3-text.readthedocs.io/en/latest/&quot;&gt;Orange-Text&lt;/a&gt; and &lt;a href=&quot;https://orange3-network.readthedocs.io/en/latest/&quot;&gt;Network&lt;/a&gt; which are used for &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_theory&quot;&gt;network analysis&lt;/a&gt; respectively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Story Navigator: a custom Orange add-on I am developing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am currently in the process of developing an add-on as part of a project with researchers at the &lt;a href=&quot;https://www.utwente.nl/&quot;&gt;University of Twente&lt;/a&gt; in the Netherlands. The add-on is called the &lt;a href=&quot;https://github.com/navigating-stories/orange-story-navigator&quot;&gt;Story Navigator&lt;/a&gt;. The aim of the Story Navigator is to enable computer-aided analysis of written stories for students and researchers who study &lt;a href=&quot;https://en.wikipedia.org/wiki/Narrative_psychology&quot;&gt;narrative psychology&lt;/a&gt;. The add-on has several widgets to analyse different aspects of a story. It uses a combination of &lt;a href=&quot;https://encyclopediaofmath.org/wiki/Natural_language_processing&quot;&gt;natural language processing&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_mining&quot;&gt;text mining&lt;/a&gt;, and general data analysis techniques to implement theories in narrative psychology, such as &lt;a href=&quot;https://natureofwriting.com/courses/introduction-to-rhetoric/lessons/burkes-pentad/&quot;&gt;Burke’s pentad&lt;/a&gt;. Here’s a screen:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_bzPwFl1nsKeO-G9zDQzSpg-a1858653.Av62JrBZ_ZNscwQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of the Story Navigator add-on (not yet released) for Orange3.&lt;/p&gt;
&lt;p&gt;The add-on works by first importing textual stories into the workflow using the existing &lt;a href=&quot;https://orangedatamining.com/widget-catalog/text-mining/importdocuments/&quot;&gt;“Import Documents”&lt;/a&gt; widget from the Orange-Text add-on. Thereafter the researcher can choose a widget from the add-on for analysing some aspects of the imported stories. The actor analysis widget, for example, highlights potential characters in the stories; shows which kinds of actions (verbs) the characters are associated with; and calculates different measures for how central specific characters are to the stories.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;958&quot; height=&quot;578&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_JXuPlOl9CDyxWFD10paxgA-03e51f84.DYhSNI_J_Z2fQd8z.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Quantitative story analysis widgets from the Story Navigator add-on for Orange3.&lt;/p&gt;
&lt;p&gt;While it did take some time to develop the widgets for this add-on, what surprised me is that it took me only about two hours, from scratch, with no prior knowledge of Orange, to develop my first widget that showed up in the Orange3 interface when I started it up. Granted, the widget did not do anything except display. But the return on my two-hour investment was that I could now free up my creativity to develop whatever functionality I wanted in the widget, without having to create my own GUI. In doing so, I got to take advantage of a myriad of benefits including being able to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make my add-on available for anyone to use regardless of their programming knowledge&lt;/li&gt;
&lt;li&gt;Receive development and usage feedback from an existing Orange community about my add-on (without having to further promote the add-on or build another community myself from scratch)&lt;/li&gt;
&lt;li&gt;Demo my plugin to anyone, thanks to the GUI&lt;/li&gt;
&lt;li&gt;Share data analyses made with my add-on with other Orange users — enabling reproducibility (currently &lt;a href=&quot;https://www.nature.com/articles/d41586-019-00067-3&quot;&gt;undergoing a crisis&lt;/a&gt; in science)&lt;/li&gt;
&lt;li&gt;Forget about writing installation instructions — they’re already &lt;a href=&quot;https://orangedatamining.com/blog/2012/11/30/the-easy-way-to-install-add-ons/&quot;&gt;here&lt;/a&gt;!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Despite what some readers might think at this point, I am not an Orange evangelist. In fact, I am not swooning over the capabilities and potential of Orange specifically. Orange does have competing platforms that try to do similar things such as &lt;a href=&quot;https://www.knime.com/&quot;&gt;KNIME&lt;/a&gt; and &lt;a href=&quot;https://www.cs.waikato.ac.nz/ml/weka/&quot;&gt;WEKA&lt;/a&gt; which are both &lt;a href=&quot;https://www.java.com/en/&quot;&gt;Java&lt;/a&gt; -based and therefore inherit some concerns due to &lt;a href=&quot;https://www.tiobe.com/tiobe-index/&quot;&gt;Java’s declining popularity&lt;/a&gt;. Orange itself also has some clear disadvantages, not least of which are the &lt;a href=&quot;https://orangedatamining.com/blog/2012/01/03/parallel-orange/&quot;&gt;scalability issues&lt;/a&gt; and the &lt;a href=&quot;https://orange3-example-addon.readthedocs.io/en/latest/&quot;&gt;add-on development documentation&lt;/a&gt; (the latter is not very accessible for less experienced developers).&lt;/p&gt;
&lt;p&gt;But the point I am trying to make is that I am mostly just inspired by the philosophy behind platforms like these: people coming together to develop and share an extensible “workbench-style” software platform with a user-friendly interface. When I refer to software I don’t mean software that has a highly niche purpose, but software that aims to be an ever-evolving toolbox with the potential to address a multitude of research problems. Where your own creativity is the only limit in terms of contributing to it. Where the knowledge barriers to be able to contribute to it are super low, and where there are no qualifying criteria for those who can experience and benefit from the contributions.&lt;/p&gt;
&lt;p&gt;Orange was developed at the &lt;a href=&quot;https://fri.uni-lj.si/en/laboratory/biolab&quot;&gt;Laboratory for Bioinformatics&lt;/a&gt; at the University of Ljubljana. It makes sense then that most of its user base uses it for data mining in &lt;a href=&quot;https://www.britannica.com/science/bioinformatics&quot;&gt;bioinformatics&lt;/a&gt; (see for instance &lt;a href=&quot;https://www.mdpi.com/2076-3417/11/5/2218&quot;&gt;this study&lt;/a&gt; using Orange for early diagnosis of diabetes). But Orange itself is not at all designed to be domain-specific. Its add-ons and widgets are designed for domain-agnostic data mining (&lt;a href=&quot;https://www.mdpi.com/2076-3417/10/11/3894&quot;&gt;here’s a study&lt;/a&gt; using Orange to predict student performance in higher education). This begs the question, why aren’t more researchers in the Social Sciences and Humanities using it, extending it, or building similar platforms?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What the popular video game&lt;/strong&gt; &lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;&lt;strong&gt;Elder Scrolls&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;has to do with Orange&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bethesda.net/dashboard&quot;&gt;Bethesda Softworks&lt;/a&gt; is a US-based video game development company that is famous for its many franchises, one of which is “ &lt;a href=&quot;https://elderscrolls.bethesda.net/en/&quot;&gt;Elder Scrolls&lt;/a&gt; ”. The games in this franchise are “ &lt;a href=&quot;https://en.wikipedia.org/wiki/Role-playing_game&quot;&gt;RPGs&lt;/a&gt; ” that put the player in control of a character from a fictional fantasy world with the goal to… wait for it… save the world from destruction (if you’re new to the term RPGs imagine a video game based on &lt;a href=&quot;https://www.hbo.com/game-of-thrones&quot;&gt;Game of Thrones&lt;/a&gt; and you’ll get the gist). In 2002, Bethesda released its third installment of Elder Scrolls, called “ &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Elder_Scrolls_III:_Morrowind&quot;&gt;Morrowind&lt;/a&gt; ”. The super interesting part is that they also released software called the &lt;a href=&quot;https://cs.elderscrolls.com/index.php?title=Main_Page&quot;&gt;Elder Scrolls Construction Set&lt;/a&gt; alongside the game. This software allowed players to make customizations to their own copy of the game. They could do things such as create new clothing, buildings, and other items; create their own character voices; make new quests, and customize the color of the sky. These modifications (&lt;em&gt;mods&lt;/em&gt; as they are now commonly referred to) vary in terms of how much software literacy is required in order to build them, but many of them require no more knowledge than being able to install a program and click a few buttons.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;978&quot; height=&quot;513&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_7pZdxrP9AKjQ3F7p-911a47a7.D7mMaqOF_ZoyG2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Fancy introducing Spiderman-suited creatures crawling around a medieval town into your video-gaming experience? Well, someone has already created a mod for this in Skyrim.&lt;/p&gt;
&lt;p&gt;Twenty years later, and Bethesda has become known and celebrated for giving its customers the freedom to customize their gaming experience. &lt;a href=&quot;https://www.nexusmods.com/&quot;&gt;Nexusmods&lt;/a&gt; is one of the prominent hubs for hosting large collections of player-created mods for games by Bethesda and other major video game companies. I quote some jaw-dropping statistics from this site here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We host 477,145 mods for 2,342 games from 118,005 authors serving 41,902,274 members with 8,184,840,124 downloads to date.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In academia, terms like “outputs”, “impact”, “community building” and “community engagement” are often bandied about as performance goals and metrics for work. However, despite their purported importance, these terms are hard to define and measure. But when I look at those numbers, I feel like we don’t need unambiguous definitions for those terms in order to verify that the mod concept ticks all those boxes and then some.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;507&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_SayaBHWxNn7HCpmaU0YmQA-a7da4685.D8UAVMwc_Z1a8U89.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Nexusmods demonstrates that the mod concept is a winner.&lt;/p&gt;
&lt;p&gt;“Okay Kody, what does this all have to do with Orange?”, you may ask. Well, in some ways there are parallels in this story to the concept of Orange as a software platform.&lt;/p&gt;
&lt;p&gt;First, there is a &lt;em&gt;product that many people enjoy&lt;/em&gt; (or find useful). In Bethesda’s case, it is the “vanilla” Elder Scrolls games. In Orange’s case, it is a data mining platform which is a generic tool that is useful regardless of the research domain and data. The GUI aspect of Orange also opens it up to a much larger user base (not just a small group of researchers with development experience working in a niche field).&lt;/p&gt;
&lt;p&gt;Second, there is the &lt;em&gt;enabling of customization.&lt;/em&gt; In Bethesda’s case, it is the provision of customization software such as the &lt;a href=&quot;https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/&quot;&gt;Skyrim Creation Kit&lt;/a&gt;; in the case of Orange, it is the release of the code under an open-source license with reusable example code and plugin-writing tutorials.&lt;/p&gt;
&lt;p&gt;Thirdly, and what I find to be the most critical, is &lt;em&gt;making it easy to customize.&lt;/em&gt; In Bethesda’s case, they have made user-friendly software that does not require extremely specialized skills to use. Almost anyone can create a mod. In Orange’s case, you still need to know how to program to develop add-ons. But you don’t need advanced knowledge of the GUI frameworks that Orange uses — &lt;a href=&quot;https://en.wikipedia.org/wiki/Qt_(software)&quot;&gt;Qt&lt;/a&gt; and &lt;a href=&quot;https://wiki.python.org/moin/PyQt&quot;&gt;PyQt&lt;/a&gt;. In other words, if you know how to create any kind of computational script or software in Python, you can easily create an Orange widget to “house” or “wrap” its functionality. Furthermore, others, regardless of their technical nous, will be able to use it and “chain” your widget with other software in an Orange workflow.&lt;/p&gt;
&lt;p&gt;What I have experienced and want to emphasize, is that plugging your software into existing platforms like Orange (especially ones that have a nice GUI) can increase its visibility and usage, over publishing it solely in a code repository. Decently designed GUIs help users to more quickly understand what your software does which goes a long way to maximizing its value. Platforms like Orange provide a mechanism by which developers can take advantage of these GUI benefits “for free” (well, not really for free, but with &lt;em&gt;much&lt;/em&gt; less time investment than building and designing GUIs from scratch). It frees them up to use their creativity to solve research problems through widget development; it exposes their software to a much wider audience; and it allows users to interact with their software in a more intuitive way.&lt;/p&gt;
&lt;p&gt;In short, platforms like Orange can be extremely useful both for researchers who want to quickly apply computational analyses in the SSH fields (without writing code) and for developers who want to increase the usability, visibility, and sustainability of their software. While it does, to some extent, tie the success of your software to the success of Orange, you are not “putting all your eggs in one basket”. Due to the modularity and already-in-place Python package structure of Orange add-ons and widgets, you can very easily strip the GUI out of your code and release your work as a stand-alone package, or migrate it to another platform.&lt;/p&gt;
&lt;p&gt;If you are interested, my colleague &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-ji-qi/&quot;&gt;Ji Qi&lt;/a&gt; has written a &lt;a href=&quot;https://medium.com/escience-center/how-easy-it-can-be-to-whip-up-your-own-orange3-widget-a-chatbot-adventure-with-huggingchat-ded982ac0ef4&quot;&gt;post&lt;/a&gt; about how to get started with Orange add-on development — be sure to check it out!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take home messages&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Orange is an open-source extensible data mining platform that is usable by people with little to no technical experience. If you are a researcher in SSH consider using it for your research. If it doesn’t have a feature you need, &lt;a href=&quot;https://github.com/biolab/orange3/issues&quot;&gt;ask the developers if they can add it as a default feature to Orange&lt;/a&gt;. If they can’t add it, and if you or a colleague has Python experience, consider &lt;a href=&quot;http://jiblogpost/&quot;&gt;creating a custom add-on&lt;/a&gt;. It is surprisingly quick and easy to create one if you know a bit of Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1903.06039.pdf&quot;&gt;Research software sustainability is a challenge&lt;/a&gt;. Building and maintaining communities around the development of research software is hard. Don’t let your software become JAG (&lt;strong&gt;J&lt;/strong&gt; ust- &lt;strong&gt;A&lt;/strong&gt; nother- &lt;strong&gt;G&lt;/strong&gt; ithub repo). Take inspiration for how to avoid this from platforms like Orange. This does not mean that you need to create a graphical user interface for your software. It means: &lt;em&gt;find a home for your software&lt;/em&gt; or &lt;em&gt;find an existing toolbox in which to integrate your software, before creating your own toolbox&lt;/em&gt;. Integrating into existing platforms or packages will probably increase its usage and visibility over publishing as a stand-alone item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #1:&lt;/strong&gt; From the start, consider building software that solves &lt;em&gt;generic&lt;/em&gt; problems in your field. i.e., problems that are shared by others in the field as well, rather than for highly specialized use cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #2:&lt;/strong&gt; Make your software easy to use by as many &lt;em&gt;types&lt;/em&gt; of people as possible. Not just for experienced developers. Also, ensure that someone can rapidly understand what your software does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspiration point #3:&lt;/strong&gt; Make it easy for as many people as possible to customize and extend your software.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_P63Kn6BcFaxp2mzdYM-KGw-3d971242.BA8M75pr.png" medium="image"/><author>Kody Moodley</author></item><item><title>Analysis-ready climate data with ESMValCore</title><link>https://blog.esciencecenter.nl/posts/2023-10-05---analysis-ready-climate-data-with-esmvalcore</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-10-05---analysis-ready-climate-data-with-esmvalcore</guid><description>&lt;h2 id=&quot;the-easy-ipcc-blog-done-differently&quot;&gt;&lt;strong&gt;The “Easy IPCC” blog done differently&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Co-authored by &lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;Bouwe Andela&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/pangeo/easy-ipcc-part-1-multi-model-datatree-469b87cf9114&quot;&gt;recent blog post&lt;/a&gt;, Tom Nicholas presented a nice walkthrough of reproducing a famous IPCC figure with &lt;code&gt;[xarray-datatree](https://xarray-datatree.readthedocs.io/en/latest/)&lt;/code&gt;. Here, we attempt to achieve the same with ESMValCore — the workflow engine that powers the more widely known &lt;a href=&quot;http://docs.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt;. Both xarray-datatree and ESMValCore facilitate the analysis of large climate datasets, but our approach is quite different. For example, xarray-datatree tries to facilitate any hierarchical file structure (more generic), whereas ESMValCore focuses on facilitating CMIP, or CMIP-like data only (more specific, thus tailored). Seeing them side by side is food for thought.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;770&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-75688b5f.B_CK0meh_Z1NGFQd.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;“&lt;/em&gt;&lt;a href=&quot;https://github.com/zarr-developers/zarr-illustrations-falk-2022/blob/main/1200dpi/kits-deluge-1200dpi.png&quot;&gt;&lt;em&gt;Adam uploads&lt;/em&gt;&lt;/a&gt;*” by &lt;em&gt;&lt;a href=&quot;https://twitter.com/DrHenningFalk&quot;&gt;&lt;em&gt;Henning Falk&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, ©2022 &lt;em&gt;&lt;a href=&quot;https://numfocus.org/&quot;&gt;&lt;em&gt;NumFOCUS&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, is used under a &lt;em&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/&quot;&gt;&lt;em&gt;CC BY 4.0&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; license.*In case you are not familiar: &lt;a href=&quot;https://research-software-directory.org/software/esmvaltool&quot;&gt;ESMValTool&lt;/a&gt; is a software project that was designed by and for climate scientists to evaluate CMIP data in a standardized and reproducible manner (check out a recent blog &lt;a href=&quot;https://blog.esciencecenter.nl/esmvaltool-recipes-for-solid-climate-science-da5b33814f69?sk=c6510256a10d2a35e7e9a723ec4ae0fb&quot;&gt;here&lt;/a&gt;). Several years ago, the project was split in two parts: &lt;a href=&quot;https://research-software-directory.org/software/esmvalcore&quot;&gt;ESMValCore&lt;/a&gt; implements the core functionality, whereas ESMValTool is essentially a big collection of “recipes” to reproduce a wide range of CMIP analytics — including some of the IPCC figures. While ESMValCore has matured as a reliable foundation for the ESMValTool, recent additions also make it attractive as a lightweight alternative to its hefty sibling.&lt;/p&gt;
&lt;p&gt;To give you an impression of ESMValCore’s look and feel, we start with a complete code block that exactly reproduces Tom’s figure. In the remainder of this post, we’ll dive into the details: the dataset interface, automatic ESGF downloads, CMOR checks and fixes, and exporting as recipe, meanwhile touching upon some of the similarities and differences with xarray-datatree. At the end of the blogpost we’ll build an ESMValTool recipe that reproduces the same figure with all available models and ensemble members.&lt;/p&gt;
&lt;p&gt;import cf_units
import matplotlib.pyplot as plt
from iris import quickplot&lt;/p&gt;
&lt;p&gt;from esmvalcore.config import CFG
from esmvalcore.dataset import Dataset
from esmvalcore.preprocessor import annual_statistics, anomalies, area_statistics&lt;/p&gt;
&lt;h1 id=&quot;settings-for-automatic-esgf-search&quot;&gt;Settings for automatic ESGF search&lt;/h1&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘when_missing’&lt;/p&gt;
&lt;h1 id=&quot;declare-common-dataset-facets&quot;&gt;Declare common dataset facets&lt;/h1&gt;
&lt;p&gt;template = Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp= &apos;&lt;em&gt;&apos;, # We’ll fill this below
dataset=&apos;&lt;/em&gt;&apos;,  # We’ll fill this below
ensemble=‘r4i1p1f1’,
grid=‘gn’,
)&lt;/p&gt;
&lt;h1 id=&quot;substitute-data-sources-and-experiments&quot;&gt;Substitute data sources and experiments&lt;/h1&gt;
&lt;p&gt;datasets = []
for dataset_id in [“CESM2”, “MPI-ESM1-2-LR”, “IPSL-CM6A-LR”]:
for experiment_id in [‘ssp126’, ‘ssp585’]:
dataset = template.copy(dataset=dataset_id, exp=[‘historical’, experiment_id])
dataset.add_supplementary(short_name=‘areacello’, mip=‘Ofx’, exp=‘historical’)
dataset.augment_facets()
datasets.append(dataset)&lt;/p&gt;
&lt;h1 id=&quot;set-the-reference-period-for-anomalies&quot;&gt;Set the reference period for anomalies&lt;/h1&gt;
&lt;p&gt;reference_period = {
“start_year”: 1950, “start_month”: 1, “start_day”: 1,
“end_year”: 1979, “end_month”: 12, “end_day”: 31,
}&lt;/p&gt;
&lt;h1 id=&quot;download-pre-process-and-plot-the-cubes&quot;&gt;(Down)load, pre-process, and plot the cubes&lt;/h1&gt;
&lt;p&gt;for dataset in datasets:
cube = dataset.load()
cube = area_statistics(cube, operator=‘mean’)
cube = anomalies(cube, reference=reference_period, period=‘month’)  # notice ‘month’
cube = annual_statistics(cube, operator=‘mean’)
cube.convert_units(‘degrees_C’)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Make sure all datasets use the same calendar for plotting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tcoord = cube.coord(&apos;time&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tcoord.units = cf_units.Unit(tcoord.units.origin, calendar=&apos;gregorian&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Plot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;quickplot.plot(cube, label=f&quot;{dataset[&apos;dataset&apos;]} - {dataset[&apos;exp&apos;]}&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;show-the-plot&quot;&gt;Show the plot&lt;/h1&gt;
&lt;p&gt;plt.legend()
plt.show()
&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;554&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-02171093.CmC3M12p_3bLXz.webp&quot; srcset=&quot;&quot;&gt;
The famous IPCC figure from Tom’s blogpost reproduced with ESMValCore.Cool! This looks exactly like the figure in Tom’s post 🎉. With roughly the same amount of code. If you haven’t read Tom’s post, this figure shows the historical and projected rise in sea-surface temperature from different climate models and future emission scenario’s.&lt;/p&gt;
&lt;h3 id=&quot;key-takeaway-&quot;&gt;Key takeaway **🔑&lt;/h3&gt;
&lt;p&gt;If there is one thing to note from this little script, it is how “scientifically meaningful” it is. For example, we never got to see actual files. We simply defined our datasets with meaningful &lt;em&gt;facets&lt;/em&gt;, as described in the CMIP &lt;a href=&quot;https://github.com/WCRP-CMIP/CMIP6_CVs&quot;&gt;controlled vocabulary&lt;/a&gt;. In the background, ESMValCore located the corresponding files on ESGF, downloaded them to our local environment (if we didn’t have them yet), loaded them into memory, checked adherence to the CMOR conventions, and applied fixes for known issues. But those are technical details, not science.&lt;/p&gt;
&lt;p&gt;ESMValCore, in the spirit of ESMValTool, focuses very much on &lt;em&gt;what&lt;/em&gt; to do, instead of &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-inner-workings-️&quot;&gt;**The inner workings **⚙️&lt;/h2&gt;
&lt;p&gt;It’s worth dissecting *how *ESMValCore does things, though. Firstly because you’ll need some understanding to wield it effectively. But mostly because we scientists are often trying to solve the same problems, so it’s interesting to see how ESMValCore tackles some of these issues so you don’t have to.&lt;/p&gt;
&lt;h3 id=&quot;configuration&quot;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;ESMValCore works with a configuration file. This is where you store information about, for example, how your data is organized on disk. The defaults are pretty good, we only had to enable automatic downloads. Let’s have a look at some of the other settings.&lt;/p&gt;
&lt;p&gt;print({key: CFG[key] **       for key in [‘download_dir’, ‘drs’, ‘output_dir’, ‘rootpath’]
}){
‘download_dir’: PosixPath(‘/home/peter/climate_data’),
‘drs’: {‘CMIP3’: ‘ESGF’, ‘CMIP5’: ‘ESGF’, ‘CMIP6’: ‘ESGF’, ‘CORDEX’: ‘ESGF’, ‘obs4MIPs’: ‘ESGF’},
‘output_dir’: PosixPath(‘/home/peter/esmvaltool_output’),
‘rootpath’: {‘default’: [PosixPath(‘/home/peter/climate_data’)]}
}The default configuration specifies that data will be downloaded to a folder called &lt;code&gt;climate data&lt;/code&gt; in my home directory. The &lt;code&gt;rootpath&lt;/code&gt; setting specifies all folders where ESMValCore should look for data, and it is set to the same default. Finally, ESMValCore defines a dedicated folder to store output. Every ESMValTool run or session will get its own subdirectory in there.&lt;/p&gt;
&lt;p&gt;The key point here is that you don’t have to worry about data management. You can configure some folders if you want to, but even that is not strictly necessary. If you’re working on dedicated climate data infrastructure such as Jasmin or DKRZ, you can also configure ESMValCore to use the Data Reference Syntax (DRS, the filenames + folder structure) used on these machines.&lt;/p&gt;
&lt;h3 id=&quot;data-discovery-&quot;&gt;Data discovery **🔍&lt;/h3&gt;
&lt;p&gt;Let’s have a closer look at the dataset definition. What happened, for example, when we called &lt;code&gt;augment_facets&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;dataset = Dataset(**    short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=‘historical’,
dataset=‘CESM2’,
ensemble=‘r4i1p1f1’,
grid=‘gn’,
)
dataset.augment_facets()
print(dataset)Dataset:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Omon’,
‘short_name’: ‘tos’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘mon’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Sea Surface Temperature’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘tos’,
‘standard_name’: ‘sea_surface_temperature’,
‘units’: ‘degC’}
session: ‘session-405b0393-0e28-4dae-836e-0d5961e3d30b_20230609_084132’ESMValCore auto-completed our &lt;code&gt;Dataset&lt;/code&gt; based on the information it got from the &lt;a href=&quot;https://github.com/PCMDI/cmip6-cmor-tables&quot;&gt;CMOR tables&lt;/a&gt;. With this specification, ESMValCore can automatically search both your local filesystem and the ESGF for available copies of the dataset. Let’s make things a bit more interesting, and look for all available ensemble members. The &lt;code&gt;from_files()&lt;/code&gt; method is used to build a list of available dataset based on the search fields.&lt;/p&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘always’
dataset_search = Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=‘historical’,
dataset=‘CESM2’,
ensemble=’*’,
grid=‘gn’,
)
ensemble_datasets = list(dataset_search.from_files())&lt;/p&gt;
&lt;p&gt;print([ds[‘ensemble’] for dataset in ensemble_datasets])[
‘r10i1p1f1’,
‘r11i1p1f1’,
‘r1i1p1f1’,
‘r2i1p1f1’,
‘r3i1p1f1’,
‘r4i1p1f1’,
‘r5i1p1f1’,
‘r6i1p1f1’,
‘r7i1p1f1’,
‘r8i1p1f1’,
‘r9i1p1f1’
]Apparently there’s 11 ensemble members available for this model.&lt;/p&gt;
&lt;p&gt;The wildcard search functionality ( &lt;code&gt;&apos;*&apos;&lt;/code&gt; ) is incredibly useful, as there are often inconsistencies in availability between datasets. Asking for ensemble member 1 through 11 may work for CESM2 today, but not for another model, or it may be different tomorrow.&lt;/p&gt;
&lt;p&gt;What if we wanted to plot all *available data?&lt;/p&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘always’
dataset_search= Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=[‘historical’, ‘ssp585’],
dataset=&apos;&lt;em&gt;&apos;,
ensemble=&apos;&lt;/em&gt;&apos;,
institute=’*’,
grid=‘gn’,
)
all_of_cmip = list(dataset_search.from_files())
print(len(all_of_cmip))821That’s a lot of datasets! We’ll save that for the end of the post.&lt;/p&gt;
&lt;h3 id=&quot;adding-supplementary-information&quot;&gt;Adding supplementary information**&lt;/h3&gt;
&lt;p&gt;To arrive at global mean temperature, we needed to calculate an area-weighted average. The data for ocean temperature comes at the native model grid, which is irregular and the grid cell area is not easily obtained. To address exactly this issue, the CF conventions include a specification of &lt;a href=&quot;http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/build/ch07s02.html&quot;&gt;cell measures&lt;/a&gt;. ESMValCore supports this functionality and makes it easy to add cell measures to a dataset. In our case, we need the variable called &lt;code&gt;areacello&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;discard-augmented-facets-as-they-will-be-different-for-areacellodataset--datasetdatasetminimal_facets&quot;&gt;Discard augmented facets as they will be different for areacello**dataset = Dataset(**dataset.minimal_facets)&lt;/h1&gt;
&lt;h1 id=&quot;add-areacello-as-supplementary-dataset&quot;&gt;Add areacello as supplementary dataset&lt;/h1&gt;
&lt;p&gt;dataset.add_supplementary(short_name=‘areacello’, mip=‘Ofx’)&lt;/p&gt;
&lt;h1 id=&quot;autocomplete-and-inspect&quot;&gt;Autocomplete and inspect&lt;/h1&gt;
&lt;p&gt;dataset.augment_facets()
print(dataset.summary())Dataset:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Omon’,
‘short_name’: ‘tos’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘mon’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Sea Surface Temperature’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘tos’,
‘standard_name’: ‘sea_surface_temperature’,
‘units’: ‘degC’}
supplementaries:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Ofx’,
‘short_name’: ‘areacello’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘fx’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Grid-Cell Area for Ocean Variables’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘areacello’,
‘standard_name’: ‘cell_area’,
‘units’: ‘m2’}
session: ‘session-ccace7d0-dc3b-4e03-87ea-2716aa127618_20230609_085322’These ancillary datasets are not always consistently available for each variant of a dataset. ESMValCore includes some convenience functionality that tries to find a matching variable if the exact match is not available. For example, it may take the grid cell area from another ensemble member. In this case, it looks like we have an exact match.&lt;/p&gt;
&lt;h3 id=&quot;data-downloading&quot;&gt;Data (down)loading**&lt;/h3&gt;
&lt;p&gt;We now arrive at the part of the script that calls &lt;code&gt;dataset.load()&lt;/code&gt;. In the background, ESMValCore automatically located the files on ESGF and downloaded them for us. Let’s illustrate this.&lt;/p&gt;
&lt;h1 id=&quot;before-loadprintdatasetfiles&quot;&gt;Before load**print(dataset.files)[&lt;/h1&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r4i1p1f1/Omon/tos/gn/v20190308/tos_Omon_CESM2_historical_r4i1p1f1_gn_&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;185001-201412.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’,
‘esgf3.dkrz.de’]
]# After load (and re-defining the dataset to trigger a new search)
print(dataset.files)[LocalFile(‘/home/peter/climate_data/CMIP6/CMIP/NCAR/CESM2/historical/r4i1p1f1/Omon/tos/gn/v20190308/tos_Omon_CESM2_historical_r4i1p1f1_gn_185001-201412.nc’)]Notice that there were copies of this file available on 5 different ESGF nodes. ESMValCore automatically selects the fastest available server and stored the dataset according to the standard CMOR data reference syntax.&lt;/p&gt;
&lt;p&gt;For our example dataset, all the data is apparently contained within one file. However, it’s not always like this. If we look, for example, at another ensemble member, we can see that it is stored in chunks of 50 years:&lt;/p&gt;
&lt;p&gt;print(ensemble_datasets[1].files)[ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_185001-189912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_190001-194912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_195001-199912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_200001-201412.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’]]In this case, ESMValCore automatically concatenates the data for us.&lt;/p&gt;
&lt;p&gt;You may have noticed that we assigned the result of the &lt;code&gt;load&lt;/code&gt; method to a new variable called &lt;code&gt;cube&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;cube = dataset.load()Under the hood, ESMValCore uses &lt;code&gt;[iris](https://scitools-iris.readthedocs.io)&lt;/code&gt; to represent data cubes. Compared to &lt;code&gt;xarray&lt;/code&gt;, &lt;code&gt;iris&lt;/code&gt; is more strict on checking adherence to CF conventions. This can make it harder to work with, but it also acts as a safeguard against unexpected behaviour.&lt;/p&gt;
&lt;p&gt;Where Tom used &lt;a href=&quot;https://cmip6-preprocessing.readthedocs.io&quot;&gt;xMIP&lt;/a&gt;, ESMValCore comes with builtin checks and if there are any (known) issues with the datasets, it automatically fixes them. Also, it automatically loads all supplementary datasets. Notice how the cell area is present as a cell measure.&lt;/p&gt;
&lt;p&gt;print(cube)sea_surface_temperature / (degC)          (time: 1980; cell index along second dimension: 384; cell index along first dimension: 320)
Dimension coordinates:
time                                   x                                        -                          -
cell index along second dimension      -                                        x                          -
cell index along first dimension       -                                        -                          x
Auxiliary coordinates:
latitude                               -                                        x                          x
longitude                              -                                        x                          x
Cell measures:
cell_area                              -                                        x                          x
Cell methods:
mean where sea                    area
mean                              time
Attributes:
Conventions                       ‘CF-1.7 CMIP-6.2’
activity_id                       ‘CMIP’
branch_method                     ‘standard’
branch_time_in_child              0
branch_time_in_parent             -492385
case_id                           ‘18’
cesm_casename                     ‘b.e21.BHIST.f09_g17.CMIP6-historical.004’
contact                           ‘&lt;a href=&quot;mailto:cesm_cmip6@ucar.edu&quot;&gt;cesm_cmip6@ucar.edu&lt;/a&gt;’
data_specs_version                ‘01.00.29’
description                       ‘This may differ from “surface temperature” in regions of sea ice or floating …’
experiment                        ‘all-forcing simulation of the recent past’
experiment_id                     ‘historical’
external_variables                ‘areacello’
forcing_index                     1
frequency                         ‘mon’
further_info_url                  ‘&lt;a href=&quot;https://furtherinfo.es-doc.org/CMIP6.NCAR.CESM2.historical.none.r4i1p1&quot;&gt;https://furtherinfo.es-doc.org/CMIP6.NCAR.CESM2.historical.none.r4i1p1&lt;/a&gt; …’
grid                              ‘native gx1v7 displaced pole grid (384x320 latxlon)’
grid_label                        ‘gn’
id                                ‘tos’
initialization_index              1
institution                       ‘National Center for Atmospheric Research, Climate and Global Dynamics Laboratory, …’
institution_id                    ‘NCAR’
license                           ‘CMIP6 model data produced by &amp;#x3C;The National Center for Atmospheric Research&gt; …’
mipTable                          ‘Omon’
mip_era                           ‘CMIP6’
model_doi_url                     ‘&lt;a href=&quot;https://doi.org/10.5065/D67H1H0V&quot;&gt;https://doi.org/10.5065/D67H1H0V&lt;/a&gt;’
nominal_resolution                ‘100 km’
out_name                          ‘tos’
parent_activity_id                ‘CMIP’
parent_experiment_id              ‘piControl’
parent_mip_era                    ‘CMIP6’
parent_source_id                  ‘CESM2’
parent_time_units                 ‘days since 1850-1-1 00:00:00’
parent_variant_label              ‘r1i1p1f1’
physics_index                     1
product                           ‘model-output’
prov                              ‘Omon ((isd.003))’
realization_index                 4
realm                             ‘ocean’
source                            ‘CESM2 (2017): atmosphere: CAM6 (0.9x1.25 finite volume grid; 288 x 192 …’
source_id                         ‘CESM2’
source_type                       ‘AOGCM BGC’
sub_experiment                    ‘none’
sub_experiment_id                 ‘none’
table_id                          ‘Omon’
time                              ‘time’
time_label                        ‘time-mean’
time_title                        ‘Temporal mean’
title                             ‘Sea Surface Temperature’
type                              ‘real’
variable_id                       ‘tos’
variant_info                      ‘CMIP6 20th century experiments (1850-2014) with CAM6, interactive land …’
variant_label                     ‘r4i1p1f1’&lt;/p&gt;
&lt;h3 id=&quot;pre-processing-️&quot;&gt;Pre-processing **🛠️&lt;/h3&gt;
&lt;p&gt;ESMValCore comes with a &lt;a href=&quot;https://docs.esmvaltool.org/projects/ESMValCore/en/latest/api/esmvalcore.preprocessor.html&quot;&gt;large suite&lt;/a&gt; of built-in preprocessing functions. These functions have been designed as scientifically sound default implementations for frequently performed operations. An important idea underpinning ESMValCore (&amp;#x26;Tool)’s philosophy is that standardization facilitates comparison between, and reproducibility of, our data analysis workflows. Moreover, by bundling our efforts we can develop high quality preprocessor functions more effectively. In that spirit it would be good to see how xMIP could be integrated with ESMValCore’s CMOR checks and fixes.&lt;/p&gt;
&lt;p&gt;We won’t go into detail on each of the preprocessing functions applied above, as they’re fairly self-explanatory. One thing to highlight though, is that in our calculation of anomalies, we deviated a little bit from Tom’s method. He subtracted the overall average of 1950–1980; we used monthly means over that period. It’s not really necessary here, but it facilitates comparing changes in summer temperature, for example 😎.&lt;/p&gt;
&lt;p&gt;cube = area_statistics(cube, operator=‘mean’)**cube = anomalies(cube, reference=reference_period, period=‘month’)
cube = annual_statistics(cube, operator=‘mean’)
cube.convert_units(‘degrees_C’)&lt;/p&gt;
&lt;h3 id=&quot;custom-code&quot;&gt;Custom code**&lt;/h3&gt;
&lt;p&gt;Up to this point, everything we’ve done was “pure” ESMValCore. However, in every data analysis workflow, there comes a point where you want to do custom things. In the traditional context of ESMValTool, such custom code would be added as a “diagnostic script”. In the context of this notebook, we can simply start working with the cube in whatever way we like.&lt;/p&gt;
&lt;p&gt;This can be a good moment to thank iris for its services, and continue with xarray if you prefer. For example:&lt;/p&gt;
&lt;p&gt;import xarray as xr**da = xr.DataArray.from_iris(cube)
da.plot()
print(da)&amp;#x3C;xarray.DataArray ‘tos’ (time: 165)&gt;
dask.array&amp;#x3C;filled, shape=(165,), dtype=float32, chunksize=(1,), chunktype=numpy.ndarray&gt;
Coordinates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;time     (time) object 1850-07-02 13:00:00.000001 … 2014-07-02 12:00:00
nlon     int64 …
nlat     int64 …
lat      float64 …
lon      float64 …
year     (time) int64 …
Attributes: (12/57)
standard_name:          sea_surface_temperature
long_name:              Sea Surface Temperature
units:                  degrees_C
Conventions:            CF-1.7 CMIP-6.2
activity_id:            CMIP
case_id:                18
…                     …
time:                   time
time_label:             time-mean
time_title:             Temporal mean
title:                  Sea Surface Temperature
type:                   real
cell_methods:           area: mean where sea time: mean longitude: latitu…
&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;595&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-7d340529.qacNBbLZ_Z1kY9o1.webp&quot; srcset=&quot;&quot;&gt;
The change in sea-surface temperature as plotted by xarray’s builtin plot method.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;reproducibility-convert-to-recipe&quot;&gt;Reproducibility: convert to recipe**&lt;/h2&gt;
&lt;p&gt;Traditionally, ESMValTool was designed to work with recipes: static, human-readable files that declare a worfklow from start to finish. This comes back to what we said earlier about describing &lt;em&gt;what&lt;/em&gt; to do instead of &lt;em&gt;how&lt;/em&gt;. ESMValCore helps us to start building a recipe. With the following code, we can generate the &lt;code&gt;datasets&lt;/code&gt; and &lt;code&gt;diagnostics&lt;/code&gt; sections of the recipe:&lt;/p&gt;
&lt;p&gt;from esmvalcore.dataset import datasets_to_recipe**import yaml&lt;/p&gt;
&lt;p&gt;for dataset in ensemble_datasets:
dataset.facets[‘diagnostic’] = ‘easy_ipcc’
print(yaml.safe_dump(datasets_to_recipe(datasets)))datasets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dataset: CESM2
ensemble: r4i1p1f1
institute: NCAR&lt;/li&gt;
&lt;li&gt;dataset: IPSL-CM6A-LR
ensemble: r4i1p1f1
institute: IPSL&lt;/li&gt;
&lt;li&gt;dataset: MPI-ESM1-2-LR
ensemble: r4i1p1f1
institute: MPI-M&lt;/li&gt;
&lt;li&gt;dataset: TaiESM1
ensemble: r1i1p1f1
institute: AS-RCEC&lt;/li&gt;
&lt;li&gt;dataset: AWI-CM-1-1-MR
ensemble: r(1:5)i1p1f1
institute: AWI&lt;/li&gt;
&lt;li&gt;dataset: AWI-ESM-1-1-LR
ensemble: r1i1p1f1
institute: AWI&lt;/li&gt;
&lt;li&gt;dataset: BCC-CSM2-MR
ensemble: r(1:3)i1p1f1
institute: BCC
…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;diagnostics:
easy_ipcc:
variables:
tos:
exp:
- historical
- ssp585
grid: gn
mip: Omon
project: CMIP6You still have to add the preprocessors and some metadata (a short description etc.). We envision a workflow where you use ESMValCore interactively for most of your exploratory work, and then port it to a recipe for sharing and reproducibility.&lt;/p&gt;
&lt;p&gt;To complete this post, we’ve gone ahead and extended the recipe above to include all the available CMIP6 data and make a nice plot. As you might expect, this required more labour due to dataset issues for which no fixes were available, and a bit of extra tinkering to make the figure look more like the IPCC version. You can find the corresponding recipe and diagnostic script &lt;a href=&quot;https://github.com/ESMValGroup/ESMValTool/pull/3356&quot;&gt;here&lt;/a&gt;. Be careful with running it, though! This recipe will try to download almost twenty-thousand files… Running this on the German climate compute service, we get the following figure:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-3815e0c2.CnP8Bhji_ZGVqem.webp&quot; srcset=&quot;&quot;&gt;
This image includes all available models &amp;#x26; ensemble members.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary**&lt;/h2&gt;
&lt;p&gt;ESMValCore is great addition to any climate analysis toolbox. Its key strengths are its its approach to streamlining workflows to achieve scientific rigor and reproducibility, and its tight integration with the ESGF and CMOR standards.&lt;/p&gt;
&lt;p&gt;If you regularly work with CMIP data, sometimes struggle to retrieve data from ESGF, frequently encounter incompatible datasets, or want to make your workflows available to others, you should definitely give it a shot.&lt;/p&gt;</description><pubDate>Thu, 05 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-easy-ipcc-blog-done-differently&quot;&gt;&lt;strong&gt;The “Easy IPCC” blog done differently&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Co-authored by &lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;Bouwe Andela&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/pangeo/easy-ipcc-part-1-multi-model-datatree-469b87cf9114&quot;&gt;recent blog post&lt;/a&gt;, Tom Nicholas presented a nice walkthrough of reproducing a famous IPCC figure with &lt;code&gt;[xarray-datatree](https://xarray-datatree.readthedocs.io/en/latest/)&lt;/code&gt;. Here, we attempt to achieve the same with ESMValCore — the workflow engine that powers the more widely known &lt;a href=&quot;http://docs.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt;. Both xarray-datatree and ESMValCore facilitate the analysis of large climate datasets, but our approach is quite different. For example, xarray-datatree tries to facilitate any hierarchical file structure (more generic), whereas ESMValCore focuses on facilitating CMIP, or CMIP-like data only (more specific, thus tailored). Seeing them side by side is food for thought.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;770&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-75688b5f.B_CK0meh_Z1NGFQd.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;“&lt;/em&gt;&lt;a href=&quot;https://github.com/zarr-developers/zarr-illustrations-falk-2022/blob/main/1200dpi/kits-deluge-1200dpi.png&quot;&gt;&lt;em&gt;Adam uploads&lt;/em&gt;&lt;/a&gt;*” by &lt;em&gt;&lt;a href=&quot;https://twitter.com/DrHenningFalk&quot;&gt;&lt;em&gt;Henning Falk&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, ©2022 &lt;em&gt;&lt;a href=&quot;https://numfocus.org/&quot;&gt;&lt;em&gt;NumFOCUS&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, is used under a &lt;em&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/&quot;&gt;&lt;em&gt;CC BY 4.0&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; license.*In case you are not familiar: &lt;a href=&quot;https://research-software-directory.org/software/esmvaltool&quot;&gt;ESMValTool&lt;/a&gt; is a software project that was designed by and for climate scientists to evaluate CMIP data in a standardized and reproducible manner (check out a recent blog &lt;a href=&quot;https://blog.esciencecenter.nl/esmvaltool-recipes-for-solid-climate-science-da5b33814f69?sk=c6510256a10d2a35e7e9a723ec4ae0fb&quot;&gt;here&lt;/a&gt;). Several years ago, the project was split in two parts: &lt;a href=&quot;https://research-software-directory.org/software/esmvalcore&quot;&gt;ESMValCore&lt;/a&gt; implements the core functionality, whereas ESMValTool is essentially a big collection of “recipes” to reproduce a wide range of CMIP analytics — including some of the IPCC figures. While ESMValCore has matured as a reliable foundation for the ESMValTool, recent additions also make it attractive as a lightweight alternative to its hefty sibling.&lt;/p&gt;
&lt;p&gt;To give you an impression of ESMValCore’s look and feel, we start with a complete code block that exactly reproduces Tom’s figure. In the remainder of this post, we’ll dive into the details: the dataset interface, automatic ESGF downloads, CMOR checks and fixes, and exporting as recipe, meanwhile touching upon some of the similarities and differences with xarray-datatree. At the end of the blogpost we’ll build an ESMValTool recipe that reproduces the same figure with all available models and ensemble members.&lt;/p&gt;
&lt;p&gt;import cf_units
import matplotlib.pyplot as plt
from iris import quickplot&lt;/p&gt;
&lt;p&gt;from esmvalcore.config import CFG
from esmvalcore.dataset import Dataset
from esmvalcore.preprocessor import annual_statistics, anomalies, area_statistics&lt;/p&gt;
&lt;h1 id=&quot;settings-for-automatic-esgf-search&quot;&gt;Settings for automatic ESGF search&lt;/h1&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘when_missing’&lt;/p&gt;
&lt;h1 id=&quot;declare-common-dataset-facets&quot;&gt;Declare common dataset facets&lt;/h1&gt;
&lt;p&gt;template = Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp= &apos;&lt;em&gt;&apos;, # We’ll fill this below
dataset=&apos;&lt;/em&gt;&apos;,  # We’ll fill this below
ensemble=‘r4i1p1f1’,
grid=‘gn’,
)&lt;/p&gt;
&lt;h1 id=&quot;substitute-data-sources-and-experiments&quot;&gt;Substitute data sources and experiments&lt;/h1&gt;
&lt;p&gt;datasets = []
for dataset_id in [“CESM2”, “MPI-ESM1-2-LR”, “IPSL-CM6A-LR”]:
for experiment_id in [‘ssp126’, ‘ssp585’]:
dataset = template.copy(dataset=dataset_id, exp=[‘historical’, experiment_id])
dataset.add_supplementary(short_name=‘areacello’, mip=‘Ofx’, exp=‘historical’)
dataset.augment_facets()
datasets.append(dataset)&lt;/p&gt;
&lt;h1 id=&quot;set-the-reference-period-for-anomalies&quot;&gt;Set the reference period for anomalies&lt;/h1&gt;
&lt;p&gt;reference_period = {
“start_year”: 1950, “start_month”: 1, “start_day”: 1,
“end_year”: 1979, “end_month”: 12, “end_day”: 31,
}&lt;/p&gt;
&lt;h1 id=&quot;download-pre-process-and-plot-the-cubes&quot;&gt;(Down)load, pre-process, and plot the cubes&lt;/h1&gt;
&lt;p&gt;for dataset in datasets:
cube = dataset.load()
cube = area_statistics(cube, operator=‘mean’)
cube = anomalies(cube, reference=reference_period, period=‘month’)  # notice ‘month’
cube = annual_statistics(cube, operator=‘mean’)
cube.convert_units(‘degrees_C’)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Make sure all datasets use the same calendar for plotting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tcoord = cube.coord(&apos;time&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tcoord.units = cf_units.Unit(tcoord.units.origin, calendar=&apos;gregorian&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Plot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;quickplot.plot(cube, label=f&quot;{dataset[&apos;dataset&apos;]} - {dataset[&apos;exp&apos;]}&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;show-the-plot&quot;&gt;Show the plot&lt;/h1&gt;
&lt;p&gt;plt.legend()
plt.show()
&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;554&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-02171093.CmC3M12p_3bLXz.webp&quot; srcset=&quot;&quot;&gt;
The famous IPCC figure from Tom’s blogpost reproduced with ESMValCore.Cool! This looks exactly like the figure in Tom’s post 🎉. With roughly the same amount of code. If you haven’t read Tom’s post, this figure shows the historical and projected rise in sea-surface temperature from different climate models and future emission scenario’s.&lt;/p&gt;
&lt;h3 id=&quot;key-takeaway-&quot;&gt;Key takeaway **🔑&lt;/h3&gt;
&lt;p&gt;If there is one thing to note from this little script, it is how “scientifically meaningful” it is. For example, we never got to see actual files. We simply defined our datasets with meaningful &lt;em&gt;facets&lt;/em&gt;, as described in the CMIP &lt;a href=&quot;https://github.com/WCRP-CMIP/CMIP6_CVs&quot;&gt;controlled vocabulary&lt;/a&gt;. In the background, ESMValCore located the corresponding files on ESGF, downloaded them to our local environment (if we didn’t have them yet), loaded them into memory, checked adherence to the CMOR conventions, and applied fixes for known issues. But those are technical details, not science.&lt;/p&gt;
&lt;p&gt;ESMValCore, in the spirit of ESMValTool, focuses very much on &lt;em&gt;what&lt;/em&gt; to do, instead of &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-inner-workings-️&quot;&gt;**The inner workings **⚙️&lt;/h2&gt;
&lt;p&gt;It’s worth dissecting *how *ESMValCore does things, though. Firstly because you’ll need some understanding to wield it effectively. But mostly because we scientists are often trying to solve the same problems, so it’s interesting to see how ESMValCore tackles some of these issues so you don’t have to.&lt;/p&gt;
&lt;h3 id=&quot;configuration&quot;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;ESMValCore works with a configuration file. This is where you store information about, for example, how your data is organized on disk. The defaults are pretty good, we only had to enable automatic downloads. Let’s have a look at some of the other settings.&lt;/p&gt;
&lt;p&gt;print({key: CFG[key] **       for key in [‘download_dir’, ‘drs’, ‘output_dir’, ‘rootpath’]
}){
‘download_dir’: PosixPath(‘/home/peter/climate_data’),
‘drs’: {‘CMIP3’: ‘ESGF’, ‘CMIP5’: ‘ESGF’, ‘CMIP6’: ‘ESGF’, ‘CORDEX’: ‘ESGF’, ‘obs4MIPs’: ‘ESGF’},
‘output_dir’: PosixPath(‘/home/peter/esmvaltool_output’),
‘rootpath’: {‘default’: [PosixPath(‘/home/peter/climate_data’)]}
}The default configuration specifies that data will be downloaded to a folder called &lt;code&gt;climate data&lt;/code&gt; in my home directory. The &lt;code&gt;rootpath&lt;/code&gt; setting specifies all folders where ESMValCore should look for data, and it is set to the same default. Finally, ESMValCore defines a dedicated folder to store output. Every ESMValTool run or session will get its own subdirectory in there.&lt;/p&gt;
&lt;p&gt;The key point here is that you don’t have to worry about data management. You can configure some folders if you want to, but even that is not strictly necessary. If you’re working on dedicated climate data infrastructure such as Jasmin or DKRZ, you can also configure ESMValCore to use the Data Reference Syntax (DRS, the filenames + folder structure) used on these machines.&lt;/p&gt;
&lt;h3 id=&quot;data-discovery-&quot;&gt;Data discovery **🔍&lt;/h3&gt;
&lt;p&gt;Let’s have a closer look at the dataset definition. What happened, for example, when we called &lt;code&gt;augment_facets&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;dataset = Dataset(**    short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=‘historical’,
dataset=‘CESM2’,
ensemble=‘r4i1p1f1’,
grid=‘gn’,
)
dataset.augment_facets()
print(dataset)Dataset:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Omon’,
‘short_name’: ‘tos’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘mon’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Sea Surface Temperature’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘tos’,
‘standard_name’: ‘sea_surface_temperature’,
‘units’: ‘degC’}
session: ‘session-405b0393-0e28-4dae-836e-0d5961e3d30b_20230609_084132’ESMValCore auto-completed our &lt;code&gt;Dataset&lt;/code&gt; based on the information it got from the &lt;a href=&quot;https://github.com/PCMDI/cmip6-cmor-tables&quot;&gt;CMOR tables&lt;/a&gt;. With this specification, ESMValCore can automatically search both your local filesystem and the ESGF for available copies of the dataset. Let’s make things a bit more interesting, and look for all available ensemble members. The &lt;code&gt;from_files()&lt;/code&gt; method is used to build a list of available dataset based on the search fields.&lt;/p&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘always’
dataset_search = Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=‘historical’,
dataset=‘CESM2’,
ensemble=’*’,
grid=‘gn’,
)
ensemble_datasets = list(dataset_search.from_files())&lt;/p&gt;
&lt;p&gt;print([ds[‘ensemble’] for dataset in ensemble_datasets])[
‘r10i1p1f1’,
‘r11i1p1f1’,
‘r1i1p1f1’,
‘r2i1p1f1’,
‘r3i1p1f1’,
‘r4i1p1f1’,
‘r5i1p1f1’,
‘r6i1p1f1’,
‘r7i1p1f1’,
‘r8i1p1f1’,
‘r9i1p1f1’
]Apparently there’s 11 ensemble members available for this model.&lt;/p&gt;
&lt;p&gt;The wildcard search functionality ( &lt;code&gt;&apos;*&apos;&lt;/code&gt; ) is incredibly useful, as there are often inconsistencies in availability between datasets. Asking for ensemble member 1 through 11 may work for CESM2 today, but not for another model, or it may be different tomorrow.&lt;/p&gt;
&lt;p&gt;What if we wanted to plot all *available data?&lt;/p&gt;
&lt;p&gt;CFG[‘search_esgf’] = ‘always’
dataset_search= Dataset(
short_name=‘tos’,
mip=‘Omon’,
project=‘CMIP6’,
exp=[‘historical’, ‘ssp585’],
dataset=&apos;&lt;em&gt;&apos;,
ensemble=&apos;&lt;/em&gt;&apos;,
institute=’*’,
grid=‘gn’,
)
all_of_cmip = list(dataset_search.from_files())
print(len(all_of_cmip))821That’s a lot of datasets! We’ll save that for the end of the post.&lt;/p&gt;
&lt;h3 id=&quot;adding-supplementary-information&quot;&gt;Adding supplementary information**&lt;/h3&gt;
&lt;p&gt;To arrive at global mean temperature, we needed to calculate an area-weighted average. The data for ocean temperature comes at the native model grid, which is irregular and the grid cell area is not easily obtained. To address exactly this issue, the CF conventions include a specification of &lt;a href=&quot;http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/build/ch07s02.html&quot;&gt;cell measures&lt;/a&gt;. ESMValCore supports this functionality and makes it easy to add cell measures to a dataset. In our case, we need the variable called &lt;code&gt;areacello&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;discard-augmented-facets-as-they-will-be-different-for-areacellodataset--datasetdatasetminimal_facets&quot;&gt;Discard augmented facets as they will be different for areacello**dataset = Dataset(**dataset.minimal_facets)&lt;/h1&gt;
&lt;h1 id=&quot;add-areacello-as-supplementary-dataset&quot;&gt;Add areacello as supplementary dataset&lt;/h1&gt;
&lt;p&gt;dataset.add_supplementary(short_name=‘areacello’, mip=‘Ofx’)&lt;/p&gt;
&lt;h1 id=&quot;autocomplete-and-inspect&quot;&gt;Autocomplete and inspect&lt;/h1&gt;
&lt;p&gt;dataset.augment_facets()
print(dataset.summary())Dataset:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Omon’,
‘short_name’: ‘tos’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘mon’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Sea Surface Temperature’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘tos’,
‘standard_name’: ‘sea_surface_temperature’,
‘units’: ‘degC’}
supplementaries:
{‘dataset’: ‘CESM2’,
‘project’: ‘CMIP6’,
‘mip’: ‘Ofx’,
‘short_name’: ‘areacello’,
‘activity’: ‘CMIP’,
‘ensemble’: ‘r4i1p1f1’,
‘exp’: ‘historical’,
‘frequency’: ‘fx’,
‘grid’: ‘gn’,
‘institute’: [‘NCAR’],
‘long_name’: ‘Grid-Cell Area for Ocean Variables’,
‘modeling_realm’: [‘ocean’],
‘original_short_name’: ‘areacello’,
‘standard_name’: ‘cell_area’,
‘units’: ‘m2’}
session: ‘session-ccace7d0-dc3b-4e03-87ea-2716aa127618_20230609_085322’These ancillary datasets are not always consistently available for each variant of a dataset. ESMValCore includes some convenience functionality that tries to find a matching variable if the exact match is not available. For example, it may take the grid cell area from another ensemble member. In this case, it looks like we have an exact match.&lt;/p&gt;
&lt;h3 id=&quot;data-downloading&quot;&gt;Data (down)loading**&lt;/h3&gt;
&lt;p&gt;We now arrive at the part of the script that calls &lt;code&gt;dataset.load()&lt;/code&gt;. In the background, ESMValCore automatically located the files on ESGF and downloaded them for us. Let’s illustrate this.&lt;/p&gt;
&lt;h1 id=&quot;before-loadprintdatasetfiles&quot;&gt;Before load**print(dataset.files)[&lt;/h1&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r4i1p1f1/Omon/tos/gn/v20190308/tos_Omon_CESM2_historical_r4i1p1f1_gn_&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;185001-201412.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’,
‘esgf3.dkrz.de’]
]# After load (and re-defining the dataset to trigger a new search)
print(dataset.files)[LocalFile(‘/home/peter/climate_data/CMIP6/CMIP/NCAR/CESM2/historical/r4i1p1f1/Omon/tos/gn/v20190308/tos_Omon_CESM2_historical_r4i1p1f1_gn_185001-201412.nc’)]Notice that there were copies of this file available on 5 different ESGF nodes. ESMValCore automatically selects the fastest available server and stored the dataset according to the standard CMOR data reference syntax.&lt;/p&gt;
&lt;p&gt;For our example dataset, all the data is apparently contained within one file. However, it’s not always like this. If we look, for example, at another ensemble member, we can see that it is stored in chunks of 50 years:&lt;/p&gt;
&lt;p&gt;print(ensemble_datasets[1].files)[ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_185001-189912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_190001-194912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_195001-199912.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’],
ESGFFile:CMIP6/CMIP/NCAR/CESM2/historical/r10i1p1f1/Omon/tos/gn/v20190313/tos_Omon_CESM2_historical_r10i1p1f1_gn_200001-201412.nc on hosts [‘aims3.llnl.gov’, ‘esgf-data.ucar.edu’, ‘esgf-data04.diasjp.net’, ‘esgf.ceda.ac.uk’, ‘esgf3.dkrz.de’]]In this case, ESMValCore automatically concatenates the data for us.&lt;/p&gt;
&lt;p&gt;You may have noticed that we assigned the result of the &lt;code&gt;load&lt;/code&gt; method to a new variable called &lt;code&gt;cube&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;cube = dataset.load()Under the hood, ESMValCore uses &lt;code&gt;[iris](https://scitools-iris.readthedocs.io)&lt;/code&gt; to represent data cubes. Compared to &lt;code&gt;xarray&lt;/code&gt;, &lt;code&gt;iris&lt;/code&gt; is more strict on checking adherence to CF conventions. This can make it harder to work with, but it also acts as a safeguard against unexpected behaviour.&lt;/p&gt;
&lt;p&gt;Where Tom used &lt;a href=&quot;https://cmip6-preprocessing.readthedocs.io&quot;&gt;xMIP&lt;/a&gt;, ESMValCore comes with builtin checks and if there are any (known) issues with the datasets, it automatically fixes them. Also, it automatically loads all supplementary datasets. Notice how the cell area is present as a cell measure.&lt;/p&gt;
&lt;p&gt;print(cube)sea_surface_temperature / (degC)          (time: 1980; cell index along second dimension: 384; cell index along first dimension: 320)
Dimension coordinates:
time                                   x                                        -                          -
cell index along second dimension      -                                        x                          -
cell index along first dimension       -                                        -                          x
Auxiliary coordinates:
latitude                               -                                        x                          x
longitude                              -                                        x                          x
Cell measures:
cell_area                              -                                        x                          x
Cell methods:
mean where sea                    area
mean                              time
Attributes:
Conventions                       ‘CF-1.7 CMIP-6.2’
activity_id                       ‘CMIP’
branch_method                     ‘standard’
branch_time_in_child              0
branch_time_in_parent             -492385
case_id                           ‘18’
cesm_casename                     ‘b.e21.BHIST.f09_g17.CMIP6-historical.004’
contact                           ‘&lt;a href=&quot;mailto:cesm_cmip6@ucar.edu&quot;&gt;cesm_cmip6@ucar.edu&lt;/a&gt;’
data_specs_version                ‘01.00.29’
description                       ‘This may differ from “surface temperature” in regions of sea ice or floating …’
experiment                        ‘all-forcing simulation of the recent past’
experiment_id                     ‘historical’
external_variables                ‘areacello’
forcing_index                     1
frequency                         ‘mon’
further_info_url                  ‘&lt;a href=&quot;https://furtherinfo.es-doc.org/CMIP6.NCAR.CESM2.historical.none.r4i1p1&quot;&gt;https://furtherinfo.es-doc.org/CMIP6.NCAR.CESM2.historical.none.r4i1p1&lt;/a&gt; …’
grid                              ‘native gx1v7 displaced pole grid (384x320 latxlon)’
grid_label                        ‘gn’
id                                ‘tos’
initialization_index              1
institution                       ‘National Center for Atmospheric Research, Climate and Global Dynamics Laboratory, …’
institution_id                    ‘NCAR’
license                           ‘CMIP6 model data produced by &amp;#x3C;The National Center for Atmospheric Research&gt; …’
mipTable                          ‘Omon’
mip_era                           ‘CMIP6’
model_doi_url                     ‘&lt;a href=&quot;https://doi.org/10.5065/D67H1H0V&quot;&gt;https://doi.org/10.5065/D67H1H0V&lt;/a&gt;’
nominal_resolution                ‘100 km’
out_name                          ‘tos’
parent_activity_id                ‘CMIP’
parent_experiment_id              ‘piControl’
parent_mip_era                    ‘CMIP6’
parent_source_id                  ‘CESM2’
parent_time_units                 ‘days since 1850-1-1 00:00:00’
parent_variant_label              ‘r1i1p1f1’
physics_index                     1
product                           ‘model-output’
prov                              ‘Omon ((isd.003))’
realization_index                 4
realm                             ‘ocean’
source                            ‘CESM2 (2017): atmosphere: CAM6 (0.9x1.25 finite volume grid; 288 x 192 …’
source_id                         ‘CESM2’
source_type                       ‘AOGCM BGC’
sub_experiment                    ‘none’
sub_experiment_id                 ‘none’
table_id                          ‘Omon’
time                              ‘time’
time_label                        ‘time-mean’
time_title                        ‘Temporal mean’
title                             ‘Sea Surface Temperature’
type                              ‘real’
variable_id                       ‘tos’
variant_info                      ‘CMIP6 20th century experiments (1850-2014) with CAM6, interactive land …’
variant_label                     ‘r4i1p1f1’&lt;/p&gt;
&lt;h3 id=&quot;pre-processing-️&quot;&gt;Pre-processing **🛠️&lt;/h3&gt;
&lt;p&gt;ESMValCore comes with a &lt;a href=&quot;https://docs.esmvaltool.org/projects/ESMValCore/en/latest/api/esmvalcore.preprocessor.html&quot;&gt;large suite&lt;/a&gt; of built-in preprocessing functions. These functions have been designed as scientifically sound default implementations for frequently performed operations. An important idea underpinning ESMValCore (&amp;#x26;Tool)’s philosophy is that standardization facilitates comparison between, and reproducibility of, our data analysis workflows. Moreover, by bundling our efforts we can develop high quality preprocessor functions more effectively. In that spirit it would be good to see how xMIP could be integrated with ESMValCore’s CMOR checks and fixes.&lt;/p&gt;
&lt;p&gt;We won’t go into detail on each of the preprocessing functions applied above, as they’re fairly self-explanatory. One thing to highlight though, is that in our calculation of anomalies, we deviated a little bit from Tom’s method. He subtracted the overall average of 1950–1980; we used monthly means over that period. It’s not really necessary here, but it facilitates comparing changes in summer temperature, for example 😎.&lt;/p&gt;
&lt;p&gt;cube = area_statistics(cube, operator=‘mean’)**cube = anomalies(cube, reference=reference_period, period=‘month’)
cube = annual_statistics(cube, operator=‘mean’)
cube.convert_units(‘degrees_C’)&lt;/p&gt;
&lt;h3 id=&quot;custom-code&quot;&gt;Custom code**&lt;/h3&gt;
&lt;p&gt;Up to this point, everything we’ve done was “pure” ESMValCore. However, in every data analysis workflow, there comes a point where you want to do custom things. In the traditional context of ESMValTool, such custom code would be added as a “diagnostic script”. In the context of this notebook, we can simply start working with the cube in whatever way we like.&lt;/p&gt;
&lt;p&gt;This can be a good moment to thank iris for its services, and continue with xarray if you prefer. For example:&lt;/p&gt;
&lt;p&gt;import xarray as xr**da = xr.DataArray.from_iris(cube)
da.plot()
print(da)&amp;#x3C;xarray.DataArray ‘tos’ (time: 165)&gt;
dask.array&amp;#x3C;filled, shape=(165,), dtype=float32, chunksize=(1,), chunktype=numpy.ndarray&gt;
Coordinates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;time     (time) object 1850-07-02 13:00:00.000001 … 2014-07-02 12:00:00
nlon     int64 …
nlat     int64 …
lat      float64 …
lon      float64 …
year     (time) int64 …
Attributes: (12/57)
standard_name:          sea_surface_temperature
long_name:              Sea Surface Temperature
units:                  degrees_C
Conventions:            CF-1.7 CMIP-6.2
activity_id:            CMIP
case_id:                18
…                     …
time:                   time
time_label:             time-mean
time_title:             Temporal mean
title:                  Sea Surface Temperature
type:                   real
cell_methods:           area: mean where sea time: mean longitude: latitu…
&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;595&quot; height=&quot;453&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-7d340529.qacNBbLZ_Z1kY9o1.webp&quot; srcset=&quot;&quot;&gt;
The change in sea-surface temperature as plotted by xarray’s builtin plot method.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;reproducibility-convert-to-recipe&quot;&gt;Reproducibility: convert to recipe**&lt;/h2&gt;
&lt;p&gt;Traditionally, ESMValTool was designed to work with recipes: static, human-readable files that declare a worfklow from start to finish. This comes back to what we said earlier about describing &lt;em&gt;what&lt;/em&gt; to do instead of &lt;em&gt;how&lt;/em&gt;. ESMValCore helps us to start building a recipe. With the following code, we can generate the &lt;code&gt;datasets&lt;/code&gt; and &lt;code&gt;diagnostics&lt;/code&gt; sections of the recipe:&lt;/p&gt;
&lt;p&gt;from esmvalcore.dataset import datasets_to_recipe**import yaml&lt;/p&gt;
&lt;p&gt;for dataset in ensemble_datasets:
dataset.facets[‘diagnostic’] = ‘easy_ipcc’
print(yaml.safe_dump(datasets_to_recipe(datasets)))datasets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dataset: CESM2
ensemble: r4i1p1f1
institute: NCAR&lt;/li&gt;
&lt;li&gt;dataset: IPSL-CM6A-LR
ensemble: r4i1p1f1
institute: IPSL&lt;/li&gt;
&lt;li&gt;dataset: MPI-ESM1-2-LR
ensemble: r4i1p1f1
institute: MPI-M&lt;/li&gt;
&lt;li&gt;dataset: TaiESM1
ensemble: r1i1p1f1
institute: AS-RCEC&lt;/li&gt;
&lt;li&gt;dataset: AWI-CM-1-1-MR
ensemble: r(1:5)i1p1f1
institute: AWI&lt;/li&gt;
&lt;li&gt;dataset: AWI-ESM-1-1-LR
ensemble: r1i1p1f1
institute: AWI&lt;/li&gt;
&lt;li&gt;dataset: BCC-CSM2-MR
ensemble: r(1:3)i1p1f1
institute: BCC
…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;diagnostics:
easy_ipcc:
variables:
tos:
exp:
- historical
- ssp585
grid: gn
mip: Omon
project: CMIP6You still have to add the preprocessors and some metadata (a short description etc.). We envision a workflow where you use ESMValCore interactively for most of your exploratory work, and then port it to a recipe for sharing and reproducibility.&lt;/p&gt;
&lt;p&gt;To complete this post, we’ve gone ahead and extended the recipe above to include all the available CMIP6 data and make a nice plot. As you might expect, this required more labour due to dataset issues for which no fixes were available, and a bit of extra tinkering to make the figure look more like the IPCC version. You can find the corresponding recipe and diagnostic script &lt;a href=&quot;https://github.com/ESMValGroup/ESMValTool/pull/3356&quot;&gt;here&lt;/a&gt;. Be careful with running it, though! This recipe will try to download almost twenty-thousand files… Running this on the German climate compute service, we get the following figure:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Analysis-ready climate data with ESMValCore&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-3815e0c2.CnP8Bhji_ZGVqem.webp&quot; srcset=&quot;&quot;&gt;
This image includes all available models &amp;#x26; ensemble members.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary**&lt;/h2&gt;
&lt;p&gt;ESMValCore is great addition to any climate analysis toolbox. Its key strengths are its its approach to streamlining workflows to achieve scientific rigor and reproducibility, and its tight integration with the ESGF and CMOR standards.&lt;/p&gt;
&lt;p&gt;If you regularly work with CMIP data, sometimes struggle to retrieve data from ESGF, frequently encounter incompatible datasets, or want to make your workflows available to others, you should definitely give it a shot.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/analysis-ready-climate-data-with-esmvalc-75688b5f.B_CK0meh.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Do you have 50.000 annotators?</title><link>https://blog.esciencecenter.nl/posts/2023-09-21---do-you-have-50000-annotators</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-09-21---do-you-have-50000-annotators</guid><description>&lt;h1 id=&quot;do-you-have-50000-annotators&quot;&gt;&lt;strong&gt;Do you have 50.000 annotators?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;*Written by eScience Center Fellow, *&lt;a href=&quot;https://www.esciencecenter.nl/fellows/daniela-gawehns/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Do you have 50.000 annotators?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/do-you-have-50000-annotators-9925b35a.DQcEXpIh_Z6PdAr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://www.shutterstock.com/image-photo/business-people-diverse-brainstorm-meeting-concept-388995775&quot;&gt;Shutterstock&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;During ICT.open 2023, I organized a workshop for 40 computer scientists on reproducibility in computer science. This is a short summary of the main results and how I experienced the workshop as a moderator.&lt;/p&gt;
&lt;p&gt;The workshop was part of &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;my fellowship project&lt;/a&gt; at the eScience Center to find out how people in the computer sciences understand reproducibility. The idea behind the project is that communities of researchers differ in how they understand the term reproducibility. Before providing tools, guidance or incentives on how to make research outputs more reproducible, we need to figure out what people understand as reproducible research.&lt;/p&gt;
&lt;p&gt;What happened?**&lt;/p&gt;
&lt;p&gt;First, participants were invited to think in small groups about four ways to make their research less (sic!) reproducible (while still making a career in science). Afterward, the groups moved to another flip chart to expand on their predecessor’s ideas. Again, the prompt was to make their work as least reproducible as possible.&lt;/p&gt;
&lt;p&gt;Participants were then invited to walk through the room, look at the posters, and pick a few ideas that they found most impactful in their own subfield of Computer Science. They labeled those ideas with post-it notes. During the last exercise, participants discussed in larger groups four different aspects of non-reproducible science: “Use overcomplicated theory”, “Use proprietary data/software”, “Require expensive tech” and “Do not share code/data”.&lt;/p&gt;
&lt;p&gt;Thinking about the opposite of what you set out to achieve was counterintuitive for some participants, while others said “This is easy, I just describe all of my frustrations. Research that I encounter in my daily work is in large parts non-reproducible”. I didn’t give a definition of what Reproducibility means or how the term is defined for the purpose of the workshop at the beginning. This was intentional, as I was hoping to gather as many ideas as possible, without influencing people’s understanding of reproducible research. As a researcher with a background in the social sciences who has discussed reproducibility of research mainly with open science enthusiasts from the social sciences, I found it important to keep as much of my previous understanding of reproducibility outside the workshop room.&lt;/p&gt;
&lt;p&gt;This workshop provided a glimpse into what computer scientists feel is important in achieving reproducibility and how this might differ from other areas of research. The use of expensive computing power or annotations is not often mentioned when I talk to psychologists, for example. I was surprised how often participants mentioned overly complicated theory as a barrier to reproducibility. Using version control to keep track of changes in code was only mentioned in passing. It didn’t seem to be on participants’ minds, while this is something I keep on hearing about in my own Open Science bubble.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What did I learn?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giving participants a lot of freedom by keeping definitions to a minimum allows participants to share their understanding. It can also lead to frustrations from people who like to set a framework for themselves before starting creative work. Inviting everyone to participate and share their ideas is a key ingredient to running a workshop where all participants are happy with the outcomes.&lt;/li&gt;
&lt;li&gt;Asking people to describe their field of research leads to answers that are difficult to use and interpret. Answers like “Human Centered Interaction/ Data and Visual Analytics“ make it hard to categorize responses into just one subcategory (in this case Human Computer Interaction or Data Science). Another question is how to split Data Science, AI and ML. Especially if people describe their work as “AI/ML” or other combinations.&lt;/li&gt;
&lt;li&gt;There was a lot more input we didn’t have time to explore. For the second part of the workshop, we picked four topics to further focus on. Other barriers to reproducibility that were mentioned by participants, but couldn’t be discussed further include: “Poorly conceptualized Desk Research”, “System Design without clear Problem description”, “Don’t explain the Evaluation, Say “well-established procedures” “, “50.000 Annotators Needed”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What’s next?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This workshop, as well as a few interviews with Computer Scientists at Leiden University, informed a survey that will be sent out in September 2023 to computer scientists working in the Netherlands. Recruitment for that survey will happen via the research schools SIKS and ASCI, social media and word of mouth. &lt;a href=&quot;https://danielagawehns.github.io/&quot;&gt;Please let me know&lt;/a&gt; if you know of a good way to reach a diverse group of survey respondents from the computer sciences.&lt;/p&gt;
&lt;p&gt;The proceedings of the &lt;a href=&quot;https://dl.acm.org/doi/proceedings/10.1145/3589806&quot;&gt;ACM REP conference&lt;/a&gt; are a good starting point for anyone interested in the topic of reproducible computer science. You can find a collection of materials in several community calls on the topic of reproducibility in Computer Science &lt;a href=&quot;https://reproducibility.acm.org/blog/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A transcript of the flip charts created during the workshop can be found &lt;a href=&quot;https://docs.google.com/document/d/1QdL4YY6RUzJkz3juMM_HDuwzrSNGNBbX1hXbgm39OtQ/edit?usp=sharing&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 21 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;do-you-have-50000-annotators&quot;&gt;&lt;strong&gt;Do you have 50.000 annotators?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;*Written by eScience Center Fellow, *&lt;a href=&quot;https://www.esciencecenter.nl/fellows/daniela-gawehns/&quot;&gt;&lt;em&gt;Daniela Gawehns&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Do you have 50.000 annotators?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/do-you-have-50000-annotators-9925b35a.DQcEXpIh_Z6PdAr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://www.shutterstock.com/image-photo/business-people-diverse-brainstorm-meeting-concept-388995775&quot;&gt;Shutterstock&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;During ICT.open 2023, I organized a workshop for 40 computer scientists on reproducibility in computer science. This is a short summary of the main results and how I experienced the workshop as a moderator.&lt;/p&gt;
&lt;p&gt;The workshop was part of &lt;a href=&quot;https://www.esciencecenter.nl/fellowship-programme/&quot;&gt;my fellowship project&lt;/a&gt; at the eScience Center to find out how people in the computer sciences understand reproducibility. The idea behind the project is that communities of researchers differ in how they understand the term reproducibility. Before providing tools, guidance or incentives on how to make research outputs more reproducible, we need to figure out what people understand as reproducible research.&lt;/p&gt;
&lt;p&gt;What happened?**&lt;/p&gt;
&lt;p&gt;First, participants were invited to think in small groups about four ways to make their research less (sic!) reproducible (while still making a career in science). Afterward, the groups moved to another flip chart to expand on their predecessor’s ideas. Again, the prompt was to make their work as least reproducible as possible.&lt;/p&gt;
&lt;p&gt;Participants were then invited to walk through the room, look at the posters, and pick a few ideas that they found most impactful in their own subfield of Computer Science. They labeled those ideas with post-it notes. During the last exercise, participants discussed in larger groups four different aspects of non-reproducible science: “Use overcomplicated theory”, “Use proprietary data/software”, “Require expensive tech” and “Do not share code/data”.&lt;/p&gt;
&lt;p&gt;Thinking about the opposite of what you set out to achieve was counterintuitive for some participants, while others said “This is easy, I just describe all of my frustrations. Research that I encounter in my daily work is in large parts non-reproducible”. I didn’t give a definition of what Reproducibility means or how the term is defined for the purpose of the workshop at the beginning. This was intentional, as I was hoping to gather as many ideas as possible, without influencing people’s understanding of reproducible research. As a researcher with a background in the social sciences who has discussed reproducibility of research mainly with open science enthusiasts from the social sciences, I found it important to keep as much of my previous understanding of reproducibility outside the workshop room.&lt;/p&gt;
&lt;p&gt;This workshop provided a glimpse into what computer scientists feel is important in achieving reproducibility and how this might differ from other areas of research. The use of expensive computing power or annotations is not often mentioned when I talk to psychologists, for example. I was surprised how often participants mentioned overly complicated theory as a barrier to reproducibility. Using version control to keep track of changes in code was only mentioned in passing. It didn’t seem to be on participants’ minds, while this is something I keep on hearing about in my own Open Science bubble.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What did I learn?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giving participants a lot of freedom by keeping definitions to a minimum allows participants to share their understanding. It can also lead to frustrations from people who like to set a framework for themselves before starting creative work. Inviting everyone to participate and share their ideas is a key ingredient to running a workshop where all participants are happy with the outcomes.&lt;/li&gt;
&lt;li&gt;Asking people to describe their field of research leads to answers that are difficult to use and interpret. Answers like “Human Centered Interaction/ Data and Visual Analytics“ make it hard to categorize responses into just one subcategory (in this case Human Computer Interaction or Data Science). Another question is how to split Data Science, AI and ML. Especially if people describe their work as “AI/ML” or other combinations.&lt;/li&gt;
&lt;li&gt;There was a lot more input we didn’t have time to explore. For the second part of the workshop, we picked four topics to further focus on. Other barriers to reproducibility that were mentioned by participants, but couldn’t be discussed further include: “Poorly conceptualized Desk Research”, “System Design without clear Problem description”, “Don’t explain the Evaluation, Say “well-established procedures” “, “50.000 Annotators Needed”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What’s next?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This workshop, as well as a few interviews with Computer Scientists at Leiden University, informed a survey that will be sent out in September 2023 to computer scientists working in the Netherlands. Recruitment for that survey will happen via the research schools SIKS and ASCI, social media and word of mouth. &lt;a href=&quot;https://danielagawehns.github.io/&quot;&gt;Please let me know&lt;/a&gt; if you know of a good way to reach a diverse group of survey respondents from the computer sciences.&lt;/p&gt;
&lt;p&gt;The proceedings of the &lt;a href=&quot;https://dl.acm.org/doi/proceedings/10.1145/3589806&quot;&gt;ACM REP conference&lt;/a&gt; are a good starting point for anyone interested in the topic of reproducible computer science. You can find a collection of materials in several community calls on the topic of reproducibility in Computer Science &lt;a href=&quot;https://reproducibility.acm.org/blog/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A transcript of the flip charts created during the workshop can be found &lt;a href=&quot;https://docs.google.com/document/d/1QdL4YY6RUzJkz3juMM_HDuwzrSNGNBbX1hXbgm39OtQ/edit?usp=sharing&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/do-you-have-50000-annotators-9925b35a.DQcEXpIh.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>ESMValTool: Recipes for solid climate science</title><link>https://blog.esciencecenter.nl/posts/2023-09-11---esmvaltool-recipes-for-solid-climate-science</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-09-11---esmvaltool-recipes-for-solid-climate-science</guid><description>&lt;h1 id=&quot;esmvaltool-recipes-for-solid-climate-science&quot;&gt;&lt;strong&gt;ESMValTool: Recipes for solid climate science&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;*This story was coauthored by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-peter-kalverla/&quot;&gt;&lt;em&gt;Peter Kalverla&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;&lt;em&gt;Bouwe Andela&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Like an artisan chef can improvise a delicious meal, so too can a scientist create new insights from raw data and exploratory analysis. But to run a successful restaurant with personnel and a consistent menu, our chef resorts to writing down his recipes. Similarly, we scientists must make an effort if we want our results to be consistent and widely reusable.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-9ecc0726.TI0_OHJi_2ekT7l.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@novokayn?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Pylyp Sukhenko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;This is where &lt;a href=&quot;https://esmvaltool.org/&quot;&gt;ESMValTool &lt;/a&gt;comes into play. Designed to ease and automate the analysis of large ensembles of climate model outputs, ESMValTool defines a clear and plain scientific [“recipe” format](&lt;a href=&quot;https://docs.esmvaltool.org/projects/ESMVal&quot;&gt;https://docs.esmvaltool.org/projects/ESMVal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Core/en/latest/recipe/overview.html). This not only helps to make workflows scientifically robust, but also provides a way to easily share and build upon each others’ work. Even if you’re not a climate scientist, there are valuable lessons to draw from ESMValTool’s approach to FAIR and open science.&lt;/p&gt;
&lt;p&gt;In this blogpost, we’ll explore four aspects of ESMValTool that may be worth your while. Starting with its take on analysis-ready data and its rich suite of pre-processor functions, we’ll set the stage for a broader discussion on how standardization helps making research easy and FAIR and the crucial role of a community in setting itself up for success.&lt;/p&gt;
&lt;h2 id=&quot;analysis-ready-cmip-data&quot;&gt;Analysis-ready (CMIP) data**&lt;/h2&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Strictly speaking, most of the functionality described here is part of ESMValCore. ESMValCore is the engine, if you will, that executes ESMValTool recipes under the hood. ESMValTool, then, is a big collection of recipes. To the user of ESMValTool, this distinction is irrelevant, but we’ll use the terms interchangeably to be as accurate as possible. For a description of ESMValCore as a standalone utility, see the companion blogpost.&lt;/p&gt;
&lt;p&gt;ESMValTool was originally designed for the analysis of CMIP data: output of many climate models assembled in a series of “Coupled Model Intercomparison Projects”. The CMIP &lt;a href=&quot;https://wcrp-cmip.github.io/WGCM_Infrastructure_Panel/CMIP6/data_request.html&quot;&gt;data request&lt;/a&gt; specifies standards that the data should adhere to. Known as the &lt;a href=&quot;https://pcmdi.llnl.gov/software/cmorTable/index.html&quot;&gt;CMOR standards&lt;/a&gt;, after the “Climate Model Output Rewriter” software, they describe things like variable names, units, coordinates (with their direction), and also file name conventions. These standards make it much easier to compare output from different climate models, and they are the foundation on which ESMValTool &amp;#x26; Core were built.&lt;/p&gt;
&lt;p&gt;For example, the file name conventions make it possible to specify a dataset like so:&lt;/p&gt;
&lt;p&gt;Dataset(**    short_name = ‘tos’,
mip = ‘Omon’,
project = ‘CMIP6’,
exp = ‘historical’,
dataset = ‘CESM2’,
ensemble = ‘r4i1p1f1’,
grid = ‘gn’
)and ESMValCore is able to locate it, both on your local computer or on &lt;a href=&quot;https://esgf.llnl.gov/&quot;&gt;ESGF&lt;/a&gt;, the shared infrastructure where all of the CMIP data are collected. ESMValCore can automatically download data from ESGF, provided that the data is present there.&lt;/p&gt;
&lt;p&gt;Pause a moment to let this sink in: ESMValCore eliminates hardcoded paths in your scripts, or rather, recipes. This is key to making them interoperable.&lt;/p&gt;
&lt;p&gt;If you’ve worked with CMIP data yourself, you’ll probably know that, despite the strict protocol, small dataset issues are commonplace. That’s why ESMValCore executes an additional CMOR check upon data loading. Where possible, it applies automatic fixes for known and trivial issues. This makes working with the data much easier.&lt;/p&gt;
&lt;p&gt;Another common issue with CMIP data is that files may not or no longer be available. ESMValCore makes it easy to perform wildcard searches or ignore missing datasets, saving you the trouble of figuring out which datasets are available or have been retracted since the last time you ran your recipe. Thus, ESMValCore is also a great utility for CMIP data discovery.&lt;/p&gt;
&lt;p&gt;While ESMValTool &amp;#x26; Core were originally developed for CMIP data, it also supports ingestion of other datasets. For example, it can apply “on the fly CMORization” of ERA5 data, and it ships with download and “CMORizer” scripts for many other (observational) datasets. This makes ESMValTool more broadly applicable and moreover, it promotes standardization beyond its original scope.&lt;/p&gt;
&lt;p&gt;To summarize, ESMValTool makes it easy to get to your data. In the next section, we’ll describe how ESMValTool also helps to standardize how you process it (without compromising on versatility).&lt;/p&gt;
&lt;h2 id=&quot;esmvalcores-rich-preprocessor-suite&quot;&gt;ESMValCore’s rich preprocessor suite**&lt;/h2&gt;
&lt;p&gt;Like with a kitchen recipe, after the ingredients come the preparation steps. In ESMValTool &amp;#x26; Core, they are called pre-processors. Common preps for climate data include regridding, area extraction, calculating anomalies and all kinds of statistics.&lt;/p&gt;
&lt;p&gt;ESMValCore has built-in functions for each of these pre-processors, and they can be added to a recipe using a very high-level specification. For example:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;226&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-d3a6c4c4.DFn5tAf4_Z1OGbrR.webp&quot; srcset=&quot;&quot;&gt;
Part of an ESMValTool a recipe listing the pre-processing steps that should be appliedBy reading this snippet, you can probably get a pretty good idea of what this recipe is trying to achieve: the mean (temperature) change over Europe with respect to a reference period. This is a declarative syntax, focusing on &lt;em&gt;what&lt;/em&gt; should be done, instead of &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Ideally, with ESMValCore, the standard pre-processors provide a scientifically sound consensus implementation. For example, it uses state-of-the-art regridding with ESMF/ESMPy, and strict CF-compliant statistics from the Iris package. These functions have been designed by domain experts and are openly developed, so anyone can suggest improvements if they feel the current implementation is insufficient. ESMValCore executes these steps in a standard order which makes sense for most applications. However, you can also specify a custom order as this might make sense for some specific use cases.&lt;/p&gt;
&lt;p&gt;In the illustration below, you can see the default order in which the pre-processors are executed. In your recipe, you can simply select those steps that are relevant for your workflow.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;352&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-3ba2f9e1.D73OQFGO_1LykGp.webp&quot; srcset=&quot;&quot;&gt;
The architecture of ESMValTool: recipe specifies which input data is loaded. This data is then ingested and the preprocessor steps specified in the recipe are executed. Finally, pre-processed data is passed onto a diagnostic script to generate the final output.After prepping, your data is (optionally) passed on to a diagnostic script. This is the place where you can do custom things, such as making a figure, or doing a more thorough and case-specific analysis. “Combining the ingredients into a tasty dish”, to stick with the chef’s analogy.&lt;/p&gt;
&lt;p&gt;So far, we’ve seen how ESMValTool tries to streamline those parts of your analysis workflow that can be standardized, and tries to accomodate all specific things you might need or want. In the next section, we’ll see how this helps you make your research more &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;FAIR&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fair-and-open-science&quot;&gt;FAIR and open science**&lt;/h2&gt;
&lt;p&gt;ESMValTool is a great example of how open science can work in practice.&lt;/p&gt;
&lt;p&gt;Recently there’s been an increased focus on accessibility, transpancy, and &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/reproducible-research.html&quot;&gt;reproducibility &lt;/a&gt;in science. We’ve seen the advent of open access publications, the introduction of FAIR &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;standards &lt;/a&gt;for research data management. It’s easy to extrapolate these ideas to other aspects of the research process as well. At the same time, this can be daunting, because it may seem like a lot of extra work that you might not have the time or skills for. So let’s see how ESMValTool helps with these concerns.&lt;/p&gt;
&lt;p&gt;One ideal that’s often associated with open science is reciprocity, which we all know in &lt;a href=&quot;https://genius.com/27629118&quot;&gt;lyrical form&lt;/a&gt; as “never take more than you give”. The idea is that scientific progress benefits from mutual exchange and building upon each other’s work. ESMValTool provides a platform for receiving and giving back. By making available a large suite of recipes that other people have already composed. By establishing a process to contribute your own recipes. By setting a standard format to encode recipes. By integrating existing functionality into a streamlined workflow system. And by facilitating a process of feedback based around users’ contributions, and a forum for discussion. Many of the things that are hard to organize on your own, have already been organized by the ESMValTool community. Thus, you’ll be greeted with a warm welcome instead of a daunting prospect.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-fd3a27a4.DxpAYR-F_Z2nruy3.webp&quot; srcset=&quot;&quot;&gt;
Illustration from the Turing way book dashes.Going more into the specifics of FAIR, we can see how ESMValTool contributes: ESMValTool has great documentation listing all &lt;a href=&quot;https://docs.esmvaltool.org/en/latest/recipes/index.html&quot;&gt;available recipes&lt;/a&gt; and a gallery with outputs. You can also list the available recipes from within the software, or browse the &lt;a href=&quot;https://github.com/ESMValGroup/ESMValTool/tree/main/esmvaltool/recipes&quot;&gt;source code&lt;/a&gt;. So recipes are quite findable, although you could still take it a step further by creating a searchable registry with unique identifiers for each recipe (Note that the package as a whole does have a &lt;a href=&quot;https://doi.org/10.5281/zenodo.3401363&quot;&gt;DOI&lt;/a&gt; for each version).&lt;/p&gt;
&lt;p&gt;ESMValTool recipes are also very accessible. The YAML format is very readable for humans and also by machines; they can be executed. As we’ve seen above recipes are also portable: hardcoded file paths et cetera have been eliminated. For each release of ESMValTool, all recipes are executed to see if they still work, and output is made available.&lt;/p&gt;
&lt;p&gt;To summarize, ESMValTool itself would qualify as “FAIR software. But moreover, ESMValTool recipes also come a long way as “FAIR scientific workflows”. Just like kitchen recipes empower chefs, ESMValTool recipes empower scientists.&lt;/p&gt;
&lt;h2 id=&quot;the-crucial-role-of-community&quot;&gt;&lt;strong&gt;The crucial role of community&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;ESMValTool would not have been where it is now if it wasn’t for the community. The ESMValTool community is a nice and welcoming crowd of scientists and software engineers from various institutes in Europe and beyond. In addition to lively interactions on GitHub there are monthly online meetings that are open to all, and there’s an in-person workshop once or twice a year. Furthermore there are spontaneous gatherings of ESMValTool contributors at other ocassions such as conferences.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;340&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-a4ea8d51.Cx9hSZoT_29CzAr.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of the ESMValTool discussion forum announcing some of the community gatherings.Over the years the ‘core team’ has gained a lot of experience and become more professional, for example when it comes to processes for decision making and user engagement. There are clear guidelines for contributing to the codebase, and people are always willing to help each other out. To support new users, the user engagement team maintains a &lt;a href=&quot;https://tutorial.esmvaltool.org/&quot;&gt;tutorial &lt;/a&gt;that is regularly taught.&lt;/p&gt;
&lt;p&gt;By fostering enjoyable and personal interaction, the community plays a vital role in facilitating the development and long-term sustainability of ESMValTool.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, ESMValTool provides a valuable platform for scientists to achieve consistency, reusability, and standardization in their research, owing much of its current success to the dedicated community that surrounds it.&lt;/p&gt;
&lt;p&gt;Are you a climate scientists and do you want to be part of this community? Don’t hesitate to reach out on GitHub or another channel that you see fit. Are you passionate about open science but not necessarily in climate science? Then we hope you could get some nice takeaways from ESMValTools experience and we are always happy to exchange more. In any case, the next time you visit a restaurant, remember to appreciate not only the chef but also the thoughtfully curated menu.&lt;/p&gt;</description><pubDate>Mon, 11 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;esmvaltool-recipes-for-solid-climate-science&quot;&gt;&lt;strong&gt;ESMValTool: Recipes for solid climate science&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;*This story was coauthored by &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-peter-kalverla/&quot;&gt;&lt;em&gt;Peter Kalverla&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;&lt;em&gt;Bouwe Andela&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Like an artisan chef can improvise a delicious meal, so too can a scientist create new insights from raw data and exploratory analysis. But to run a successful restaurant with personnel and a consistent menu, our chef resorts to writing down his recipes. Similarly, we scientists must make an effort if we want our results to be consistent and widely reusable.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-9ecc0726.TI0_OHJi_2ekT7l.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@novokayn?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Pylyp Sukhenko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;This is where &lt;a href=&quot;https://esmvaltool.org/&quot;&gt;ESMValTool &lt;/a&gt;comes into play. Designed to ease and automate the analysis of large ensembles of climate model outputs, ESMValTool defines a clear and plain scientific [“recipe” format](&lt;a href=&quot;https://docs.esmvaltool.org/projects/ESMVal&quot;&gt;https://docs.esmvaltool.org/projects/ESMVal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Core/en/latest/recipe/overview.html). This not only helps to make workflows scientifically robust, but also provides a way to easily share and build upon each others’ work. Even if you’re not a climate scientist, there are valuable lessons to draw from ESMValTool’s approach to FAIR and open science.&lt;/p&gt;
&lt;p&gt;In this blogpost, we’ll explore four aspects of ESMValTool that may be worth your while. Starting with its take on analysis-ready data and its rich suite of pre-processor functions, we’ll set the stage for a broader discussion on how standardization helps making research easy and FAIR and the crucial role of a community in setting itself up for success.&lt;/p&gt;
&lt;h2 id=&quot;analysis-ready-cmip-data&quot;&gt;Analysis-ready (CMIP) data**&lt;/h2&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Strictly speaking, most of the functionality described here is part of ESMValCore. ESMValCore is the engine, if you will, that executes ESMValTool recipes under the hood. ESMValTool, then, is a big collection of recipes. To the user of ESMValTool, this distinction is irrelevant, but we’ll use the terms interchangeably to be as accurate as possible. For a description of ESMValCore as a standalone utility, see the companion blogpost.&lt;/p&gt;
&lt;p&gt;ESMValTool was originally designed for the analysis of CMIP data: output of many climate models assembled in a series of “Coupled Model Intercomparison Projects”. The CMIP &lt;a href=&quot;https://wcrp-cmip.github.io/WGCM_Infrastructure_Panel/CMIP6/data_request.html&quot;&gt;data request&lt;/a&gt; specifies standards that the data should adhere to. Known as the &lt;a href=&quot;https://pcmdi.llnl.gov/software/cmorTable/index.html&quot;&gt;CMOR standards&lt;/a&gt;, after the “Climate Model Output Rewriter” software, they describe things like variable names, units, coordinates (with their direction), and also file name conventions. These standards make it much easier to compare output from different climate models, and they are the foundation on which ESMValTool &amp;#x26; Core were built.&lt;/p&gt;
&lt;p&gt;For example, the file name conventions make it possible to specify a dataset like so:&lt;/p&gt;
&lt;p&gt;Dataset(**    short_name = ‘tos’,
mip = ‘Omon’,
project = ‘CMIP6’,
exp = ‘historical’,
dataset = ‘CESM2’,
ensemble = ‘r4i1p1f1’,
grid = ‘gn’
)and ESMValCore is able to locate it, both on your local computer or on &lt;a href=&quot;https://esgf.llnl.gov/&quot;&gt;ESGF&lt;/a&gt;, the shared infrastructure where all of the CMIP data are collected. ESMValCore can automatically download data from ESGF, provided that the data is present there.&lt;/p&gt;
&lt;p&gt;Pause a moment to let this sink in: ESMValCore eliminates hardcoded paths in your scripts, or rather, recipes. This is key to making them interoperable.&lt;/p&gt;
&lt;p&gt;If you’ve worked with CMIP data yourself, you’ll probably know that, despite the strict protocol, small dataset issues are commonplace. That’s why ESMValCore executes an additional CMOR check upon data loading. Where possible, it applies automatic fixes for known and trivial issues. This makes working with the data much easier.&lt;/p&gt;
&lt;p&gt;Another common issue with CMIP data is that files may not or no longer be available. ESMValCore makes it easy to perform wildcard searches or ignore missing datasets, saving you the trouble of figuring out which datasets are available or have been retracted since the last time you ran your recipe. Thus, ESMValCore is also a great utility for CMIP data discovery.&lt;/p&gt;
&lt;p&gt;While ESMValTool &amp;#x26; Core were originally developed for CMIP data, it also supports ingestion of other datasets. For example, it can apply “on the fly CMORization” of ERA5 data, and it ships with download and “CMORizer” scripts for many other (observational) datasets. This makes ESMValTool more broadly applicable and moreover, it promotes standardization beyond its original scope.&lt;/p&gt;
&lt;p&gt;To summarize, ESMValTool makes it easy to get to your data. In the next section, we’ll describe how ESMValTool also helps to standardize how you process it (without compromising on versatility).&lt;/p&gt;
&lt;h2 id=&quot;esmvalcores-rich-preprocessor-suite&quot;&gt;ESMValCore’s rich preprocessor suite**&lt;/h2&gt;
&lt;p&gt;Like with a kitchen recipe, after the ingredients come the preparation steps. In ESMValTool &amp;#x26; Core, they are called pre-processors. Common preps for climate data include regridding, area extraction, calculating anomalies and all kinds of statistics.&lt;/p&gt;
&lt;p&gt;ESMValCore has built-in functions for each of these pre-processors, and they can be added to a recipe using a very high-level specification. For example:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;226&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-d3a6c4c4.DFn5tAf4_Z1OGbrR.webp&quot; srcset=&quot;&quot;&gt;
Part of an ESMValTool a recipe listing the pre-processing steps that should be appliedBy reading this snippet, you can probably get a pretty good idea of what this recipe is trying to achieve: the mean (temperature) change over Europe with respect to a reference period. This is a declarative syntax, focusing on &lt;em&gt;what&lt;/em&gt; should be done, instead of &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Ideally, with ESMValCore, the standard pre-processors provide a scientifically sound consensus implementation. For example, it uses state-of-the-art regridding with ESMF/ESMPy, and strict CF-compliant statistics from the Iris package. These functions have been designed by domain experts and are openly developed, so anyone can suggest improvements if they feel the current implementation is insufficient. ESMValCore executes these steps in a standard order which makes sense for most applications. However, you can also specify a custom order as this might make sense for some specific use cases.&lt;/p&gt;
&lt;p&gt;In the illustration below, you can see the default order in which the pre-processors are executed. In your recipe, you can simply select those steps that are relevant for your workflow.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;352&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-3ba2f9e1.D73OQFGO_1LykGp.webp&quot; srcset=&quot;&quot;&gt;
The architecture of ESMValTool: recipe specifies which input data is loaded. This data is then ingested and the preprocessor steps specified in the recipe are executed. Finally, pre-processed data is passed onto a diagnostic script to generate the final output.After prepping, your data is (optionally) passed on to a diagnostic script. This is the place where you can do custom things, such as making a figure, or doing a more thorough and case-specific analysis. “Combining the ingredients into a tasty dish”, to stick with the chef’s analogy.&lt;/p&gt;
&lt;p&gt;So far, we’ve seen how ESMValTool tries to streamline those parts of your analysis workflow that can be standardized, and tries to accomodate all specific things you might need or want. In the next section, we’ll see how this helps you make your research more &lt;a href=&quot;https://www.nature.com/articles/s41597-022-01710-x&quot;&gt;FAIR&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fair-and-open-science&quot;&gt;FAIR and open science**&lt;/h2&gt;
&lt;p&gt;ESMValTool is a great example of how open science can work in practice.&lt;/p&gt;
&lt;p&gt;Recently there’s been an increased focus on accessibility, transpancy, and &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/reproducible-research.html&quot;&gt;reproducibility &lt;/a&gt;in science. We’ve seen the advent of open access publications, the introduction of FAIR &lt;a href=&quot;https://www.nature.com/articles/sdata201618&quot;&gt;standards &lt;/a&gt;for research data management. It’s easy to extrapolate these ideas to other aspects of the research process as well. At the same time, this can be daunting, because it may seem like a lot of extra work that you might not have the time or skills for. So let’s see how ESMValTool helps with these concerns.&lt;/p&gt;
&lt;p&gt;One ideal that’s often associated with open science is reciprocity, which we all know in &lt;a href=&quot;https://genius.com/27629118&quot;&gt;lyrical form&lt;/a&gt; as “never take more than you give”. The idea is that scientific progress benefits from mutual exchange and building upon each other’s work. ESMValTool provides a platform for receiving and giving back. By making available a large suite of recipes that other people have already composed. By establishing a process to contribute your own recipes. By setting a standard format to encode recipes. By integrating existing functionality into a streamlined workflow system. And by facilitating a process of feedback based around users’ contributions, and a forum for discussion. Many of the things that are hard to organize on your own, have already been organized by the ESMValTool community. Thus, you’ll be greeted with a warm welcome instead of a daunting prospect.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-fd3a27a4.DxpAYR-F_Z2nruy3.webp&quot; srcset=&quot;&quot;&gt;
Illustration from the Turing way book dashes.Going more into the specifics of FAIR, we can see how ESMValTool contributes: ESMValTool has great documentation listing all &lt;a href=&quot;https://docs.esmvaltool.org/en/latest/recipes/index.html&quot;&gt;available recipes&lt;/a&gt; and a gallery with outputs. You can also list the available recipes from within the software, or browse the &lt;a href=&quot;https://github.com/ESMValGroup/ESMValTool/tree/main/esmvaltool/recipes&quot;&gt;source code&lt;/a&gt;. So recipes are quite findable, although you could still take it a step further by creating a searchable registry with unique identifiers for each recipe (Note that the package as a whole does have a &lt;a href=&quot;https://doi.org/10.5281/zenodo.3401363&quot;&gt;DOI&lt;/a&gt; for each version).&lt;/p&gt;
&lt;p&gt;ESMValTool recipes are also very accessible. The YAML format is very readable for humans and also by machines; they can be executed. As we’ve seen above recipes are also portable: hardcoded file paths et cetera have been eliminated. For each release of ESMValTool, all recipes are executed to see if they still work, and output is made available.&lt;/p&gt;
&lt;p&gt;To summarize, ESMValTool itself would qualify as “FAIR software. But moreover, ESMValTool recipes also come a long way as “FAIR scientific workflows”. Just like kitchen recipes empower chefs, ESMValTool recipes empower scientists.&lt;/p&gt;
&lt;h2 id=&quot;the-crucial-role-of-community&quot;&gt;&lt;strong&gt;The crucial role of community&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;ESMValTool would not have been where it is now if it wasn’t for the community. The ESMValTool community is a nice and welcoming crowd of scientists and software engineers from various institutes in Europe and beyond. In addition to lively interactions on GitHub there are monthly online meetings that are open to all, and there’s an in-person workshop once or twice a year. Furthermore there are spontaneous gatherings of ESMValTool contributors at other ocassions such as conferences.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ESMValTool: Recipes for solid climate science&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;340&quot; src=&quot;https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-a4ea8d51.Cx9hSZoT_29CzAr.webp&quot; srcset=&quot;&quot;&gt;
Screenshot of the ESMValTool discussion forum announcing some of the community gatherings.Over the years the ‘core team’ has gained a lot of experience and become more professional, for example when it comes to processes for decision making and user engagement. There are clear guidelines for contributing to the codebase, and people are always willing to help each other out. To support new users, the user engagement team maintains a &lt;a href=&quot;https://tutorial.esmvaltool.org/&quot;&gt;tutorial &lt;/a&gt;that is regularly taught.&lt;/p&gt;
&lt;p&gt;By fostering enjoyable and personal interaction, the community plays a vital role in facilitating the development and long-term sustainability of ESMValTool.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, ESMValTool provides a valuable platform for scientists to achieve consistency, reusability, and standardization in their research, owing much of its current success to the dedicated community that surrounds it.&lt;/p&gt;
&lt;p&gt;Are you a climate scientists and do you want to be part of this community? Don’t hesitate to reach out on GitHub or another channel that you see fit. Are you passionate about open science but not necessarily in climate science? Then we hope you could get some nice takeaways from ESMValTools experience and we are always happy to exchange more. In any case, the next time you visit a restaurant, remember to appreciate not only the chef but also the thoughtfully curated menu.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/esmvaltool-recipes-for-solid-climate-sci-9ecc0726.TI0_OHJi.jpg" medium="image"/><author>Peter Kalverla</author></item><item><title>Coming Soon: Conditional Process Models in JASP</title><link>https://blog.esciencecenter.nl/posts/2023-08-31---coming-soon-conditional-process-models-in-jasp</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-08-31---coming-soon-conditional-process-models-in-jasp</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/malte-luken/&quot;&gt;Malte Lüken&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/thijs-vroegh/&quot;&gt;Thijs Vroegh&lt;/a&gt;, &lt;a href=&quot;https://www.uva.nl/en/profile/d/o/j.b.vandoorn/j.b.vandoorn.html&quot;&gt;Johnny van Doorn&lt;/a&gt;, and &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is also published on the JASP &lt;em&gt;&lt;a href=&quot;https://jasp-stats.org/blog/&quot;&gt;&lt;em&gt;blog&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-28f59e63.BvDjMAD5_Z1hQvP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@humakabakci?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Huma Kabakci&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;
&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-1571ecc2.wAju-tYr_2e1nej.webp&quot; srcset=&quot;&quot;&gt;
Many students, teachers and researchers use the popular &lt;a href=&quot;https://www.processmacro.org/&quot;&gt;PROCESS&lt;/a&gt; macro for SPSS (Hayes, 2022a, 2022b) to estimate conditional process models involving mediation and moderation effects. Recently, however, these models were also criticized because they make causal assumptions, which do not hold in many applied settings (Bullock et al., 2010, Rohrer et al., 2022). The popularity and criticism warrant a new module to make conditional process models easily accessible to the JASP community. Moreover, the module should provide a better understanding of the underlying causal assumptions for users and tools to explicitly test them. The JASP Team and the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; are currently working on such an endeavor, and we give a short teaser in this blog post.&lt;/p&gt;
&lt;h2 id=&quot;estimating-models-as-in-spss&quot;&gt;Estimating Models as in SPSS&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;928&quot; height=&quot;572&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-c574f468.CqYvTdHT_Z1HpGWI.webp&quot; srcset=&quot;&quot;&gt;
The new &lt;em&gt;Process&lt;/em&gt; module has two graphical user interfaces: One interface resembles the interface of the original SPSS macro where users first select a model configuration from a predefined list. In contrast to SPSS, JASP immediately shows the user a graphical representation of the specified model (i.e., a path plot), which facilitates the search for the right model. As the user adds more variables to the model, the graphical representation is updated. The module will provide both conceptual and statistical path plots, where the statistical path plot includes the estimated parameters.&lt;/p&gt;
&lt;h2 id=&quot;building-models-step-by-step&quot;&gt;Building Models Step-by-step&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;928&quot; height=&quot;573&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-da35f929.CqlR2qB3_1bgfQX.webp&quot; srcset=&quot;&quot;&gt;
With a second, complementary interface users can build models step-by-step starting from scratch. They can iteratively add paths (i.e., relations) between selected variables and define how other variables influence each path (e.g., through mediation or moderation). Below, we reproduce predefined Model 5 with two path specifications: We first add a path between Extraversion and Neuroticism (X and Y) and specify Openness as a mediator for this path (M). Then, we add a second path specification between Extraversion and Neuroticism, but this time we include Agreeableness as a moderator for this path (W). Again, every time a path is added or modified, JASP will immediately show the user the corresponding graphical representation of the model to facilitate the model-building process. This approach enables users to build models intuitively and flexibly, avoiding the restrictions of predefined model configurations.&lt;/p&gt;
&lt;h2 id=&quot;addressing-criticisms-of-process-models&quot;&gt;Addressing Criticisms of Process Models&lt;/h2&gt;
&lt;p&gt;Conditional process models make strong causal assumptions about the relationships between variables. A mediation model, for example, states that there is a causal relationship from X to Y, X to M, as well as M to Y. Critics have argued that researchers cannot assume these causal assumptions to hold in most applications, even in experimental settings (Bullock et al., 2010, Rohrer et al., 2022). In the new module, we aim to address some of these arguments by making the causal assumptions more explicit via footnotes and warnings. Importantly, we will also enable users to test the statistical patterns implied by the causal assumptions (i.e., via conditional independence tests; see Rohrer et al., 2022). Users can then conclude which assumptions are violated and modify their model or experimental design accordingly. Because of its step-by-step interface, the module allows users to build more complex models to accommodate the requirements of their application (e.g., by adding confounding variables to different paths). Despite these features, many challenges remain when applying conditional process models, most of which are related to careful experimental design (see Bullock et al., 2010). We aim to draw the users’ attention to these challenges and improve the statistical use of process models in practice.&lt;/p&gt;
&lt;h2 id=&quot;behind-the-project&quot;&gt;Behind the Project&lt;/h2&gt;
&lt;p&gt;This project is a collaboration between the JASP Team and the Netherlands eScience Center. As the national institute for research software, the Netherlands eScience Center awards projects as part of calls for proposals. Instead of monetary funding, it provides in-kind support by Research Software Engineers to create innovative digital solutions. This project was granted as part of the Small-Scale Initiatives Digital Approaches to the Social Sciences call 2022.&lt;/p&gt;
&lt;p&gt;We kindly thank &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;&lt;em&gt;Tom Bakker&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;&lt;em&gt;Lieke de Boer&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for providing feedback on earlier versions of this post.*&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Bullock, J. G., Green, D. P., &amp;#x26; Ha, S. E. (2010). Yes, but what’s the mechanism? (don’t expect an easy answer). &lt;em&gt;Journal of Personality and Social Psychology, 98&lt;/em&gt;(4), 550–558. &lt;a href=&quot;https://psycnet.apa.org/doi/10.1037/a0018933&quot;&gt;https://doi.org/10.1037/a0018933&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022a). *Introduction to mediation, moderation, and conditional process analysis *(3rd Ed.). New York: The Guilford Press.&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022b). The PROCESS macro for SPSS, SAS, and R (Version 4.2) [Computer software]. &lt;a href=&quot;https://processmacro.org&quot;&gt;https://processmacro.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., Hünermund, P., Arslan, R. C., Elson, M. (2022). That’s a lot to process! Pitfalls of popular path models. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 5&lt;/em&gt;(2). &lt;a href=&quot;https://doi.org/10.1177/25152459221095827&quot;&gt;https://doi.org/10.1177/25152459221095827&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 31 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.esciencecenter.nl/team/malte-luken/&quot;&gt;Malte Lüken&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/thijs-vroegh/&quot;&gt;Thijs Vroegh&lt;/a&gt;, &lt;a href=&quot;https://www.uva.nl/en/profile/d/o/j.b.vandoorn/j.b.vandoorn.html&quot;&gt;Johnny van Doorn&lt;/a&gt;, and &lt;a href=&quot;https://www.uva.nl/en/profile/w/a/e.m.wagenmakers/e.m.wagenmakers.html&quot;&gt;Eric-Jan Wagenmakers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is also published on the JASP &lt;em&gt;&lt;a href=&quot;https://jasp-stats.org/blog/&quot;&gt;&lt;em&gt;blog&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-28f59e63.BvDjMAD5_Z1hQvP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@humakabakci?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Huma Kabakci&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;
&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-1571ecc2.wAju-tYr_2e1nej.webp&quot; srcset=&quot;&quot;&gt;
Many students, teachers and researchers use the popular &lt;a href=&quot;https://www.processmacro.org/&quot;&gt;PROCESS&lt;/a&gt; macro for SPSS (Hayes, 2022a, 2022b) to estimate conditional process models involving mediation and moderation effects. Recently, however, these models were also criticized because they make causal assumptions, which do not hold in many applied settings (Bullock et al., 2010, Rohrer et al., 2022). The popularity and criticism warrant a new module to make conditional process models easily accessible to the JASP community. Moreover, the module should provide a better understanding of the underlying causal assumptions for users and tools to explicitly test them. The JASP Team and the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; are currently working on such an endeavor, and we give a short teaser in this blog post.&lt;/p&gt;
&lt;h2 id=&quot;estimating-models-as-in-spss&quot;&gt;Estimating Models as in SPSS&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;928&quot; height=&quot;572&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-c574f468.CqYvTdHT_Z1HpGWI.webp&quot; srcset=&quot;&quot;&gt;
The new &lt;em&gt;Process&lt;/em&gt; module has two graphical user interfaces: One interface resembles the interface of the original SPSS macro where users first select a model configuration from a predefined list. In contrast to SPSS, JASP immediately shows the user a graphical representation of the specified model (i.e., a path plot), which facilitates the search for the right model. As the user adds more variables to the model, the graphical representation is updated. The module will provide both conceptual and statistical path plots, where the statistical path plot includes the estimated parameters.&lt;/p&gt;
&lt;h2 id=&quot;building-models-step-by-step&quot;&gt;Building Models Step-by-step&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Coming Soon: Conditional Process Models in JASP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;928&quot; height=&quot;573&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-da35f929.CqlR2qB3_1bgfQX.webp&quot; srcset=&quot;&quot;&gt;
With a second, complementary interface users can build models step-by-step starting from scratch. They can iteratively add paths (i.e., relations) between selected variables and define how other variables influence each path (e.g., through mediation or moderation). Below, we reproduce predefined Model 5 with two path specifications: We first add a path between Extraversion and Neuroticism (X and Y) and specify Openness as a mediator for this path (M). Then, we add a second path specification between Extraversion and Neuroticism, but this time we include Agreeableness as a moderator for this path (W). Again, every time a path is added or modified, JASP will immediately show the user the corresponding graphical representation of the model to facilitate the model-building process. This approach enables users to build models intuitively and flexibly, avoiding the restrictions of predefined model configurations.&lt;/p&gt;
&lt;h2 id=&quot;addressing-criticisms-of-process-models&quot;&gt;Addressing Criticisms of Process Models&lt;/h2&gt;
&lt;p&gt;Conditional process models make strong causal assumptions about the relationships between variables. A mediation model, for example, states that there is a causal relationship from X to Y, X to M, as well as M to Y. Critics have argued that researchers cannot assume these causal assumptions to hold in most applications, even in experimental settings (Bullock et al., 2010, Rohrer et al., 2022). In the new module, we aim to address some of these arguments by making the causal assumptions more explicit via footnotes and warnings. Importantly, we will also enable users to test the statistical patterns implied by the causal assumptions (i.e., via conditional independence tests; see Rohrer et al., 2022). Users can then conclude which assumptions are violated and modify their model or experimental design accordingly. Because of its step-by-step interface, the module allows users to build more complex models to accommodate the requirements of their application (e.g., by adding confounding variables to different paths). Despite these features, many challenges remain when applying conditional process models, most of which are related to careful experimental design (see Bullock et al., 2010). We aim to draw the users’ attention to these challenges and improve the statistical use of process models in practice.&lt;/p&gt;
&lt;h2 id=&quot;behind-the-project&quot;&gt;Behind the Project&lt;/h2&gt;
&lt;p&gt;This project is a collaboration between the JASP Team and the Netherlands eScience Center. As the national institute for research software, the Netherlands eScience Center awards projects as part of calls for proposals. Instead of monetary funding, it provides in-kind support by Research Software Engineers to create innovative digital solutions. This project was granted as part of the Small-Scale Initiatives Digital Approaches to the Social Sciences call 2022.&lt;/p&gt;
&lt;p&gt;We kindly thank &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;&lt;em&gt;Tom Bakker&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;&lt;em&gt;Lieke de Boer&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; for providing feedback on earlier versions of this post.*&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Bullock, J. G., Green, D. P., &amp;#x26; Ha, S. E. (2010). Yes, but what’s the mechanism? (don’t expect an easy answer). &lt;em&gt;Journal of Personality and Social Psychology, 98&lt;/em&gt;(4), 550–558. &lt;a href=&quot;https://psycnet.apa.org/doi/10.1037/a0018933&quot;&gt;https://doi.org/10.1037/a0018933&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022a). *Introduction to mediation, moderation, and conditional process analysis *(3rd Ed.). New York: The Guilford Press.&lt;/p&gt;
&lt;p&gt;Hayes, A. F. (2022b). The PROCESS macro for SPSS, SAS, and R (Version 4.2) [Computer software]. &lt;a href=&quot;https://processmacro.org&quot;&gt;https://processmacro.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Rohrer, J. M., Hünermund, P., Arslan, R. C., Elson, M. (2022). That’s a lot to process! Pitfalls of popular path models. &lt;em&gt;Advances in Methods and Practices in Psychological Science, 5&lt;/em&gt;(2). &lt;a href=&quot;https://doi.org/10.1177/25152459221095827&quot;&gt;https://doi.org/10.1177/25152459221095827&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/coming-soon-conditional-process-models-i-28f59e63.BvDjMAD5.jpg" medium="image"/><author>Malte Lüken</author></item><item><title>Why your research deserves to be an R package</title><link>https://blog.esciencecenter.nl/posts/2023-08-30---why-your-research-deserves-to-be-an-r-package</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-08-30---why-your-research-deserves-to-be-an-r-package</guid><description>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If after reading this post you are motivated to make your own R package, consider joining our upcoming workshop! &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.nl/e/reproducible-research-with-r-packages-tickets-672884123527&quot;&gt;&lt;em&gt;Free tickets are now available&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you are an R user, think about this scenario:&lt;/p&gt;
&lt;p&gt;How often have you reused someone else’s code — a colleague’s workflow, perhaps a script you found as an appendix in a paper? Did it run right away? Was it easy to reuse?&lt;/p&gt;
&lt;p&gt;Now, ask yourself whether you have used someone else’s packaged code. How often have you started your own script with &lt;em&gt;library (packagename)&lt;/em&gt;, and used functions that are not part of base R?&lt;/p&gt;
&lt;p&gt;I am willing to bet quite a lot that the second scenario is an order of magnitude more common than the first. There is a reason for this: packages are made to be reused. Scripts, while technically reusable, are not.&lt;/p&gt;
&lt;p&gt;Let me now ask you about your own work: do you want it to be reused?&lt;/p&gt;
&lt;p&gt;You know what you have to do now, right?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-bebe4eaf.DCiM-mIO_2mR8fo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kadh?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Kira auf der Heide&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;but-making-a-package-isnt-that-complicated&quot;&gt;But making a package… isn’t that complicated?&lt;/h3&gt;
&lt;p&gt;An R package distinguishes itself from scripted code in a few ways, but it is much less complex than you may think.&lt;/p&gt;
&lt;p&gt;First of all, when your code is packaged, it is contained in a standardized folder structure. The code itself lives in a designated folder (aptly named ‘R’). In addition, the root of the package contains files with some basic information about your package — like the title, the authors, and the license for future users.&lt;/p&gt;
&lt;p&gt;Secondly, and perhaps most crucially, packaged code consists of functions only. Functions are the units at the centre of a package. They take information as arguments and return an output. For example, I have a function called *multiply. *This function, you guessed it, multiplies the two arguments I give it, and returns the result:&lt;/p&gt;
&lt;p&gt;multiply &amp;#x3C;- function(a, b){
return(a * b)
}After including this function in a package — let’s call it *mypackage — *someone else can now use it without opening and running the entire codebase, but instead by attaching the package and calling the function:&lt;/p&gt;
&lt;p&gt;&gt; library(myPackage)
&gt; multiply(3,4)
[1] 12You have likely written functions before. And you know how folders work. To dot the i’s and cross the t’s, Rstudio is here to help: it contains many built-in functions to make package creation a breeze.&lt;/p&gt;
&lt;h3 id=&quot;your-work-deserves-to-be-reused&quot;&gt;Your work deserves to be reused.&lt;/h3&gt;
&lt;p&gt;Just in case you are now doubting yourself, please don’t. Scripting an analysis is more than just applying existing calculations. The workflow itself is an original thought. Even if you have not, say, designed a new statistical method yourself, the methods you choose, the way you select and handle your data, the visualisations you make — they are your work, and could be reused as a standardised workflow in your field.&lt;/p&gt;
&lt;p&gt;Let’s take an example. Mark*, a linguistics professor, runs frequent analyses on datasets made from taped conversations. He uses R to uncover the unwritten rules of conversation, finding out how people weave their utterances together. With this data, he creates &lt;a href=&quot;https://ideophone.org/snailplot-rmd/&quot;&gt;fantastic&lt;/a&gt; &lt;a href=&quot;https://markdingemanse.net/publications/visuals/how-asr-training-data-differs-from-real-conversation&quot;&gt;visualisations&lt;/a&gt;, which give insight into the conversational dynamics at play.&lt;/p&gt;
&lt;p&gt;Mark has hundreds of conversations to analyse, so he made functions that contains the essential elements of his workflow. Now, when he loads a new conversation, he can for instance use this function** to quickly get an overview of the basic statistics:&lt;/p&gt;
&lt;p&gt;&gt; conversation &amp;#x3C;- read.csv(“data/conversation25.csv”)
&gt; inspect_convo(conversation)
Number of speakers: 2
Length of conversation: 10:03
Number of utterances: 9438But Mark does not work alone. His group contains PhD students and postdocs, and is a popular place for bachelor and master internships. He shares his scripts with his group, but they can be a daunting sight for those who have not programmed much before. And as his toolkit grows, he loses track of the different elements it contains, and what updates he has shared with whom.&lt;/p&gt;
&lt;p&gt;Mark needs an R package.&lt;/p&gt;
&lt;h3 id=&quot;a-package-makes-you-a-better-programmer&quot;&gt;A package makes you a better programmer.&lt;/h3&gt;
&lt;p&gt;An important element of packaged functions is their documentation: a user who only has access to the name of the function, needs to know how to use it. But writing documentation is not just for users: it does something for you as a developer as well.&lt;/p&gt;
&lt;p&gt;Writing down the logic of your functions — what goes in? What comes out? Exactly what formats are needed for each argument?— helps you think more critically about the objects you use and create as part of your workflow. You may not expect it, but documentation is a powerful way to take a step back and start viewing your set of functions as a whole.&lt;/p&gt;
&lt;p&gt;This is where you go from scripting to software engineering.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-921434e2.m43Kfwp4_Z1RWn4W.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@retrosupply?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;RetroSupply&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;packaged-code-is-more-robust-and-developing-it-is-more-efficient&quot;&gt;Packaged code is more robust, and developing it is more efficient.&lt;/h3&gt;
&lt;p&gt;Because your functions are in a package, you now also have access to another powerful tool in the software engineering toolbox: testing.&lt;/p&gt;
&lt;p&gt;Most likely, when you were developing your function, you were running it over and over to confirm it still did what it was supposed to. You gave it input, and checked that it returned the right output.&lt;/p&gt;
&lt;p&gt;You were testing your function, and it took a lot of time.&lt;/p&gt;
&lt;p&gt;With tests, we can automate this process. Mark, for instance, knows that when he puts the file conversation25.csv* into &lt;em&gt;inspect_convo&lt;/em&gt;, it should return information about the number of speakers (2), the length of the file (10 minutes and 3 seconds), and the number of utterances (9438). He does not have to keep checking this himself, but can put his knowledge inside a test:&lt;/p&gt;
&lt;p&gt;test_that(“Conversation inspection returns the right results”, {&lt;/p&gt;
&lt;h1 id=&quot;load-the-test-object-and-run-inspect_convo&quot;&gt;load the test object and run inspect_convo&lt;/h1&gt;
&lt;p&gt;load(“conversation25.Rda”)
conversation &amp;#x3C;- inspect_convo(conversation25)&lt;/p&gt;
&lt;h1 id=&quot;inspect_convo-should-return-the-right-information&quot;&gt;inspect_convo should return the right information&lt;/h1&gt;
&lt;p&gt;expect_true(conversation[1] == “Number of speakers: 2”)
expect_true(conversation[2] == “Length of conversation: 10:03”)
expect_true(conversation[3] == “Number of utterances: 9438”)
})Now he simply runs the tests, and Rstudio will tell him if they pass. This quickly starts saving him a lot of time, especially when the package grows and starts including more functions. With one click, Mark can confirm that everything, everywhere, is OK.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;382&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-f3599774.CaOP46cu_Z1C3a1f.webp&quot; srcset=&quot;&quot;&gt;
The Rstudio view of the tests in this package confirm that every function is operating as it should.Being able to check functionality like this comes with a lot of freedom, to grow your package, but also to improve the things already written. How efficient is that function you wrote, really? When you edit (or “refactor”) the code, your tests give you the peace of mind that your edits have not caused any inadvertent problems. After all, as soon as something breaks, you will know!&lt;/p&gt;
&lt;h3 id=&quot;but-what-about-my-paper&quot;&gt;But what about my paper?&lt;/h3&gt;
&lt;p&gt;While you may be happy that someone else can reuse your functions, it is likely that the original goal of your research project was not to write a toolkit, but a paper. Not to worry, there is a designated space for this inside an R package: a vignette.&lt;/p&gt;
&lt;p&gt;In a vignette, you take a reader through your project from A to Z. While explaining your workflow in accompanying markdown-formatted text, you apply your functions in blocks of R code, and the resulting document shows both the code and the resulting output. This is the cherry on top: you have turned your research into an easily reusable toolkit, and shown how to use the functions in a reproducible document.&lt;/p&gt;
&lt;h3 id=&quot;would-you-like-some-help&quot;&gt;Would you like some help?&lt;/h3&gt;
&lt;p&gt;There are a lot of online resources that can help you work on your first package. For one, the book &lt;a href=&quot;https://r-pkgs.org/&quot;&gt;R Packages&lt;/a&gt; is a resource I cannot recommend enough. It has been the basis for the &lt;a href=&quot;https://carpentries-incubator.github.io/lesson-R-packaging/&quot;&gt;Carpentries lesson “R Packaging”&lt;/a&gt;, which is regularly held as part of the eScience Center’s digital skills workshops. Take a look &lt;a href=&quot;https://www.esciencecenter.nl/events/?f=workshops&quot;&gt;at our schedule&lt;/a&gt; to see upcoming dates for “Reproducible Research with R Packages”, and join us!&lt;/p&gt;
&lt;p&gt;*) The story used in this blog is inspired by the package &lt;a href=&quot;https://github.com/elpaco-escience/talkr/&quot;&gt;&lt;em&gt;talkr&lt;/em&gt;&lt;/a&gt;, which is part of &lt;a href=&quot;https://research-software-directory.org/projects/diversity-aware&quot;&gt;&lt;em&gt;Towards next-generation scientific computing tools for diversity-aware language science and technology&lt;/em&gt;&lt;/a&gt;, a project with Mark Dingemanse and Andreas Liesenfeld at the Radboud Universiteit Nijmegen. You can read more about the real Mark at his own website: &lt;a href=&quot;https://markdingemanse.net/&quot;&gt;markdingemanse.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;**) The functions and files in this blog are simplified and fictionalised for ease of reading.&lt;/p&gt;</description><pubDate>Wed, 30 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If after reading this post you are motivated to make your own R package, consider joining our upcoming workshop! &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.nl/e/reproducible-research-with-r-packages-tickets-672884123527&quot;&gt;&lt;em&gt;Free tickets are now available&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you are an R user, think about this scenario:&lt;/p&gt;
&lt;p&gt;How often have you reused someone else’s code — a colleague’s workflow, perhaps a script you found as an appendix in a paper? Did it run right away? Was it easy to reuse?&lt;/p&gt;
&lt;p&gt;Now, ask yourself whether you have used someone else’s packaged code. How often have you started your own script with &lt;em&gt;library (packagename)&lt;/em&gt;, and used functions that are not part of base R?&lt;/p&gt;
&lt;p&gt;I am willing to bet quite a lot that the second scenario is an order of magnitude more common than the first. There is a reason for this: packages are made to be reused. Scripts, while technically reusable, are not.&lt;/p&gt;
&lt;p&gt;Let me now ask you about your own work: do you want it to be reused?&lt;/p&gt;
&lt;p&gt;You know what you have to do now, right?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-bebe4eaf.DCiM-mIO_2mR8fo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kadh?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Kira auf der Heide&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;but-making-a-package-isnt-that-complicated&quot;&gt;But making a package… isn’t that complicated?&lt;/h3&gt;
&lt;p&gt;An R package distinguishes itself from scripted code in a few ways, but it is much less complex than you may think.&lt;/p&gt;
&lt;p&gt;First of all, when your code is packaged, it is contained in a standardized folder structure. The code itself lives in a designated folder (aptly named ‘R’). In addition, the root of the package contains files with some basic information about your package — like the title, the authors, and the license for future users.&lt;/p&gt;
&lt;p&gt;Secondly, and perhaps most crucially, packaged code consists of functions only. Functions are the units at the centre of a package. They take information as arguments and return an output. For example, I have a function called *multiply. *This function, you guessed it, multiplies the two arguments I give it, and returns the result:&lt;/p&gt;
&lt;p&gt;multiply &amp;#x3C;- function(a, b){
return(a * b)
}After including this function in a package — let’s call it *mypackage — *someone else can now use it without opening and running the entire codebase, but instead by attaching the package and calling the function:&lt;/p&gt;
&lt;p&gt;&gt; library(myPackage)
&gt; multiply(3,4)
[1] 12You have likely written functions before. And you know how folders work. To dot the i’s and cross the t’s, Rstudio is here to help: it contains many built-in functions to make package creation a breeze.&lt;/p&gt;
&lt;h3 id=&quot;your-work-deserves-to-be-reused&quot;&gt;Your work deserves to be reused.&lt;/h3&gt;
&lt;p&gt;Just in case you are now doubting yourself, please don’t. Scripting an analysis is more than just applying existing calculations. The workflow itself is an original thought. Even if you have not, say, designed a new statistical method yourself, the methods you choose, the way you select and handle your data, the visualisations you make — they are your work, and could be reused as a standardised workflow in your field.&lt;/p&gt;
&lt;p&gt;Let’s take an example. Mark*, a linguistics professor, runs frequent analyses on datasets made from taped conversations. He uses R to uncover the unwritten rules of conversation, finding out how people weave their utterances together. With this data, he creates &lt;a href=&quot;https://ideophone.org/snailplot-rmd/&quot;&gt;fantastic&lt;/a&gt; &lt;a href=&quot;https://markdingemanse.net/publications/visuals/how-asr-training-data-differs-from-real-conversation&quot;&gt;visualisations&lt;/a&gt;, which give insight into the conversational dynamics at play.&lt;/p&gt;
&lt;p&gt;Mark has hundreds of conversations to analyse, so he made functions that contains the essential elements of his workflow. Now, when he loads a new conversation, he can for instance use this function** to quickly get an overview of the basic statistics:&lt;/p&gt;
&lt;p&gt;&gt; conversation &amp;#x3C;- read.csv(“data/conversation25.csv”)
&gt; inspect_convo(conversation)
Number of speakers: 2
Length of conversation: 10:03
Number of utterances: 9438But Mark does not work alone. His group contains PhD students and postdocs, and is a popular place for bachelor and master internships. He shares his scripts with his group, but they can be a daunting sight for those who have not programmed much before. And as his toolkit grows, he loses track of the different elements it contains, and what updates he has shared with whom.&lt;/p&gt;
&lt;p&gt;Mark needs an R package.&lt;/p&gt;
&lt;h3 id=&quot;a-package-makes-you-a-better-programmer&quot;&gt;A package makes you a better programmer.&lt;/h3&gt;
&lt;p&gt;An important element of packaged functions is their documentation: a user who only has access to the name of the function, needs to know how to use it. But writing documentation is not just for users: it does something for you as a developer as well.&lt;/p&gt;
&lt;p&gt;Writing down the logic of your functions — what goes in? What comes out? Exactly what formats are needed for each argument?— helps you think more critically about the objects you use and create as part of your workflow. You may not expect it, but documentation is a powerful way to take a step back and start viewing your set of functions as a whole.&lt;/p&gt;
&lt;p&gt;This is where you go from scripting to software engineering.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-921434e2.m43Kfwp4_Z1RWn4W.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@retrosupply?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;RetroSupply&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;packaged-code-is-more-robust-and-developing-it-is-more-efficient&quot;&gt;Packaged code is more robust, and developing it is more efficient.&lt;/h3&gt;
&lt;p&gt;Because your functions are in a package, you now also have access to another powerful tool in the software engineering toolbox: testing.&lt;/p&gt;
&lt;p&gt;Most likely, when you were developing your function, you were running it over and over to confirm it still did what it was supposed to. You gave it input, and checked that it returned the right output.&lt;/p&gt;
&lt;p&gt;You were testing your function, and it took a lot of time.&lt;/p&gt;
&lt;p&gt;With tests, we can automate this process. Mark, for instance, knows that when he puts the file conversation25.csv* into &lt;em&gt;inspect_convo&lt;/em&gt;, it should return information about the number of speakers (2), the length of the file (10 minutes and 3 seconds), and the number of utterances (9438). He does not have to keep checking this himself, but can put his knowledge inside a test:&lt;/p&gt;
&lt;p&gt;test_that(“Conversation inspection returns the right results”, {&lt;/p&gt;
&lt;h1 id=&quot;load-the-test-object-and-run-inspect_convo&quot;&gt;load the test object and run inspect_convo&lt;/h1&gt;
&lt;p&gt;load(“conversation25.Rda”)
conversation &amp;#x3C;- inspect_convo(conversation25)&lt;/p&gt;
&lt;h1 id=&quot;inspect_convo-should-return-the-right-information&quot;&gt;inspect_convo should return the right information&lt;/h1&gt;
&lt;p&gt;expect_true(conversation[1] == “Number of speakers: 2”)
expect_true(conversation[2] == “Length of conversation: 10:03”)
expect_true(conversation[3] == “Number of utterances: 9438”)
})Now he simply runs the tests, and Rstudio will tell him if they pass. This quickly starts saving him a lot of time, especially when the package grows and starts including more functions. With one click, Mark can confirm that everything, everywhere, is OK.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why your research deserves to be an R package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;382&quot; src=&quot;https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-f3599774.CaOP46cu_Z1C3a1f.webp&quot; srcset=&quot;&quot;&gt;
The Rstudio view of the tests in this package confirm that every function is operating as it should.Being able to check functionality like this comes with a lot of freedom, to grow your package, but also to improve the things already written. How efficient is that function you wrote, really? When you edit (or “refactor”) the code, your tests give you the peace of mind that your edits have not caused any inadvertent problems. After all, as soon as something breaks, you will know!&lt;/p&gt;
&lt;h3 id=&quot;but-what-about-my-paper&quot;&gt;But what about my paper?&lt;/h3&gt;
&lt;p&gt;While you may be happy that someone else can reuse your functions, it is likely that the original goal of your research project was not to write a toolkit, but a paper. Not to worry, there is a designated space for this inside an R package: a vignette.&lt;/p&gt;
&lt;p&gt;In a vignette, you take a reader through your project from A to Z. While explaining your workflow in accompanying markdown-formatted text, you apply your functions in blocks of R code, and the resulting document shows both the code and the resulting output. This is the cherry on top: you have turned your research into an easily reusable toolkit, and shown how to use the functions in a reproducible document.&lt;/p&gt;
&lt;h3 id=&quot;would-you-like-some-help&quot;&gt;Would you like some help?&lt;/h3&gt;
&lt;p&gt;There are a lot of online resources that can help you work on your first package. For one, the book &lt;a href=&quot;https://r-pkgs.org/&quot;&gt;R Packages&lt;/a&gt; is a resource I cannot recommend enough. It has been the basis for the &lt;a href=&quot;https://carpentries-incubator.github.io/lesson-R-packaging/&quot;&gt;Carpentries lesson “R Packaging”&lt;/a&gt;, which is regularly held as part of the eScience Center’s digital skills workshops. Take a look &lt;a href=&quot;https://www.esciencecenter.nl/events/?f=workshops&quot;&gt;at our schedule&lt;/a&gt; to see upcoming dates for “Reproducible Research with R Packages”, and join us!&lt;/p&gt;
&lt;p&gt;*) The story used in this blog is inspired by the package &lt;a href=&quot;https://github.com/elpaco-escience/talkr/&quot;&gt;&lt;em&gt;talkr&lt;/em&gt;&lt;/a&gt;, which is part of &lt;a href=&quot;https://research-software-directory.org/projects/diversity-aware&quot;&gt;&lt;em&gt;Towards next-generation scientific computing tools for diversity-aware language science and technology&lt;/em&gt;&lt;/a&gt;, a project with Mark Dingemanse and Andreas Liesenfeld at the Radboud Universiteit Nijmegen. You can read more about the real Mark at his own website: &lt;a href=&quot;https://markdingemanse.net/&quot;&gt;markdingemanse.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;**) The functions and files in this blog are simplified and fictionalised for ease of reading.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/why-your-research-deserves-to-be-an-r-pa-bebe4eaf.DCiM-mIO.jpg" medium="image"/><author>Barbara Vreede</author></item><item><title>Lilio — a calendar package for machine learning with time series data</title><link>https://blog.esciencecenter.nl/posts/2023-08-21---lilio-a-calendar-package-for-machine-learning-with-time-seri</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-08-21---lilio-a-calendar-package-for-machine-learning-with-time-seri</guid><description>&lt;h2 id=&quot;designed-with-the-s2s-community-available-for-everyone&quot;&gt;Designed with the S2S community, available for everyone&lt;/h2&gt;
&lt;p&gt;These are just some of the questions that scientists in the field of sub-seasonal to seasonal (S2S) weather and climate prediction have to deal with on a daily basis. Especially now that the use of machine learning is &lt;a href=&quot;https://s2s-ai-challenge.github.io/&quot;&gt;gaining traction&lt;/a&gt;. In this blog post, we introduce &lt;a href=&quot;https://lilio.readthedocs.io/en/latest/index.html&quot;&gt;Lilio&lt;/a&gt;, a new calendar &lt;a href=&quot;https://pypi.org/project/lilio/&quot;&gt;package &lt;/a&gt;that was designed to help tackle these questions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;295&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-42268afa.DQXZijBm_kI8Gb.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://github.com/AI4S2S/lilio&quot;&gt;https://github.com/AI4S2S/lilio&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-niche&quot;&gt;The niche&lt;/h2&gt;
&lt;p&gt;Before we dive into the capabilities of Lilio, let me briefly review why existing packages didn’t cut the deal for us. &lt;a href=&quot;https://pandas.pydata.org/&quot;&gt;Pandas&lt;/a&gt; is great and we rely on it, but we wanted more flexibility to construct varying intervals with custom gaps in between. And instead of a continuous index, we wanted to exploit the periodicity in our use cases. Existing time series models (e.g. *&lt;a href=&quot;https://medium.com/unit8-machine-learning-publication/time-series-forecasting-using-past-and-future-external-data-with-darts-1f0539585993&quot;&gt;Darts&lt;/a&gt;) often apply the same model irrespective of the forecast issue date, and the forecasts are anchored to said issue date. By contrast, our experiments are usually anchored to a clear target period, and each target may have a unique set of predictors. We have different models with different precursors for a windy May, a wet monsoon, a mild winter, …&lt;/p&gt;
&lt;h2 id=&quot;the-fill&quot;&gt;The fill&lt;/h2&gt;
&lt;p&gt;So, how does Lilio help with all of that? First of all, we stack the years to obtain a 2-dimensional calendar. Each row represents a year, and columns are intervals within that year. Typically we have several precursor periods leading up to one or more target periods. This aligns nicely with the common representation of samples and features in ML data. In our case, the target is in the rightmost column(s).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-e88dbf7f.DGXG8Njk_2unjb.webp&quot; srcset=&quot;&quot;&gt;
Conceptual illustration of the structure of our calendars.We define the “anchor date” to be between the target and precursor periods. All other intervals are expressed as offsets to this anchor date. Conveniently, this eliminates any ambiguity related to leap years. Here’s a calendar generated with Lilio:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;558&quot; height=&quot;253&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-fd12e9cf.CFTBVga4_Z18KxhS.webp&quot; srcset=&quot;&quot;&gt;
Example calendar with uniform 10-day intervals, here represented as offsets to the anchor date.By default, we include as many blocks (of a given frequency) as fit in one year but not more. To control this behaviour, Lilio provides options to allow or prohibit overlap. This makes it straightforward to apply existing train/test splitting strategies without leakage.&lt;/p&gt;
&lt;h2 id=&quot;anchor--offset--date&quot;&gt;Anchor + offset = date&lt;/h2&gt;
&lt;p&gt;Initially, Lilio calendars don’t include years. Only after we map the calendar onto a given year range or dataset, actual dates can be calculated. Since the start or end date of the calendar doesn’t always nicely align with the input data, the calendar also comes with a method to map it to the range of available data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;278&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-bd2f18b7.CQTMkBtB_1LmwU6.webp&quot; srcset=&quot;&quot;&gt;
Same calendar as above but plotted on a datetime axis. The anchor date for this calendar is 30 November. Combined with the anchor years 2020 and 2021, the actual dates can be inferred.&lt;/p&gt;
&lt;h2 id=&quot;visualizations--wishful-drawing&quot;&gt;Visualizations &amp;#x26; wishful drawing&lt;/h2&gt;
&lt;p&gt;The visualizations shown above are generated automatically. This turns out to be very helpful in the initial process of setting up your experiments. We even found ourselves making “wishful drawings” to communicate about alternative calendars that we’d like to support.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;185&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-a153c1a1.ljuxYc1j_Z266lfM.webp&quot; srcset=&quot;&quot;&gt;
Illustrated feature request for a “rolling calendar”&lt;/p&gt;
&lt;h2 id=&quot;resampling&quot;&gt;Resampling&lt;/h2&gt;
&lt;p&gt;Lilio’s resampling functionality can be used to aggregate the input data based on the calendar’s intervals. Here, again, we heavily rely on the presence of bounded intervals. By using these as resampling bins, we ensure that all input data ends up on the exact same time axis.&lt;/p&gt;
&lt;h2 id=&quot;simple-and-custom-calendars&quot;&gt;Simple and custom calendars&lt;/h2&gt;
&lt;p&gt;For many applications, a simple weekly, monthly, or (n-)daily calendar may be all you need, and Lilio makes this super easy. With only a bit more effort, you can also construct calendars with gaps and overlapping intervals of varying lengths. Here’s a more exotic calendar for predicting the chances of a white Christmas:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;581&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-17ff14ed.CAzdFlPH_7Ogq9.webp&quot; srcset=&quot;&quot;&gt;
This calendar uses more fine-grained information closer to the target&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;Lilio has been developed in the context of a larger &lt;a href=&quot;https://research-software-directory.org/projects/ai4s2s&quot;&gt;project &lt;/a&gt;in which we are developing a Python package to set up and streamline S2S — machine learning workflows. It will be a key component in our experimental setup. At the same time, the calendar is also very suitable as a stand-alone component for use in other applications. We are curious to learn about new use cases that you may have for it.&lt;/p&gt;
&lt;h2 id=&quot;final-note&quot;&gt;Final note&lt;/h2&gt;
&lt;p&gt;Collaborative research software development is a &lt;a href=&quot;https://github.com/AI4S2S/lilio/graphs/contributors&quot;&gt;team effort&lt;/a&gt;. Please give appropriate credit and consider&lt;a href=&quot;https://github.com/AI4S2S/lilio&quot;&gt; joining us&lt;/a&gt; 😊. And if you read up to this point and still wonder who Lilio was: &lt;a href=&quot;https://en.wikipedia.org/wiki/Aloysius_Lilius&quot;&gt;here you go&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 21 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;designed-with-the-s2s-community-available-for-everyone&quot;&gt;Designed with the S2S community, available for everyone&lt;/h2&gt;
&lt;p&gt;These are just some of the questions that scientists in the field of sub-seasonal to seasonal (S2S) weather and climate prediction have to deal with on a daily basis. Especially now that the use of machine learning is &lt;a href=&quot;https://s2s-ai-challenge.github.io/&quot;&gt;gaining traction&lt;/a&gt;. In this blog post, we introduce &lt;a href=&quot;https://lilio.readthedocs.io/en/latest/index.html&quot;&gt;Lilio&lt;/a&gt;, a new calendar &lt;a href=&quot;https://pypi.org/project/lilio/&quot;&gt;package &lt;/a&gt;that was designed to help tackle these questions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;295&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-42268afa.DQXZijBm_kI8Gb.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://github.com/AI4S2S/lilio&quot;&gt;https://github.com/AI4S2S/lilio&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-niche&quot;&gt;The niche&lt;/h2&gt;
&lt;p&gt;Before we dive into the capabilities of Lilio, let me briefly review why existing packages didn’t cut the deal for us. &lt;a href=&quot;https://pandas.pydata.org/&quot;&gt;Pandas&lt;/a&gt; is great and we rely on it, but we wanted more flexibility to construct varying intervals with custom gaps in between. And instead of a continuous index, we wanted to exploit the periodicity in our use cases. Existing time series models (e.g. *&lt;a href=&quot;https://medium.com/unit8-machine-learning-publication/time-series-forecasting-using-past-and-future-external-data-with-darts-1f0539585993&quot;&gt;Darts&lt;/a&gt;) often apply the same model irrespective of the forecast issue date, and the forecasts are anchored to said issue date. By contrast, our experiments are usually anchored to a clear target period, and each target may have a unique set of predictors. We have different models with different precursors for a windy May, a wet monsoon, a mild winter, …&lt;/p&gt;
&lt;h2 id=&quot;the-fill&quot;&gt;The fill&lt;/h2&gt;
&lt;p&gt;So, how does Lilio help with all of that? First of all, we stack the years to obtain a 2-dimensional calendar. Each row represents a year, and columns are intervals within that year. Typically we have several precursor periods leading up to one or more target periods. This aligns nicely with the common representation of samples and features in ML data. In our case, the target is in the rightmost column(s).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-e88dbf7f.DGXG8Njk_2unjb.webp&quot; srcset=&quot;&quot;&gt;
Conceptual illustration of the structure of our calendars.We define the “anchor date” to be between the target and precursor periods. All other intervals are expressed as offsets to this anchor date. Conveniently, this eliminates any ambiguity related to leap years. Here’s a calendar generated with Lilio:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;558&quot; height=&quot;253&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-fd12e9cf.CFTBVga4_Z18KxhS.webp&quot; srcset=&quot;&quot;&gt;
Example calendar with uniform 10-day intervals, here represented as offsets to the anchor date.By default, we include as many blocks (of a given frequency) as fit in one year but not more. To control this behaviour, Lilio provides options to allow or prohibit overlap. This makes it straightforward to apply existing train/test splitting strategies without leakage.&lt;/p&gt;
&lt;h2 id=&quot;anchor--offset--date&quot;&gt;Anchor + offset = date&lt;/h2&gt;
&lt;p&gt;Initially, Lilio calendars don’t include years. Only after we map the calendar onto a given year range or dataset, actual dates can be calculated. Since the start or end date of the calendar doesn’t always nicely align with the input data, the calendar also comes with a method to map it to the range of available data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;602&quot; height=&quot;278&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-bd2f18b7.CQTMkBtB_1LmwU6.webp&quot; srcset=&quot;&quot;&gt;
Same calendar as above but plotted on a datetime axis. The anchor date for this calendar is 30 November. Combined with the anchor years 2020 and 2021, the actual dates can be inferred.&lt;/p&gt;
&lt;h2 id=&quot;visualizations--wishful-drawing&quot;&gt;Visualizations &amp;#x26; wishful drawing&lt;/h2&gt;
&lt;p&gt;The visualizations shown above are generated automatically. This turns out to be very helpful in the initial process of setting up your experiments. We even found ourselves making “wishful drawings” to communicate about alternative calendars that we’d like to support.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;185&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-a153c1a1.ljuxYc1j_Z266lfM.webp&quot; srcset=&quot;&quot;&gt;
Illustrated feature request for a “rolling calendar”&lt;/p&gt;
&lt;h2 id=&quot;resampling&quot;&gt;Resampling&lt;/h2&gt;
&lt;p&gt;Lilio’s resampling functionality can be used to aggregate the input data based on the calendar’s intervals. Here, again, we heavily rely on the presence of bounded intervals. By using these as resampling bins, we ensure that all input data ends up on the exact same time axis.&lt;/p&gt;
&lt;h2 id=&quot;simple-and-custom-calendars&quot;&gt;Simple and custom calendars&lt;/h2&gt;
&lt;p&gt;For many applications, a simple weekly, monthly, or (n-)daily calendar may be all you need, and Lilio makes this super easy. With only a bit more effort, you can also construct calendars with gaps and overlapping intervals of varying lengths. Here’s a more exotic calendar for predicting the chances of a white Christmas:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lilio — a calendar package for machine learning with time series data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;581&quot; height=&quot;269&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-17ff14ed.CAzdFlPH_7Ogq9.webp&quot; srcset=&quot;&quot;&gt;
This calendar uses more fine-grained information closer to the target&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;Lilio has been developed in the context of a larger &lt;a href=&quot;https://research-software-directory.org/projects/ai4s2s&quot;&gt;project &lt;/a&gt;in which we are developing a Python package to set up and streamline S2S — machine learning workflows. It will be a key component in our experimental setup. At the same time, the calendar is also very suitable as a stand-alone component for use in other applications. We are curious to learn about new use cases that you may have for it.&lt;/p&gt;
&lt;h2 id=&quot;final-note&quot;&gt;Final note&lt;/h2&gt;
&lt;p&gt;Collaborative research software development is a &lt;a href=&quot;https://github.com/AI4S2S/lilio/graphs/contributors&quot;&gt;team effort&lt;/a&gt;. Please give appropriate credit and consider&lt;a href=&quot;https://github.com/AI4S2S/lilio&quot;&gt; joining us&lt;/a&gt; 😊. And if you read up to this point and still wonder who Lilio was: &lt;a href=&quot;https://en.wikipedia.org/wiki/Aloysius_Lilius&quot;&gt;here you go&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/lilio-a-calendar-package-for-machine-lea-42268afa.DQXZijBm.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Summer is here, and so are large language models.</title><link>https://blog.esciencecenter.nl/posts/2023-07-10---summer-is-here-and-so-are-large-language-models</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-07-10---summer-is-here-and-so-are-large-language-models</guid><description>&lt;p&gt;Welcome to the technological revolution of 2023, where the landscape of communication and information processing has been forever transformed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Summer is here, and so are large language models.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/summer-is-here-and-so-are-large-language-d532273d.DPS4yuCo_2nfro4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@deepmind?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Google DeepMind&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The early months of this year have been dominated by the extraordinary rise of ChatGPT and other large language models. These remarkable AI-powered systems have become the driving force behind an unprecedented level of automation and efficiency in generating summaries and content. In fact, the emergence of ChatGPT has been so influential that it has rendered the traditional practice of crafting personal summary blogs unnecessary. With its unparalleled capabilities, ChatGPT now stands as the ultimate tool to effortlessly generate comprehensive and insightful summaries, paving the way for a new era of intelligent content creation.&lt;/p&gt;
&lt;p&gt;The paragraph above was written by ChatGPT. **Other entries on our blog are still written by humans though, and good ones too. So below are our favourite blogs on large language models:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/interview-with-chatgpt-c17b87214b9c?sk=f49c1d589776446384b8ad35abcb088e&quot;&gt;Aron Jansen interviewed ChatGPT&lt;/a&gt; about the eScience Center. Amazingly, it did not know the eScience Center at the time (it definitely does now!). Arguably, this post was mostly written by ChatGPT — but Aron shows us the art of good prompting.&lt;/p&gt;
&lt;p&gt;Candace Makeda Moore warned us about the &lt;a href=&quot;https://blog.esciencecenter.nl/the-medical-chatbot-will-not-see-you-now-b2c5d67c7029?sk=d94a5bf43e44b0bfdec4a2552154b83c&quot;&gt;use of ChatGPT in medical contexts&lt;/a&gt;, in this excellent reference of the pitfalls and problems of putting all your trust in these models.&lt;/p&gt;
&lt;p&gt;To give some context to the hype, &lt;a href=&quot;https://blog.esciencecenter.nl/language-modeling-the-first-100-years-357556816148?sk=d21561541fa78fa4fa4b43e491dc5131&quot;&gt;Carsten Schnober wrote a blog about the history of language models&lt;/a&gt;. It’s an unparalleled and crystal clear description of the history of language models, utopian and dystopian fantasies, as well as concrete potentials and risks.&lt;/p&gt;
&lt;p&gt;An older, but still very relevant post on language models was written by our former engineer Florian Huber. &lt;a href=&quot;https://blog.esciencecenter.nl/king-man-woman-king-9a7fd2935a85?sk=444566a4998338af9d2bc4fa8e7ba79b&quot;&gt;He explains what language models actually “understand”&lt;/a&gt;, and drew his own funny comics to accompany the story.&lt;/p&gt;
&lt;p&gt;The eScience Center blog is going on a summer hiatus. In the meantime, we hope you enjoy these excellent stories by our excellent colleagues.*&lt;/p&gt;</description><pubDate>Mon, 10 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to the technological revolution of 2023, where the landscape of communication and information processing has been forever transformed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Summer is here, and so are large language models.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/summer-is-here-and-so-are-large-language-d532273d.DPS4yuCo_2nfro4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@deepmind?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Google DeepMind&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The early months of this year have been dominated by the extraordinary rise of ChatGPT and other large language models. These remarkable AI-powered systems have become the driving force behind an unprecedented level of automation and efficiency in generating summaries and content. In fact, the emergence of ChatGPT has been so influential that it has rendered the traditional practice of crafting personal summary blogs unnecessary. With its unparalleled capabilities, ChatGPT now stands as the ultimate tool to effortlessly generate comprehensive and insightful summaries, paving the way for a new era of intelligent content creation.&lt;/p&gt;
&lt;p&gt;The paragraph above was written by ChatGPT. **Other entries on our blog are still written by humans though, and good ones too. So below are our favourite blogs on large language models:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/interview-with-chatgpt-c17b87214b9c?sk=f49c1d589776446384b8ad35abcb088e&quot;&gt;Aron Jansen interviewed ChatGPT&lt;/a&gt; about the eScience Center. Amazingly, it did not know the eScience Center at the time (it definitely does now!). Arguably, this post was mostly written by ChatGPT — but Aron shows us the art of good prompting.&lt;/p&gt;
&lt;p&gt;Candace Makeda Moore warned us about the &lt;a href=&quot;https://blog.esciencecenter.nl/the-medical-chatbot-will-not-see-you-now-b2c5d67c7029?sk=d94a5bf43e44b0bfdec4a2552154b83c&quot;&gt;use of ChatGPT in medical contexts&lt;/a&gt;, in this excellent reference of the pitfalls and problems of putting all your trust in these models.&lt;/p&gt;
&lt;p&gt;To give some context to the hype, &lt;a href=&quot;https://blog.esciencecenter.nl/language-modeling-the-first-100-years-357556816148?sk=d21561541fa78fa4fa4b43e491dc5131&quot;&gt;Carsten Schnober wrote a blog about the history of language models&lt;/a&gt;. It’s an unparalleled and crystal clear description of the history of language models, utopian and dystopian fantasies, as well as concrete potentials and risks.&lt;/p&gt;
&lt;p&gt;An older, but still very relevant post on language models was written by our former engineer Florian Huber. &lt;a href=&quot;https://blog.esciencecenter.nl/king-man-woman-king-9a7fd2935a85?sk=444566a4998338af9d2bc4fa8e7ba79b&quot;&gt;He explains what language models actually “understand”&lt;/a&gt;, and drew his own funny comics to accompany the story.&lt;/p&gt;
&lt;p&gt;The eScience Center blog is going on a summer hiatus. In the meantime, we hope you enjoy these excellent stories by our excellent colleagues.*&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/summer-is-here-and-so-are-large-language-d532273d.DPS4yuCo.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Mcfly: An easy-to-use tool for deep learning for time series classification</title><link>https://blog.esciencecenter.nl/posts/2023-06-26---mcfly-an-easy-to-use-tool-for-deep-learning-for-time-series-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-06-26---mcfly-an-easy-to-use-tool-for-deep-learning-for-time-series-</guid><description>&lt;h2 id=&quot;a-new-mcfly-30-release-is-out-see-how-it-works-and-how-it-can-help-you-to-apply-deep-learning-to-time-series-classification&quot;&gt;A new mcfly 3.0 release is out. See how it works and how it can help you to apply deep learning to time series classification.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Apr 15, 2020&lt;/p&gt;
&lt;p&gt;Once the models are generated, they will be trained on the given data (or a subset to speed things up). This is done using &lt;code&gt;train_models_on_samples&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial/blob/master/notebooks/tutorial/tutorial_quick.ipynb&quot;&gt;See full tutorial notebook for more information.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The performance of the trained models can then interactively be compared using mcfly***, for example by comparing the accuracy on the validation set versus a number of key hyperparameters (see screenshot below). The built-in visualization is interactive and allows to select specific models (here numbered 0 to 7), or select specific architectures (here ‘CNN’ or ‘InceptionTime’), or learning rates. Most important feature to look at are the two plots on the top which display the development of the accuracy on both the training set and the validation set. A good model should perform decently well on both sides.&lt;/p&gt;
&lt;p&gt;mcfly build-in visualization of the model performance. While in this example all models achieve good results on the training dataset, much fewer reach decent results on the validation dataset.&lt;/p&gt;
&lt;h3 id=&quot;overfitting&quot;&gt;Overfitting&lt;/h3&gt;
&lt;p&gt;Since the RacketSports dataset only consits of 150 training examples, you will frequently see that generated deep learning models will &lt;strong&gt;overfit&lt;/strong&gt; the data. Overfitting is one of the most common problems when working with deep learning. It essentially means that you optimize too much on the training data so that the performance on unseen data will suffer. A typical signature for this is that models will do well on the training data (high training accuracy), but will perform poorly on the validation data (low validation accuracy). A typical example is shown below with 8 models, most of which report high &lt;code&gt;train_accuracy&lt;/code&gt;but very low &lt;code&gt;val_accuracy&lt;/code&gt;values!&lt;/p&gt;
&lt;p&gt;Example results of 8 mcfly generated models trained on RacketSports dataset. Six perform well on the training data, but only 2 models also perform well on the validation data.If we now pick one of the better performing models (or iteratively generate and train more models), then we can get quite good results on the RacketSports dataset. Below you can see how we could inspect this by generating a confusion matrix. And here it indeed reveals that most of the times the picked &lt;strong&gt;model is correctly predicting the actual activity!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Generating a confusion matrix using the validation dataset.&lt;/p&gt;
&lt;h3 id=&quot;and-now-what-are-you-waiting-for&quot;&gt;And now… what are you waiting for?&lt;/h3&gt;
&lt;p&gt;Grab some interesting time series data and try out some deep learning!&lt;/p&gt;
&lt;h2 id=&quot;did-you-use-mcfly&quot;&gt;Did you use mcfly?&lt;/h2&gt;
&lt;p&gt;Awesome! We are always happy to hear from people who have made good use of &lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt;. Please get in touch if you have suggestions and ideas for future developments or fixes (e.g. via &lt;a href=&quot;https://github.com/NLeSC/mcfly&quot;&gt;GitHub&lt;/a&gt;, via&lt;a href=&quot;https://twitter.com/me_datapoint&quot;&gt; twitter&lt;/a&gt;, or as response to this post). Many thanks.&lt;/p&gt;
&lt;p&gt;**Reference:
**D. van Kuppevelt, C. Meijer, F. Huber, A. van der Ploeg, S. Georgievska, V.T. van Hees. &lt;em&gt;Mcfly: Automated deep learning on time series.&lt;/em&gt; SoftwareX, Volume 12, 2020. &lt;a href=&quot;https://doi.org/10.1016/j.softx.2020.100548&quot;&gt;doi: 10.1016/j.softx.2020.100548&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/mcfly-time-series-classification-made-easy-e47de8d29838&quot;&gt;Former blog post from 2017&lt;/a&gt; by [Dafne van Kuppevelt]&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; on pypi: &lt;a href=&quot;https://pypi.org/project/mcfly/&quot;&gt;https://pypi.org/project/mcfly/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; on GitHub: &lt;a href=&quot;https://github.com/NLeSC/mcfly&quot;&gt;https://github.com/NLeSC/mcfly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ready-to-use RacketSports dataset on zenodo: &lt;a href=&quot;https://zenodo.org/record/3743603#.XpAypXKxUuU&quot;&gt;https://zenodo.org/record/3743603&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; tutorial(s): &lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial&quot;&gt;https://github.com/NLeSC/mcfly-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tutorial notebook with all code mentioned in this blog post: **&lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial/blob/main/notebooks/tutorial/tutorial_quick.ipynb&quot;&gt;https://github.com/NLeSC/mcfly-tutorial/blob/main/notebooks/tutorial/tutorial_quick.ipynb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;mcfly&lt;/em&gt;*** *was developed at the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;&lt;strong&gt;Netherlands eScience Center&lt;/strong&gt;&lt;/a&gt; by [Dafne van Kuppevelt], Christiaan Meijer, [Sonja Georgievska], [Vincent van Hees], [Florian Huber], [Patrick Bos], [Jurriaan H. Spaaks], Mateusz Kuzak, [Johan Hidding], [Atze van der Ploeg].&lt;/p&gt;
&lt;p&gt;Thanks to Johan Rheeder, [Sonja Georgievska], [Dafne van Kuppevelt], [Peter Kalverla,] [Patrick Bos], and [Tom Bakker] for helpful comments and edits.&lt;/p&gt;</description><pubDate>Mon, 26 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;a-new-mcfly-30-release-is-out-see-how-it-works-and-how-it-can-help-you-to-apply-deep-learning-to-time-series-classification&quot;&gt;A new mcfly 3.0 release is out. See how it works and how it can help you to apply deep learning to time series classification.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Apr 15, 2020&lt;/p&gt;
&lt;p&gt;Once the models are generated, they will be trained on the given data (or a subset to speed things up). This is done using &lt;code&gt;train_models_on_samples&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial/blob/master/notebooks/tutorial/tutorial_quick.ipynb&quot;&gt;See full tutorial notebook for more information.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The performance of the trained models can then interactively be compared using mcfly***, for example by comparing the accuracy on the validation set versus a number of key hyperparameters (see screenshot below). The built-in visualization is interactive and allows to select specific models (here numbered 0 to 7), or select specific architectures (here ‘CNN’ or ‘InceptionTime’), or learning rates. Most important feature to look at are the two plots on the top which display the development of the accuracy on both the training set and the validation set. A good model should perform decently well on both sides.&lt;/p&gt;
&lt;p&gt;mcfly build-in visualization of the model performance. While in this example all models achieve good results on the training dataset, much fewer reach decent results on the validation dataset.&lt;/p&gt;
&lt;h3 id=&quot;overfitting&quot;&gt;Overfitting&lt;/h3&gt;
&lt;p&gt;Since the RacketSports dataset only consits of 150 training examples, you will frequently see that generated deep learning models will &lt;strong&gt;overfit&lt;/strong&gt; the data. Overfitting is one of the most common problems when working with deep learning. It essentially means that you optimize too much on the training data so that the performance on unseen data will suffer. A typical signature for this is that models will do well on the training data (high training accuracy), but will perform poorly on the validation data (low validation accuracy). A typical example is shown below with 8 models, most of which report high &lt;code&gt;train_accuracy&lt;/code&gt;but very low &lt;code&gt;val_accuracy&lt;/code&gt;values!&lt;/p&gt;
&lt;p&gt;Example results of 8 mcfly generated models trained on RacketSports dataset. Six perform well on the training data, but only 2 models also perform well on the validation data.If we now pick one of the better performing models (or iteratively generate and train more models), then we can get quite good results on the RacketSports dataset. Below you can see how we could inspect this by generating a confusion matrix. And here it indeed reveals that most of the times the picked &lt;strong&gt;model is correctly predicting the actual activity!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Generating a confusion matrix using the validation dataset.&lt;/p&gt;
&lt;h3 id=&quot;and-now-what-are-you-waiting-for&quot;&gt;And now… what are you waiting for?&lt;/h3&gt;
&lt;p&gt;Grab some interesting time series data and try out some deep learning!&lt;/p&gt;
&lt;h2 id=&quot;did-you-use-mcfly&quot;&gt;Did you use mcfly?&lt;/h2&gt;
&lt;p&gt;Awesome! We are always happy to hear from people who have made good use of &lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt;. Please get in touch if you have suggestions and ideas for future developments or fixes (e.g. via &lt;a href=&quot;https://github.com/NLeSC/mcfly&quot;&gt;GitHub&lt;/a&gt;, via&lt;a href=&quot;https://twitter.com/me_datapoint&quot;&gt; twitter&lt;/a&gt;, or as response to this post). Many thanks.&lt;/p&gt;
&lt;p&gt;**Reference:
**D. van Kuppevelt, C. Meijer, F. Huber, A. van der Ploeg, S. Georgievska, V.T. van Hees. &lt;em&gt;Mcfly: Automated deep learning on time series.&lt;/em&gt; SoftwareX, Volume 12, 2020. &lt;a href=&quot;https://doi.org/10.1016/j.softx.2020.100548&quot;&gt;doi: 10.1016/j.softx.2020.100548&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/mcfly-time-series-classification-made-easy-e47de8d29838&quot;&gt;Former blog post from 2017&lt;/a&gt; by [Dafne van Kuppevelt]&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; on pypi: &lt;a href=&quot;https://pypi.org/project/mcfly/&quot;&gt;https://pypi.org/project/mcfly/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; on GitHub: &lt;a href=&quot;https://github.com/NLeSC/mcfly&quot;&gt;https://github.com/NLeSC/mcfly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ready-to-use RacketSports dataset on zenodo: &lt;a href=&quot;https://zenodo.org/record/3743603#.XpAypXKxUuU&quot;&gt;https://zenodo.org/record/3743603&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;mcfly&lt;/strong&gt;&lt;/em&gt; tutorial(s): &lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial&quot;&gt;https://github.com/NLeSC/mcfly-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tutorial notebook with all code mentioned in this blog post: **&lt;a href=&quot;https://github.com/NLeSC/mcfly-tutorial/blob/main/notebooks/tutorial/tutorial_quick.ipynb&quot;&gt;https://github.com/NLeSC/mcfly-tutorial/blob/main/notebooks/tutorial/tutorial_quick.ipynb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;mcfly&lt;/em&gt;*** *was developed at the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;&lt;strong&gt;Netherlands eScience Center&lt;/strong&gt;&lt;/a&gt; by [Dafne van Kuppevelt], Christiaan Meijer, [Sonja Georgievska], [Vincent van Hees], [Florian Huber], [Patrick Bos], [Jurriaan H. Spaaks], Mateusz Kuzak, [Johan Hidding], [Atze van der Ploeg].&lt;/p&gt;
&lt;p&gt;Thanks to Johan Rheeder, [Sonja Georgievska], [Dafne van Kuppevelt], [Peter Kalverla,] [Patrick Bos], and [Tom Bakker] for helpful comments and edits.&lt;/p&gt;</content:encoded><author>Florian Huber</author></item><item><title>Reduce, reuse, recycle: save the planet one GitHub action at a time</title><link>https://blog.esciencecenter.nl/posts/2023-06-20---reduce-reuse-recycle-save-the-planet-one-github-action-at-a-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-06-20---reduce-reuse-recycle-save-the-planet-one-github-action-at-a-</guid><description>&lt;p&gt;**&lt;/p&gt;
&lt;h1 id=&quot;reduce-reuse-recycle-save-the-planet-one-github-action-at-a-time&quot;&gt;Reduce, reuse, recycle: save the planet one GitHub action at a time&lt;/h1&gt;
&lt;p&gt;53&lt;/p&gt;
&lt;p&gt;Written by &lt;a href=&quot;https://medium.com/@stefsmeets&quot;&gt;Stef Smeets&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@s.vanrijn&quot;&gt;Sander van Rijn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ralphkayden?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Ralph (Ravi) Kayden&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Ask any environmentalist what you can do to help combat climate change and protect the environment, and they will tell you to &lt;a href=&quot;https://en.wikipedia.org/wiki/Waste_hierarchy&quot;&gt;“Reduce, Reuse, Recycle.”&lt;/a&gt; These actions are focused on maximizing practical benefit while minimizing the cost to the environment through conservation of resources and preventing the emission of greenhouse gases.&lt;/p&gt;
&lt;p&gt;As software engineers, we are big fans of integration and continuous delivery (CI/CD) workflows as part of sustainable software development. GitHub actions is &lt;a href=&quot;https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#about-billing-for-github-actions&quot;&gt;completely free for public repositories&lt;/a&gt;, so why wouldn’t we? We use it for everything, from code analysis and linting, running tests and builds in isolated environments, generating documentation on &lt;a href=&quot;https://docs.readthedocs.io/en/stable/integrations.html&quot;&gt;readthedocs&lt;/a&gt;, and publishing packages on &lt;a href=&quot;https://github.com/marketplace/actions/pypi-publish&quot;&gt;PyPI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until all of our power comes from nuclear fusion, and data centers can be made of trees, running any code will have an environmental impact: CO2 and other emissions from the power used and the production of the computers it runs on. Not writing code won’t solve our problems either, so we need to find places in our workflow where we can reduce our impact.&lt;/p&gt;
&lt;p&gt;Many CI/CD systems are configured to run automatically, often out of sight, so their impact to the planet adds up quickly. We have been asking ourselves some questions, like what we can do to make our use of CI/CD more sustainable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do we need to build the documentation for every commit we make to the code?&lt;/li&gt;
&lt;li&gt;Do we need to test on every version of Python on all platforms to ensure code works?&lt;/li&gt;
&lt;li&gt;Do we need to run all our machine learning notebooks on every push?&lt;/li&gt;
&lt;li&gt;When we fix a typo in our documentation, do we need to run a complete suite of regression tests?&lt;/li&gt;
&lt;li&gt;When we fix a bug, can we get away just re-running the failed tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blogpost we share what we have learned and give some ideas about what you can do to reduce your impact using &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-bother&quot;&gt;Why bother?&lt;/h2&gt;
&lt;p&gt;Data centers need large amounts of energy, from running servers, computing hardware, and refrigerating equipment. And, let’s not forget that the production of servers, cables and supporting equipment, and mining of the required raw materials also contribute.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://www.iea.org/reports/data-centres-and-data-transmission-networks&quot;&gt;IEA&lt;/a&gt;, all data centers and data transmission networks account for 2–3% of global electricity use. This corresponds to 300 Mt &lt;a href=&quot;https://en.wikipedia.org/wiki/Global_warming_potential#Carbon_dioxide_equivalent&quot;&gt;CO2-eq&lt;/a&gt; in 2020 (0.9% energy related greenhouse gas emissions). The costs for the environment are enormous. Although improvements in efficiency and hyperscale data centers help limit the growth in energy demands somewhat, the demand for data workloads and internet traffic still grows every year.&lt;/p&gt;
&lt;p&gt;GitHub (this blog is about GitHub Actions after all!) claims to be &lt;a href=&quot;https://github.blog/2021-04-22-environmental-sustainability-github/&quot;&gt;committed to environmental sustainability&lt;/a&gt;. A noble effort, but its parent company Microsoft increased its CO2 emissions by &lt;a href=&quot;https://aka.ms/SustainabilityReport2022&quot;&gt;nearly 15% from 2020 to 2022&lt;/a&gt;. Most companies who claim to achieve ‘net zero’ do so not by reducing their emissions, but by compensating elsewhere. Microsoft compensated only about 10% of their emissions in 2022. This is typically done through &lt;a href=&quot;https://en.wikipedia.org/wiki/Guarantee_of_origin&quot;&gt;buying certified green energy&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Carbon_offsets_and_credits&quot;&gt;CO2 compensation&lt;/a&gt;, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Emissions_trading&quot;&gt;emission trading&lt;/a&gt;. This allows companies to be green on paper by trading certificates, with little direct effect on their business operations. Such climate certificates are often sold on a promise, like planting trees or saving a forest from clearing. Better than nothing, but it’s even better to not have those emissions in the first place.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@etiennegirardet?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Etienne Girardet&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reduce&quot;&gt;Reduce&lt;/h2&gt;
&lt;p&gt;So, what can we do?&lt;/p&gt;
&lt;p&gt;The best thing we can do is prevent resource usage by reducing the number of times we trigger the CI/CD workflows.&lt;/p&gt;
&lt;h3 id=&quot;restrict-branch-and-event-type&quot;&gt;Restrict branch and event type&lt;/h3&gt;
&lt;p&gt;Many of us have configured our CI to run whenever a commit is pushed to a pull request (PR). While this gives great peace of mind to see that our tests pass, we can’t help but wonder if this is really necessary.&lt;/p&gt;
&lt;p&gt;One pattern we like to use when we are still working on a PR is to keep it in &lt;a href=&quot;https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request&quot;&gt;Draft mode*&lt;/a&gt;. Once we are happy with our code and want some feedback, we mark the PR as as &lt;em&gt;Ready for review&lt;/em&gt;. We can configure the CI to only run once a PR is &lt;em&gt;Ready for review&lt;/em&gt;. This gives the reviewer peace of mind that the PR is bug free and is safe to be merged.&lt;/p&gt;
&lt;p&gt;This also saves a whole bunch of unnecessary CI runs, and gives you more control when actually running the CI.&lt;/p&gt;
&lt;p&gt;To set this up, add this to your github action:&lt;/p&gt;
&lt;h1 id=&quot;testsyml&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;name: Tests&lt;/p&gt;
&lt;p&gt;on:
pull_request:
branches:
- main
types:
- opened
- reopened
- synchronize
- ready_for_review
push:
branches:
- main&lt;/p&gt;
&lt;p&gt;jobs:
test:
if: github.event.pull_request.draft == false
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;steps:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...See an example of how we have implemented this for one of our projects [here](https://github.com/duqtools/duqtools/blob/main/.github/workflows/test.yaml).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;filter-by-changed-files&quot;&gt;Filter by changed files&lt;/h3&gt;
&lt;p&gt;Another common pattern we use is to only run a job when the relevant files have changed. Let’s say we have a simple project with the following folder structure:&lt;/p&gt;
&lt;p&gt;project-to-save-the-planet/
├── docs/
│   └── the_plan.md
│   └── …
├── src/
│   ├── save_the_planet.py
│   ├── supporting_documentation.md
│   └── …
├── tests/
│   └── …
├── …
└── README.mdWe don’t have to re-run all tests if something only changed in the documentation, nor do we have to rebuild the documentation if we only make changes to some tests. And if we only fix a typo in &lt;code&gt;README.md&lt;/code&gt; neither will be necessary. These restrictions can be enabled by adding filters in the &lt;code&gt;[paths](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore)&lt;/code&gt; section of the workflow triggers. These &lt;code&gt;paths&lt;/code&gt; specifications can also be combined with the other filters such as branches shown earlier, to trigger only if it matches the paths and **branch. **
Here’s an example configuration that triggers only on changes in the &lt;code&gt;docs&lt;/code&gt; folders:&lt;/p&gt;
&lt;h1 id=&quot;docsyml&quot;&gt;docs.yml&lt;/h1&gt;
&lt;p&gt;on:
push:
…
paths:
- ‘docs/**’&lt;/p&gt;
&lt;p&gt;jobs:
…Certain paths or types of files can also be excluded using an exclamation mark (&lt;code&gt;!&lt;/code&gt;). This can be useful if we want to trigger the tests to run on changes in &lt;code&gt;src/&lt;/code&gt; or &lt;code&gt;tests/&lt;/code&gt;, except when we make changes to some supporting documentation or other data that does not affect the outcome of the tests. Here’s an example of such a workflow:&lt;/p&gt;
&lt;h1 id=&quot;testsyml-1&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;on:
push:
…
paths:
- ‘src/&lt;strong&gt;’
- ‘!src/supporting_documentation.md’
- ‘tests/&lt;/strong&gt;’&lt;/p&gt;
&lt;p&gt;jobs:
…&lt;/p&gt;
&lt;h3 id=&quot;use-cpu-versions-of-tensorflow-and-pytorch&quot;&gt;Use CPU versions of tensorflow and pytorch&lt;/h3&gt;
&lt;p&gt;If you are working in machine learning, you will know that tensorflow and pytorch are enormous libraries. Together with their dependencies, they can be several gigabytes in size. On a CI, downloading these packages can already take up to a minute.&lt;/p&gt;
&lt;p&gt;But, did you know that most of this space is taken up by GPU support? Try using &lt;code&gt;[tensorflow-cpu](https://pypi.org/project/tensorflow-cpu/)&lt;/code&gt;or &lt;code&gt;[pytorch-cpu](https://pytorch.org/get-started/locally/)&lt;/code&gt; instead of full-fat libraries. From our experience, this reduces the install size of our Python environments by approximately 1.5 GB on linux systems (this has no effect on Windows and Mac runners). The trick here is to install these prior to installing your package via &lt;code&gt;pip&lt;/code&gt;. These will then be skipped by &lt;code&gt;pip&lt;/code&gt; if these packages are also defined in your &lt;code&gt;pyproject.toml&lt;/code&gt; or &lt;code&gt;requirements.txt&lt;/code&gt;. Considering that all the common CI systems typically do not have GPUs in them, this makes the installs significantly lighter and therefore faster to run too!&lt;/p&gt;
&lt;p&gt;To do so, add this step to your GitHub action prior to installing your package:&lt;/p&gt;
&lt;h1 id=&quot;testsyml-2&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install tensorflow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if: runner.os == &apos;Linux&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    python3 -m pip install tensorflow-cpu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install pytorch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if: runner.os == &apos;Linux&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    python3 -m pip install torch --index-url https://download.pytorch.org/whl/cpu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      pip install .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Why throw away when you can reuse?&lt;/em&gt; Photo by &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Upcycled_Roses.jpg&quot;&gt;JulieN2212 via Wikimedia Commons&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reuse&quot;&gt;Reuse&lt;/h2&gt;
&lt;p&gt;If you must run the CI, the best way to reduce its impact is limit the actual work that needs to be done.&lt;/p&gt;
&lt;p&gt;With the &lt;a href=&quot;https://github.com/actions/cache&quot;&gt;cache action&lt;/a&gt;, you can cache dependencies and build outputs to make your workflows faster and thus more efficient. Maybe you need to compile some dependency, download and pre-compute some data, or set up your python environment via &lt;code&gt;pip&lt;/code&gt;. These typically do not change much from run to run, so try to cache these where possible.&lt;/p&gt;
&lt;h3 id=&quot;caching-your-python-environment&quot;&gt;Caching your Python environment&lt;/h3&gt;
&lt;p&gt;Just the installation of the dependencies of some Python code via pip can be quite significant. Some libraries just seem to pull in an endless stream of dependencies. So, why don’t we cache our entire Python environment?&lt;/p&gt;
&lt;p&gt;Below is a snippet that we find effective in our workflows for Python code.&lt;/p&gt;
&lt;p&gt;As the cache key, we use a combination of the Python directory name (this includes the version) in combination with the hash of the &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;setup.cfg&lt;/code&gt;, or &lt;code&gt;requirements.txt&lt;/code&gt; file. Whenever these get updated, the cache gets invalidated and regenerated.&lt;/p&gt;
&lt;p&gt;This means we can also safely skip the &lt;code&gt;pip install&lt;/code&gt; step if we hit the cache. Depending on the number of dependencies, this virtually eliminates the setup time of your workflow.&lt;/p&gt;
&lt;h1 id=&quot;testsyaml&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - uses: actions/cache@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id: cache-python-env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      path: ${{ env.pythonLocation }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      key: ${{ env.pythonLocation }}-${{ hashFiles(&apos;pyproject.toml&apos;) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - name: Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if: steps.cache-python-env.outputs.cache-hit != &apos;true&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      python -m pip install -e .[develop]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;caching-any-directory&quot;&gt;Caching any directory&lt;/h3&gt;
&lt;p&gt;To generalize the action below, the example below shows how any directory can be cached. We have used this to cache dependencies that need to be compiled. This can save minutes if not more from your workflow every single time it gets triggered.&lt;/p&gt;
&lt;p&gt;We recommend adding a version to the cache key, so that you can easily invalidate the cache and force a re-trigger through the action itself.&lt;/p&gt;
&lt;p&gt;Any subsequent workflows, will restore the directory from GitHub’s cache.&lt;/p&gt;
&lt;h1 id=&quot;testsyaml-1&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - uses: actions/cache@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id: cache-important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      path: important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      key: cache-key-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - name: Compile dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if: steps.cache-important-dependency.outputs.cache-hit != &apos;true&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      mkdir important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cd important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      echo &quot;All I want is world peace... Or a piece of the world.&quot; &amp;#x26;gt; t.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Failing code into the red bin, please. Photo by &lt;a href=&quot;https://unsplash.com/@pawel_czerwinski?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Pawel Czerwinski&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;recycle&quot;&gt;Recycle&lt;/h2&gt;
&lt;p&gt;Finally, can we recycle **anything that is left when our CI run is done? Although not exactly trash, what’s typically leftover is the test results: which tests passed and failed. If any tests failed, those definitely have to pass before we want to continue. It makes sense then to re-run those tests first, and we can stop if any of those fail again.&lt;/p&gt;
&lt;h3 id=&quot;pytest-last-failed&quot;&gt;Pytest last failed&lt;/h3&gt;
&lt;p&gt;Pytest has a very handy &lt;code&gt;[--last-failed](https://docs.pytest.org/en/stable/how-to/cache.html)&lt;/code&gt; flag for exactly this purpose, but that obviously depends on a local cache to remember the outcome of the previous run. Luckily for you, &lt;a href=&quot;https://github.com/sjvrijn/pytest-last-failed&quot;&gt;we’ve already made a GitHub action&lt;/a&gt; that takes care of setting this up for you! Simply use this action instead of your &lt;code&gt;*run: pytest --my --pytest --args*&lt;/code&gt; step:&lt;/p&gt;
&lt;h1 id=&quot;testsyaml-2&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
# create python environment and install pytest&lt;br&gt;
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Run pytest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uses: sjvrijn/pytest-last-failed@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    pytest-args: &apos;--my --pytest --args&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we introduced some options to make your sustainable software development more sustainable to the planet as well, whether by preventing double work or avoiding unnecessary CI runs in the first place. All it takes is a few extra lines in your workflows to help save the planet and save yourself some time in the process.&lt;/p&gt;
&lt;p&gt;Of course, there are many other strategies to reduce your impact, such as using pre-built dependencies, more efficient libraries, or preparing a docker container for complex test environments.&lt;/p&gt;
&lt;p&gt;It turns out that once you start looking, there are many technical options to reduce your impact. The more difficult challenge may be a social one, to convince your peers that change is necessary. In the end, we hope that this blog post inspired you, and that you will consider the environmental impact of your work.&lt;/p&gt;</description><pubDate>Tue, 20 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;**&lt;/p&gt;
&lt;h1 id=&quot;reduce-reuse-recycle-save-the-planet-one-github-action-at-a-time&quot;&gt;Reduce, reuse, recycle: save the planet one GitHub action at a time&lt;/h1&gt;
&lt;p&gt;53&lt;/p&gt;
&lt;p&gt;Written by &lt;a href=&quot;https://medium.com/@stefsmeets&quot;&gt;Stef Smeets&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@s.vanrijn&quot;&gt;Sander van Rijn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ralphkayden?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Ralph (Ravi) Kayden&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;Ask any environmentalist what you can do to help combat climate change and protect the environment, and they will tell you to &lt;a href=&quot;https://en.wikipedia.org/wiki/Waste_hierarchy&quot;&gt;“Reduce, Reuse, Recycle.”&lt;/a&gt; These actions are focused on maximizing practical benefit while minimizing the cost to the environment through conservation of resources and preventing the emission of greenhouse gases.&lt;/p&gt;
&lt;p&gt;As software engineers, we are big fans of integration and continuous delivery (CI/CD) workflows as part of sustainable software development. GitHub actions is &lt;a href=&quot;https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#about-billing-for-github-actions&quot;&gt;completely free for public repositories&lt;/a&gt;, so why wouldn’t we? We use it for everything, from code analysis and linting, running tests and builds in isolated environments, generating documentation on &lt;a href=&quot;https://docs.readthedocs.io/en/stable/integrations.html&quot;&gt;readthedocs&lt;/a&gt;, and publishing packages on &lt;a href=&quot;https://github.com/marketplace/actions/pypi-publish&quot;&gt;PyPI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until all of our power comes from nuclear fusion, and data centers can be made of trees, running any code will have an environmental impact: CO2 and other emissions from the power used and the production of the computers it runs on. Not writing code won’t solve our problems either, so we need to find places in our workflow where we can reduce our impact.&lt;/p&gt;
&lt;p&gt;Many CI/CD systems are configured to run automatically, often out of sight, so their impact to the planet adds up quickly. We have been asking ourselves some questions, like what we can do to make our use of CI/CD more sustainable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do we need to build the documentation for every commit we make to the code?&lt;/li&gt;
&lt;li&gt;Do we need to test on every version of Python on all platforms to ensure code works?&lt;/li&gt;
&lt;li&gt;Do we need to run all our machine learning notebooks on every push?&lt;/li&gt;
&lt;li&gt;When we fix a typo in our documentation, do we need to run a complete suite of regression tests?&lt;/li&gt;
&lt;li&gt;When we fix a bug, can we get away just re-running the failed tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blogpost we share what we have learned and give some ideas about what you can do to reduce your impact using &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-bother&quot;&gt;Why bother?&lt;/h2&gt;
&lt;p&gt;Data centers need large amounts of energy, from running servers, computing hardware, and refrigerating equipment. And, let’s not forget that the production of servers, cables and supporting equipment, and mining of the required raw materials also contribute.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://www.iea.org/reports/data-centres-and-data-transmission-networks&quot;&gt;IEA&lt;/a&gt;, all data centers and data transmission networks account for 2–3% of global electricity use. This corresponds to 300 Mt &lt;a href=&quot;https://en.wikipedia.org/wiki/Global_warming_potential#Carbon_dioxide_equivalent&quot;&gt;CO2-eq&lt;/a&gt; in 2020 (0.9% energy related greenhouse gas emissions). The costs for the environment are enormous. Although improvements in efficiency and hyperscale data centers help limit the growth in energy demands somewhat, the demand for data workloads and internet traffic still grows every year.&lt;/p&gt;
&lt;p&gt;GitHub (this blog is about GitHub Actions after all!) claims to be &lt;a href=&quot;https://github.blog/2021-04-22-environmental-sustainability-github/&quot;&gt;committed to environmental sustainability&lt;/a&gt;. A noble effort, but its parent company Microsoft increased its CO2 emissions by &lt;a href=&quot;https://aka.ms/SustainabilityReport2022&quot;&gt;nearly 15% from 2020 to 2022&lt;/a&gt;. Most companies who claim to achieve ‘net zero’ do so not by reducing their emissions, but by compensating elsewhere. Microsoft compensated only about 10% of their emissions in 2022. This is typically done through &lt;a href=&quot;https://en.wikipedia.org/wiki/Guarantee_of_origin&quot;&gt;buying certified green energy&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Carbon_offsets_and_credits&quot;&gt;CO2 compensation&lt;/a&gt;, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Emissions_trading&quot;&gt;emission trading&lt;/a&gt;. This allows companies to be green on paper by trading certificates, with little direct effect on their business operations. Such climate certificates are often sold on a promise, like planting trees or saving a forest from clearing. Better than nothing, but it’s even better to not have those emissions in the first place.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@etiennegirardet?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Etienne Girardet&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reduce&quot;&gt;Reduce&lt;/h2&gt;
&lt;p&gt;So, what can we do?&lt;/p&gt;
&lt;p&gt;The best thing we can do is prevent resource usage by reducing the number of times we trigger the CI/CD workflows.&lt;/p&gt;
&lt;h3 id=&quot;restrict-branch-and-event-type&quot;&gt;Restrict branch and event type&lt;/h3&gt;
&lt;p&gt;Many of us have configured our CI to run whenever a commit is pushed to a pull request (PR). While this gives great peace of mind to see that our tests pass, we can’t help but wonder if this is really necessary.&lt;/p&gt;
&lt;p&gt;One pattern we like to use when we are still working on a PR is to keep it in &lt;a href=&quot;https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request&quot;&gt;Draft mode*&lt;/a&gt;. Once we are happy with our code and want some feedback, we mark the PR as as &lt;em&gt;Ready for review&lt;/em&gt;. We can configure the CI to only run once a PR is &lt;em&gt;Ready for review&lt;/em&gt;. This gives the reviewer peace of mind that the PR is bug free and is safe to be merged.&lt;/p&gt;
&lt;p&gt;This also saves a whole bunch of unnecessary CI runs, and gives you more control when actually running the CI.&lt;/p&gt;
&lt;p&gt;To set this up, add this to your github action:&lt;/p&gt;
&lt;h1 id=&quot;testsyml&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;name: Tests&lt;/p&gt;
&lt;p&gt;on:
pull_request:
branches:
- main
types:
- opened
- reopened
- synchronize
- ready_for_review
push:
branches:
- main&lt;/p&gt;
&lt;p&gt;jobs:
test:
if: github.event.pull_request.draft == false
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;steps:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...See an example of how we have implemented this for one of our projects [here](https://github.com/duqtools/duqtools/blob/main/.github/workflows/test.yaml).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;filter-by-changed-files&quot;&gt;Filter by changed files&lt;/h3&gt;
&lt;p&gt;Another common pattern we use is to only run a job when the relevant files have changed. Let’s say we have a simple project with the following folder structure:&lt;/p&gt;
&lt;p&gt;project-to-save-the-planet/
├── docs/
│   └── the_plan.md
│   └── …
├── src/
│   ├── save_the_planet.py
│   ├── supporting_documentation.md
│   └── …
├── tests/
│   └── …
├── …
└── README.mdWe don’t have to re-run all tests if something only changed in the documentation, nor do we have to rebuild the documentation if we only make changes to some tests. And if we only fix a typo in &lt;code&gt;README.md&lt;/code&gt; neither will be necessary. These restrictions can be enabled by adding filters in the &lt;code&gt;[paths](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore)&lt;/code&gt; section of the workflow triggers. These &lt;code&gt;paths&lt;/code&gt; specifications can also be combined with the other filters such as branches shown earlier, to trigger only if it matches the paths and **branch. **
Here’s an example configuration that triggers only on changes in the &lt;code&gt;docs&lt;/code&gt; folders:&lt;/p&gt;
&lt;h1 id=&quot;docsyml&quot;&gt;docs.yml&lt;/h1&gt;
&lt;p&gt;on:
push:
…
paths:
- ‘docs/**’&lt;/p&gt;
&lt;p&gt;jobs:
…Certain paths or types of files can also be excluded using an exclamation mark (&lt;code&gt;!&lt;/code&gt;). This can be useful if we want to trigger the tests to run on changes in &lt;code&gt;src/&lt;/code&gt; or &lt;code&gt;tests/&lt;/code&gt;, except when we make changes to some supporting documentation or other data that does not affect the outcome of the tests. Here’s an example of such a workflow:&lt;/p&gt;
&lt;h1 id=&quot;testsyml-1&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;on:
push:
…
paths:
- ‘src/&lt;strong&gt;’
- ‘!src/supporting_documentation.md’
- ‘tests/&lt;/strong&gt;’&lt;/p&gt;
&lt;p&gt;jobs:
…&lt;/p&gt;
&lt;h3 id=&quot;use-cpu-versions-of-tensorflow-and-pytorch&quot;&gt;Use CPU versions of tensorflow and pytorch&lt;/h3&gt;
&lt;p&gt;If you are working in machine learning, you will know that tensorflow and pytorch are enormous libraries. Together with their dependencies, they can be several gigabytes in size. On a CI, downloading these packages can already take up to a minute.&lt;/p&gt;
&lt;p&gt;But, did you know that most of this space is taken up by GPU support? Try using &lt;code&gt;[tensorflow-cpu](https://pypi.org/project/tensorflow-cpu/)&lt;/code&gt;or &lt;code&gt;[pytorch-cpu](https://pytorch.org/get-started/locally/)&lt;/code&gt; instead of full-fat libraries. From our experience, this reduces the install size of our Python environments by approximately 1.5 GB on linux systems (this has no effect on Windows and Mac runners). The trick here is to install these prior to installing your package via &lt;code&gt;pip&lt;/code&gt;. These will then be skipped by &lt;code&gt;pip&lt;/code&gt; if these packages are also defined in your &lt;code&gt;pyproject.toml&lt;/code&gt; or &lt;code&gt;requirements.txt&lt;/code&gt;. Considering that all the common CI systems typically do not have GPUs in them, this makes the installs significantly lighter and therefore faster to run too!&lt;/p&gt;
&lt;p&gt;To do so, add this step to your GitHub action prior to installing your package:&lt;/p&gt;
&lt;h1 id=&quot;testsyml-2&quot;&gt;tests.yml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install tensorflow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if: runner.os == &apos;Linux&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    python3 -m pip install tensorflow-cpu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install pytorch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if: runner.os == &apos;Linux&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    python3 -m pip install torch --index-url https://download.pytorch.org/whl/cpu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      pip install .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Why throw away when you can reuse?&lt;/em&gt; Photo by &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Upcycled_Roses.jpg&quot;&gt;JulieN2212 via Wikimedia Commons&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reuse&quot;&gt;Reuse&lt;/h2&gt;
&lt;p&gt;If you must run the CI, the best way to reduce its impact is limit the actual work that needs to be done.&lt;/p&gt;
&lt;p&gt;With the &lt;a href=&quot;https://github.com/actions/cache&quot;&gt;cache action&lt;/a&gt;, you can cache dependencies and build outputs to make your workflows faster and thus more efficient. Maybe you need to compile some dependency, download and pre-compute some data, or set up your python environment via &lt;code&gt;pip&lt;/code&gt;. These typically do not change much from run to run, so try to cache these where possible.&lt;/p&gt;
&lt;h3 id=&quot;caching-your-python-environment&quot;&gt;Caching your Python environment&lt;/h3&gt;
&lt;p&gt;Just the installation of the dependencies of some Python code via pip can be quite significant. Some libraries just seem to pull in an endless stream of dependencies. So, why don’t we cache our entire Python environment?&lt;/p&gt;
&lt;p&gt;Below is a snippet that we find effective in our workflows for Python code.&lt;/p&gt;
&lt;p&gt;As the cache key, we use a combination of the Python directory name (this includes the version) in combination with the hash of the &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;setup.cfg&lt;/code&gt;, or &lt;code&gt;requirements.txt&lt;/code&gt; file. Whenever these get updated, the cache gets invalidated and regenerated.&lt;/p&gt;
&lt;p&gt;This means we can also safely skip the &lt;code&gt;pip install&lt;/code&gt; step if we hit the cache. Depending on the number of dependencies, this virtually eliminates the setup time of your workflow.&lt;/p&gt;
&lt;h1 id=&quot;testsyaml&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - uses: actions/cache@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id: cache-python-env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      path: ${{ env.pythonLocation }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      key: ${{ env.pythonLocation }}-${{ hashFiles(&apos;pyproject.toml&apos;) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - name: Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if: steps.cache-python-env.outputs.cache-hit != &apos;true&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      python -m pip install -e .[develop]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;caching-any-directory&quot;&gt;Caching any directory&lt;/h3&gt;
&lt;p&gt;To generalize the action below, the example below shows how any directory can be cached. We have used this to cache dependencies that need to be compiled. This can save minutes if not more from your workflow every single time it gets triggered.&lt;/p&gt;
&lt;p&gt;We recommend adding a version to the cache key, so that you can easily invalidate the cache and force a re-trigger through the action itself.&lt;/p&gt;
&lt;p&gt;Any subsequent workflows, will restore the directory from GitHub’s cache.&lt;/p&gt;
&lt;h1 id=&quot;testsyaml-1&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - uses: actions/cache@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id: cache-important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      path: important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      key: cache-key-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - name: Compile dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if: steps.cache-important-dependency.outputs.cache-hit != &apos;true&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    run: |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      mkdir important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cd important-dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      echo &quot;All I want is world peace... Or a piece of the world.&quot; &amp;#x26;gt; t.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Failing code into the red bin, please. Photo by &lt;a href=&quot;https://unsplash.com/@pawel_czerwinski?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Pawel Czerwinski&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;recycle&quot;&gt;Recycle&lt;/h2&gt;
&lt;p&gt;Finally, can we recycle **anything that is left when our CI run is done? Although not exactly trash, what’s typically leftover is the test results: which tests passed and failed. If any tests failed, those definitely have to pass before we want to continue. It makes sense then to re-run those tests first, and we can stop if any of those fail again.&lt;/p&gt;
&lt;h3 id=&quot;pytest-last-failed&quot;&gt;Pytest last failed&lt;/h3&gt;
&lt;p&gt;Pytest has a very handy &lt;code&gt;[--last-failed](https://docs.pytest.org/en/stable/how-to/cache.html)&lt;/code&gt; flag for exactly this purpose, but that obviously depends on a local cache to remember the outcome of the previous run. Luckily for you, &lt;a href=&quot;https://github.com/sjvrijn/pytest-last-failed&quot;&gt;we’ve already made a GitHub action&lt;/a&gt; that takes care of setting this up for you! Simply use this action instead of your &lt;code&gt;*run: pytest --my --pytest --args*&lt;/code&gt; step:&lt;/p&gt;
&lt;h1 id=&quot;testsyaml-2&quot;&gt;tests.yaml&lt;/h1&gt;
&lt;p&gt;jobs:
test:
steps:
# create python environment and install pytest&lt;br&gt;
…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- name: Run pytest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uses: sjvrijn/pytest-last-failed@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    pytest-args: &apos;--my --pytest --args&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we introduced some options to make your sustainable software development more sustainable to the planet as well, whether by preventing double work or avoiding unnecessary CI runs in the first place. All it takes is a few extra lines in your workflows to help save the planet and save yourself some time in the process.&lt;/p&gt;
&lt;p&gt;Of course, there are many other strategies to reduce your impact, such as using pre-built dependencies, more efficient libraries, or preparing a docker container for complex test environments.&lt;/p&gt;
&lt;p&gt;It turns out that once you start looking, there are many technical options to reduce your impact. The more difficult challenge may be a social one, to convince your peers that change is necessary. In the end, we hope that this blog post inspired you, and that you will consider the environmental impact of your work.&lt;/p&gt;</content:encoded><author>Stef Smeets</author></item><item><title>NL-RSE: What Open Science can learn from Open Source</title><link>https://blog.esciencecenter.nl/posts/2023-06-08---nl-rse-what-open-science-can-learn-from-open-source</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-06-08---nl-rse-what-open-science-can-learn-from-open-source</guid><description>&lt;p&gt;&lt;em&gt;NL-RSE meetups are bimonthly events where the &lt;em&gt;&lt;a href=&quot;https://nl-rse.org/&quot;&gt;&lt;em&gt;Dutch community for Research Software Engineers&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; comes together to learn new skills or hear inspiring talks by experts in the field of Open Science, Open Source, Research Software or Software Engineering. The &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.com/e/nl-rse-introduction-to-automated-software-testing-tickets-633227900697&quot;&gt;&lt;em&gt;next NL-RSE meetup&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; takes place on 15 June in Leiden and will be about automated testing. You can sign up for the meetup &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.com/e/nl-rse-introduction-to-automated-software-testing-tickets-633227900697&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and the mailing list &lt;em&gt;&lt;a href=&quot;https://nl-rse.org/pages/join&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Back in 2021, lawyer, philosopher, and Open Science advocate &lt;a href=&quot;https://twitter.com/jdelacueva&quot;&gt;Javier de la Cueva&lt;/a&gt; gave a talk at an NL-RSE meetup about what Open Science can learn from Open Source. This post is a report of that talk — originally first posted on the &lt;a href=&quot;https://nl-rse.org/posts/2021-07-07-jdlc-meetup-june&quot;&gt;NL-RSE blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;NL-RSE: What Open Science can learn from Open Source&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/nl-rse-what-open-science-can-learn-from--46f96ea7.B4loulY6_1PWI65.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@rocinante_11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mick Haupt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jdelacueva&quot;&gt;Javier de la Cueva&lt;/a&gt; does not like slideshows — “&lt;em&gt;it limits the ways we communicate, like squeezing thoughts into 140 characters&lt;/em&gt;”, but for the NL-RSE meetup, he made one anyway. De la Cueva is a lawyer, philosopher, and Open Science advocate, with expertise in free software and intellectual property. During the &lt;a href=&quot;https://nl-rse.org/events/2021-06-11-meetup&quot;&gt;meetup on Friday, 11 June 2021&lt;/a&gt;, he gave a passionate talk about what the Open Science movement can learn from the Free Software movement, blending the topics of software development and science in a way not unfamiliar to those identifying as RSEs.&lt;/p&gt;
&lt;p&gt;If anyone’s an expert on these topics, it’s De la Cueva. He switched from Windows to Linux in 2000, after receiving a Blue Screen of Death on his Windows machine — “&lt;em&gt;Why would you create a wall that doesn’t allow me to understand something I paid for?&lt;/em&gt;”. In 2002, when Wikipedia was planning to commercialize, De la Cueva and others &lt;a href=&quot;https://www.wired.co.uk/article/wikipedia-spanish-fork&quot;&gt;forked the Spanish version of the page onto a server in the University of Seville, Spain&lt;/a&gt;, proving to Wikipedia’s owners that the entire project could be run on non-profit servers — a move some consider responsible for keeping Wikipedia free of commercial ads and paywalls to this day. Later, in 2006, he was, in his own words, “&lt;em&gt;the first lawyer&lt;/em&gt; &lt;em&gt;to obtain a judicial ruling where the term &lt;em&gt;&lt;a href=&quot;https://copyleft.org/&quot;&gt;&lt;em&gt;copyleft&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; was included&lt;/em&gt;”. For the case in question, &lt;a href=&quot;https://edri.org/our-work/edrigramnumber4-9spaincc/&quot;&gt;Ladinamo&lt;/a&gt;, De la Cueva defended the owners of a bar who were sued for failing to pay the compulsory licensing fee for playing music in their establishment. He won the case by successfully arguing that the music’s Creative Commons licenses allowed for public performance, and that no additional fees had to be paid.&lt;/p&gt;
&lt;p&gt;In 2014, De la Cueva defended his philosophy thesis, &lt;a href=&quot;https://www.researchgate.net/publication/266487696_Pragmaticas_tecnologicas_ciudadanas_y_regeneracion_democratica&quot;&gt;Citizen Technological Pragmatics and Democratic Regeneration&lt;/a&gt; (abstract in English, thesis in Spanish). The work discusses how open access, open science, open data, and open government affect public knowledge and democracy. The thesis reflects Javier’s varied interests, providing insights from the fields of law, technology, political philosophy, and philosophy of language. Today, De la Cueva works as a lawyer and professor at IE University in Madrid. Along with his university teaching activities, De la Cueva is actively involved in science dissemination, “because a functioning democracy needs its citizens to be informed about scientific development*”. Science, he says, should not be about &lt;em&gt;who&lt;/em&gt; does it, but about &lt;em&gt;what&lt;/em&gt; scientists are doing. A common sensical enough statement, but one that may sound like an unrealistic utopia to anyone who has ever worked in academia.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;NL-RSE: What Open Science can learn from Open Source&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/nl-rse-what-open-science-can-learn-from--e598c5b9.fh3CfeSY_Z2mRXuJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@umby?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Umberto&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;American sociologist of science [Robert K. Merton](&lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_K._Merton#&quot;&gt;https://en.wikipedia.org/wiki/Robert_K._Merton#&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sociology_of_science_and_CUDOS) recognized this tension: he observed that the social system of science works both in agreement with, but also often in contradiction to, its own ideal. Merton expressed the ideal of science in four concrete moral principles, referred to as CUDOS** : Science must be &lt;strong&gt;C&lt;/strong&gt;ommunist (in the sense of communal), meaning that all scientists have common ownership of scientific goods, giving up intellectual property of their work in exchange for recognition. It should be &lt;strong&gt;U&lt;/strong&gt;niversal, or independent of the socio-political status and personal attributes of its participants. Scientific institutions should also be &lt;strong&gt;D&lt;/strong&gt;isinterested, meaning personal gain of individuals within them is inferior to the greater goal of the scientific enterprise. Lastly, science must have &lt;strong&gt;O&lt;/strong&gt;rganised &lt;strong&gt;S&lt;/strong&gt;cepticism.&lt;/p&gt;
&lt;p&gt;For science to be in line with CUDOS, we have to rethink the relationship between scientists and their work. Because every scientific institution inevitably brings their own view of the world to the way they collect, analyse, and publish their data, open access to scientific publications only is not enough. After all, after data is collected, it is translated and analysed (often with the use of in-house developed software), written up into results, preprints and research papers, which can obscure the bias inherent in every step of the way leading up to that publication. Ideally, science openly shares every output that it creates, including data, publications, education, software and other tools. These outputs should be reused to two ends: First, to reproduce existing findings, De la Cueva argues — “&lt;em&gt;there is too much emphasis on novelty in science&lt;/em&gt;”. Second, to combine all levels of existing scientific outputs into new structures, which De la Cueva considers crucial for innovation.&lt;/p&gt;
&lt;p&gt;Open Science can look at the Free Software movement for an example on how to openly share its output. Free Software developers recognise the importance of their software’s reusability, which means they understand the importance of licensing and diversity of licenses. Scientists, on the other hand, do not hold the power to put a license on their scientific output. De la Cueva argues that this should change. Science could, for example, take inspiration from the Internet Engineering Task Force (IETF), which manages standards for the Internet. Any contributor permits the IETF to distribute their contributions freely, and in turn can use any of the other standards, which have been licensed in the same way. This results in an open Internet that is freely accessible to all. If we want CUDOS for science, the same mechanism could be applied to scientific outputs, where scientists permit their contributions to be distributed freely, and in turn are able to freely use others’ contributions.&lt;/p&gt;
&lt;p&gt;De la Cueva points at two signs that science is moving in the right direction. First, the existence of preprint servers. Second, the &lt;a href=&quot;https://www.aje.com/arc/open-access-changing-landscape/&quot;&gt;rise in peer-reviewed open access journals&lt;/a&gt;. And arguably, the increasingly common practice of publicly sharing research software, and adherence to FAIR data principles, can be counted as positive signs too. But there’s still work to be done: “&lt;em&gt;We still pay 9500 euros to obtain open access in&lt;/em&gt; Nature. &lt;em&gt;And the default for publications is still&lt;/em&gt; All rights reserved. &lt;em&gt;This has to end.&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;Thanks to Lourens Veen and Pablo Rodríguez-Sánchez for helpful comments and additions.&lt;/p&gt;</description><pubDate>Thu, 08 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;NL-RSE meetups are bimonthly events where the &lt;em&gt;&lt;a href=&quot;https://nl-rse.org/&quot;&gt;&lt;em&gt;Dutch community for Research Software Engineers&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; comes together to learn new skills or hear inspiring talks by experts in the field of Open Science, Open Source, Research Software or Software Engineering. The &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.com/e/nl-rse-introduction-to-automated-software-testing-tickets-633227900697&quot;&gt;&lt;em&gt;next NL-RSE meetup&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; takes place on 15 June in Leiden and will be about automated testing. You can sign up for the meetup &lt;em&gt;&lt;a href=&quot;https://www.eventbrite.com/e/nl-rse-introduction-to-automated-software-testing-tickets-633227900697&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, and the mailing list &lt;em&gt;&lt;a href=&quot;https://nl-rse.org/pages/join&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Back in 2021, lawyer, philosopher, and Open Science advocate &lt;a href=&quot;https://twitter.com/jdelacueva&quot;&gt;Javier de la Cueva&lt;/a&gt; gave a talk at an NL-RSE meetup about what Open Science can learn from Open Source. This post is a report of that talk — originally first posted on the &lt;a href=&quot;https://nl-rse.org/posts/2021-07-07-jdlc-meetup-june&quot;&gt;NL-RSE blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;NL-RSE: What Open Science can learn from Open Source&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/nl-rse-what-open-science-can-learn-from--46f96ea7.B4loulY6_1PWI65.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@rocinante_11?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Mick Haupt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jdelacueva&quot;&gt;Javier de la Cueva&lt;/a&gt; does not like slideshows — “&lt;em&gt;it limits the ways we communicate, like squeezing thoughts into 140 characters&lt;/em&gt;”, but for the NL-RSE meetup, he made one anyway. De la Cueva is a lawyer, philosopher, and Open Science advocate, with expertise in free software and intellectual property. During the &lt;a href=&quot;https://nl-rse.org/events/2021-06-11-meetup&quot;&gt;meetup on Friday, 11 June 2021&lt;/a&gt;, he gave a passionate talk about what the Open Science movement can learn from the Free Software movement, blending the topics of software development and science in a way not unfamiliar to those identifying as RSEs.&lt;/p&gt;
&lt;p&gt;If anyone’s an expert on these topics, it’s De la Cueva. He switched from Windows to Linux in 2000, after receiving a Blue Screen of Death on his Windows machine — “&lt;em&gt;Why would you create a wall that doesn’t allow me to understand something I paid for?&lt;/em&gt;”. In 2002, when Wikipedia was planning to commercialize, De la Cueva and others &lt;a href=&quot;https://www.wired.co.uk/article/wikipedia-spanish-fork&quot;&gt;forked the Spanish version of the page onto a server in the University of Seville, Spain&lt;/a&gt;, proving to Wikipedia’s owners that the entire project could be run on non-profit servers — a move some consider responsible for keeping Wikipedia free of commercial ads and paywalls to this day. Later, in 2006, he was, in his own words, “&lt;em&gt;the first lawyer&lt;/em&gt; &lt;em&gt;to obtain a judicial ruling where the term &lt;em&gt;&lt;a href=&quot;https://copyleft.org/&quot;&gt;&lt;em&gt;copyleft&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; was included&lt;/em&gt;”. For the case in question, &lt;a href=&quot;https://edri.org/our-work/edrigramnumber4-9spaincc/&quot;&gt;Ladinamo&lt;/a&gt;, De la Cueva defended the owners of a bar who were sued for failing to pay the compulsory licensing fee for playing music in their establishment. He won the case by successfully arguing that the music’s Creative Commons licenses allowed for public performance, and that no additional fees had to be paid.&lt;/p&gt;
&lt;p&gt;In 2014, De la Cueva defended his philosophy thesis, &lt;a href=&quot;https://www.researchgate.net/publication/266487696_Pragmaticas_tecnologicas_ciudadanas_y_regeneracion_democratica&quot;&gt;Citizen Technological Pragmatics and Democratic Regeneration&lt;/a&gt; (abstract in English, thesis in Spanish). The work discusses how open access, open science, open data, and open government affect public knowledge and democracy. The thesis reflects Javier’s varied interests, providing insights from the fields of law, technology, political philosophy, and philosophy of language. Today, De la Cueva works as a lawyer and professor at IE University in Madrid. Along with his university teaching activities, De la Cueva is actively involved in science dissemination, “because a functioning democracy needs its citizens to be informed about scientific development*”. Science, he says, should not be about &lt;em&gt;who&lt;/em&gt; does it, but about &lt;em&gt;what&lt;/em&gt; scientists are doing. A common sensical enough statement, but one that may sound like an unrealistic utopia to anyone who has ever worked in academia.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;NL-RSE: What Open Science can learn from Open Source&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/nl-rse-what-open-science-can-learn-from--e598c5b9.fh3CfeSY_Z2mRXuJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@umby?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Umberto&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;American sociologist of science [Robert K. Merton](&lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_K._Merton#&quot;&gt;https://en.wikipedia.org/wiki/Robert_K._Merton#&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sociology_of_science_and_CUDOS) recognized this tension: he observed that the social system of science works both in agreement with, but also often in contradiction to, its own ideal. Merton expressed the ideal of science in four concrete moral principles, referred to as CUDOS** : Science must be &lt;strong&gt;C&lt;/strong&gt;ommunist (in the sense of communal), meaning that all scientists have common ownership of scientific goods, giving up intellectual property of their work in exchange for recognition. It should be &lt;strong&gt;U&lt;/strong&gt;niversal, or independent of the socio-political status and personal attributes of its participants. Scientific institutions should also be &lt;strong&gt;D&lt;/strong&gt;isinterested, meaning personal gain of individuals within them is inferior to the greater goal of the scientific enterprise. Lastly, science must have &lt;strong&gt;O&lt;/strong&gt;rganised &lt;strong&gt;S&lt;/strong&gt;cepticism.&lt;/p&gt;
&lt;p&gt;For science to be in line with CUDOS, we have to rethink the relationship between scientists and their work. Because every scientific institution inevitably brings their own view of the world to the way they collect, analyse, and publish their data, open access to scientific publications only is not enough. After all, after data is collected, it is translated and analysed (often with the use of in-house developed software), written up into results, preprints and research papers, which can obscure the bias inherent in every step of the way leading up to that publication. Ideally, science openly shares every output that it creates, including data, publications, education, software and other tools. These outputs should be reused to two ends: First, to reproduce existing findings, De la Cueva argues — “&lt;em&gt;there is too much emphasis on novelty in science&lt;/em&gt;”. Second, to combine all levels of existing scientific outputs into new structures, which De la Cueva considers crucial for innovation.&lt;/p&gt;
&lt;p&gt;Open Science can look at the Free Software movement for an example on how to openly share its output. Free Software developers recognise the importance of their software’s reusability, which means they understand the importance of licensing and diversity of licenses. Scientists, on the other hand, do not hold the power to put a license on their scientific output. De la Cueva argues that this should change. Science could, for example, take inspiration from the Internet Engineering Task Force (IETF), which manages standards for the Internet. Any contributor permits the IETF to distribute their contributions freely, and in turn can use any of the other standards, which have been licensed in the same way. This results in an open Internet that is freely accessible to all. If we want CUDOS for science, the same mechanism could be applied to scientific outputs, where scientists permit their contributions to be distributed freely, and in turn are able to freely use others’ contributions.&lt;/p&gt;
&lt;p&gt;De la Cueva points at two signs that science is moving in the right direction. First, the existence of preprint servers. Second, the &lt;a href=&quot;https://www.aje.com/arc/open-access-changing-landscape/&quot;&gt;rise in peer-reviewed open access journals&lt;/a&gt;. And arguably, the increasingly common practice of publicly sharing research software, and adherence to FAIR data principles, can be counted as positive signs too. But there’s still work to be done: “&lt;em&gt;We still pay 9500 euros to obtain open access in&lt;/em&gt; Nature. &lt;em&gt;And the default for publications is still&lt;/em&gt; All rights reserved. &lt;em&gt;This has to end.&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;Thanks to Lourens Veen and Pablo Rodríguez-Sánchez for helpful comments and additions.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/nl-rse-what-open-science-can-learn-from--46f96ea7.B4loulY6.jpg" medium="image"/><author>Lieke de Boer</author></item><item><title>Language Modeling: The First 100 Years</title><link>https://blog.esciencecenter.nl/posts/2023-06-01---language-modeling-the-first-100-years</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-06-01---language-modeling-the-first-100-years</guid><description>&lt;p&gt;&lt;em&gt;ChatGPT has become the symbol for a new wave of Artificial Intelligence. New models with even stronger conversational skills are released on a weekly basis, and the world discusses about their impact on humanity. There are utopian and dystopian fantasies, as well as concrete potentials and risks. A view of the history of language modeling helps to understand the present and the future.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-7a4401d7.BU5-v53y_Z1Yf5uV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@brett_jordan?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Brett Jordan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When Andrej Markov sat down with Alexander Pushkin’s poetic book &lt;em&gt;Eugene Onegin&lt;/em&gt; in 1913, he was not planning to distract himself from his work as a mathematician. Instead, he went through the verses and counted letters, resulting in the study “An Example of Statistical Investigation of the Text &lt;em&gt;Eugene Onegin&lt;/em&gt; Concerning the Connection of Samples in Chains”, &lt;a href=&quot;https://www.cambridge.org/core/journals/science-in-context/article/abs/an-example-of-statistical-investigation-of-the-text-eugene-onegin-concerning-the-connection-of-samples-in-chains/EA1E005FA0BC4522399A4E9DA0304862&quot;&gt;translated into English as late as 2006&lt;/a&gt;. The famous mathematician was not so much fascinated by the poetry, but by the distribution of consonants and vowels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;405&quot; height=&quot;599&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-ffedec5e.7v742PVF_ZV8yce.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Andrej Markov — By Unknown author — Converted into JPEG format from [1], Public Domain, &lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=448609&quot;&gt;https://commons.wikimedia.org/w/index.php?curid=448609&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;causes-and-conditions&quot;&gt;Causes and Conditions&lt;/h2&gt;
&lt;p&gt;Markov demonstrated that the likelihood of a letter being a vowel or a consonant can be approximated from its preceding letters. Based on these findings, he developed a probabilistic model for causal sequences, today known as Markov chain. The so-called Markov assumption holds for language on various levels beyond characters, including words. Look at the following sentence stub:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a big &amp;#x3C;?&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As readers, we cannot say which word should replace the &lt;em&gt;&amp;#x3C;?&gt;&lt;/em&gt;, but based on the preceding words, we know it is likely a noun (e.g. &lt;em&gt;house&lt;/em&gt; or &lt;em&gt;tree&lt;/em&gt;) or another adjective (e.g. &lt;em&gt;beautiful&lt;/em&gt; or &lt;em&gt;green&lt;/em&gt;) and most certainly not a determiner (e.g. &lt;em&gt;the&lt;/em&gt; or &lt;em&gt;a&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Conditional probability plays an important role: while &lt;em&gt;the&lt;/em&gt; is the most frequent word in English, it is very unlikely to occur in the position of the &lt;em&gt;&amp;#x3C;?&gt;&lt;/em&gt; above. Language modeling is about formalizing this kind of linguistic structures: what is the probability of a word &lt;em&gt;w&lt;/em&gt;, given a sequence of words &lt;em&gt;w1&lt;/em&gt;, &lt;em&gt;w2&lt;/em&gt;, … . The language model can be expressed mathematically as &lt;em&gt;P&lt;/em&gt;(&lt;em&gt;w&lt;/em&gt;|&lt;em&gt;c&lt;/em&gt;), where &lt;em&gt;c&lt;/em&gt; is short for the given word sequence. As English speakers, we know that for the context &lt;em&gt;c&lt;/em&gt; given above, the conditional** probability of &lt;em&gt;the&lt;/em&gt; — &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;the&lt;/strong&gt;|&lt;em&gt;c&lt;/em&gt;) — is much lower than, for instance, &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;house&lt;/strong&gt;|&lt;em&gt;c&lt;/em&gt;), even though the &lt;strong&gt;unconditional&lt;/strong&gt; probability &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;the&lt;/strong&gt;) is larger than that of any other word.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;512&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-cd3d68fc.CZlWP48u_Z1FzBIe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Markov Chains — Joxemai4, CC BY-SA 3.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/3.0&quot;&gt;https://creativecommons.org/licenses/by-sa/3.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Apart from the grammatical functions of words, semantics — the meanings of words — play an important role when estimating these probabilities. While, for instance, &lt;em&gt;dwarf&lt;/em&gt; is a noun just like &lt;em&gt;house&lt;/em&gt; or &lt;em&gt;tree&lt;/em&gt;, it is semantically less likely to appear after the adjective &lt;em&gt;big&lt;/em&gt;; while &lt;em&gt;big dwarf&lt;/em&gt; is perfectly valid syntactically, it is an oxymoron and therefore unlikely (but not impossible) to occur. Therefore, &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;tree&lt;/strong&gt;|&lt;strong&gt;big&lt;/strong&gt;) is larger than &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;dwarf&lt;/strong&gt;|&lt;strong&gt;big&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;By counting word sequences in a text data set — the training data — , these probabilities can be estimated. However, there will always be (new) words that do not occur in the training data which combine letters in previously unseen, but valid sequences. There also is an infinite number of valid sentences; regardless of how many texts a model has processed, words will always be arranged in ways that have never been seen before. Frequency-based methods conceptually suffer from the “&lt;a href=&quot;https://plato.stanford.edu/entries/induction-problem/&quot;&gt;problem of induction&lt;/a&gt;”: what was written in the past can at best approximate what will be written in the future. Taking that uncertainty into account has been the difficult part of language modeling.&lt;/p&gt;
&lt;h2 id=&quot;enigmatic-language&quot;&gt;Enigmatic Language&lt;/h2&gt;
&lt;p&gt;During World War 2, three decades after Markov’s experiments, mathematicians from both sides ran a race to encrypt their radio messages. With the help of statistical knowledge about language (plus some blunders from the other side), the famous team around British mathematician Alan Turing at Bletchley Park eventually managed to decipher the messages encrypted with the Enigma machine used by the German military.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;763&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-2f68a964.BFsFbNva_Z18WXt5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Enigma encryption machine — Museo della Scienza e della Tecnologia “Leonardo da Vinci”, CC BY-SA 4.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0&quot;&gt;https://creativecommons.org/licenses/by-sa/4.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Motivated by the success during the war, information theory and cryptography coined the mental model of language modeling. As a former PhD student of the famous information scientist Claude Shannon, Warren Weaver proposed to apply statistical methods to translate texts from one language into another.&lt;/p&gt;
&lt;p&gt;The basic idea was: let’s look at a text in another language (Russian) as if it was an encrypted (English) text. We could then use the methods used for decryption to translate it from Russian into English. Probably needless to say that this did not work very well. The immense productivity of language does not really align with the way encryption algorithms work.&lt;/p&gt;
&lt;h2 id=&quot;distributional-semantics&quot;&gt;Distributional Semantics&lt;/h2&gt;
&lt;p&gt;From a linguistics perspective, the likelihood of a word occurring in a particular position in a sentence depends on two dimensions: syntax and semantics. For the former, human language tends to develop grammatical rules. Formalizing the grammar of a language by these rules was a focus for computational linguists for a long time, but never fully succeeded because there are many exceptions to these rules. Additionally, they are subject to change over time, and are not always followed even by native speakers of a language.&lt;/p&gt;
&lt;p&gt;Modeling semantics, on the other hand, is essential for modeling not only syntactically valid, but also meaningful sentences. This poses other challenges than grammatical rules. There are identical words that have multiple meanings (homonyms, e.g. &lt;em&gt;bank&lt;/em&gt;), there are different words that have (almost) identical meanings (synonyms, e.g. &lt;em&gt;freedom&lt;/em&gt; and &lt;em&gt;liberty&lt;/em&gt;), and there is a very broad spectrum in between. The nuanced meaning of a word can differ per culture, dialect, and even individual speaker.&lt;/p&gt;
&lt;p&gt;The British linguist John Rupert Firth noted in 1957 that “a word is characterized by the company it keeps”. This insight has opened a beautiful door towards statistically modeling the semantics of a word. If two words appear in similar contexts frequently, it implies that their meaning is related. Note that there are many types of relatedness, including similarity, oppositions, as well as the syntactical function.&lt;/p&gt;
&lt;p&gt;Distributional semantics and the Markov assumption have since melted into a powerful armory in language modeling by the use of &lt;em&gt;n&lt;/em&gt;-grams, windows in a text whereby &lt;em&gt;n&lt;/em&gt; stands for the window size. For instance, three words form a tri-gram (or 3-gram). Like so many techniques for language processing, this can be applied on various levels again, including characters and words.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/N-gram_language_model&quot;&gt;&lt;em&gt;n&lt;/em&gt;-gram models&lt;/a&gt; of varying values for &lt;em&gt;n&lt;/em&gt; have proven to be robust for estimating frequency-based language models without explicitly taking syntactic rules into account. In applications such as machine translation or speech recognition, such models have been combined with a translation model or an acoustic model respectively. They used to form the basis of the state-of-the-art algorithms in these and other sub-fields of Natural Language Processing for a long time.&lt;/p&gt;
&lt;h2 id=&quot;embedding-words&quot;&gt;Embedding Words&lt;/h2&gt;
&lt;p&gt;The rise of artificial neural networks has brought its own methods to implement the distributional semantics hypothesis. &lt;a href=&quot;https://github.com/tmikolov/word2vec&quot;&gt;Word2Vec&lt;/a&gt; (2013), &lt;a href=&quot;https://nlp.stanford.edu/projects/glove/&quot;&gt;Glove&lt;/a&gt; (2014), &lt;a href=&quot;https://fasttext.cc/&quot;&gt;FastText&lt;/a&gt; (2016) and more generate vector representations for each word based on context windows around the word. These algorithms do not directly rely on frequencies, but their parameters are optimized so that the resulting representations of two words end up close in the vector space if they tend to occur in similar contexts. These vector representations are called word embeddings.&lt;/p&gt;
&lt;p&gt;Word embeddings do not only represent the meanings of words, the vector space into which they are embedded also allows arithmetic operations in the semantic space. A notorious example: when you take the vector for &lt;em&gt;king&lt;/em&gt;, then subtract the vector for &lt;em&gt;man&lt;/em&gt;, and add the vector for &lt;em&gt;woman&lt;/em&gt;, you come out close to the vector for &lt;em&gt;queen&lt;/em&gt;. Interestingly, these embeddings tend to encode both semantics and syntactical functions — reflecting the linguistic insight that the boundary between syntax and semantics is often affluent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-aa3f1bb3.zonGYRj8_Z1NpnxV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Distributional Word Representations — Singerep, CC BY-SA 4.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0&quot;&gt;https://creativecommons.org/licenses/by-sa/4.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given those representations of individual words, the next level in language modeling is thus to represent sequences of words — phrases, sentences, or entire documents. The simplest approach is to concatenate or average all the word vectors of a sentence, and use it as input to any machine learning algorithm.&lt;/p&gt;
&lt;p&gt;Recurrent neural networks (RNNs) have been more successful by combining a neural network’s state after processing one word with the embeddings for the following word. After iterating over an entire sentence, the network output yields a vector representation, including linguistic phenomena like negation and references between words.&lt;/p&gt;
&lt;p&gt;RNNs, however, face two major disadvantages: important contextual information can be located at a far distance in a text, and the recursive nature of an RNN prevents parallel computation. LSTM and GRU gates have extended RNNs, but only mitigated the first issue.&lt;/p&gt;
&lt;p&gt;In 2017, the architecture that enables current models was proposed: &lt;em&gt;Transformers&lt;/em&gt;. Dedicated &lt;em&gt;attention matrices&lt;/em&gt; (already &lt;a href=&quot;https://arxiv.org/abs/1409.0473&quot;&gt;proposed in 2014&lt;/a&gt;) learn which parts in an input sequence are important, instead of paying attention to a predefined context window. That allows a language model to, for instance, interpret the meaning of the ambiguous word &lt;em&gt;bank&lt;/em&gt; by paying attention to occurrences of words like &lt;em&gt;river&lt;/em&gt; — or perhaps &lt;em&gt;rob&lt;/em&gt; and &lt;em&gt;money&lt;/em&gt; — anywhere in a text. That mechanism enables Transformer models to take very large contexts into account, while the optimization of the model parameters can be parallelized efficiently.&lt;/p&gt;
&lt;p&gt;There are different techniques for the optimization of these parameters. The famous &lt;a href=&quot;https://aclanthology.org/N19-1423/&quot;&gt;BERT&lt;/a&gt;-family of models is optimized&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;to fill random gaps in the sentences of the training data (masked language modeling), and&lt;/li&gt;
&lt;li&gt;to decide whether a particular sentence follows another one (next sentence prediction).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These techniques are especially effective for generating vector-based, numeric representations of words and texts that can be used for NLP tasks like, for instance, document classification.&lt;/p&gt;
&lt;p&gt;Generative models like GPT on the other hand go back to where Andrej Markov started: they are optimized to predict the next word in a sequence. On top of that, the &lt;a href=&quot;https://proceedings.neurips.cc/paper_files/paper/2022/hash/f978c8f3b5f399cae464e85f72e28503-Abstract-Conference.html&quot;&gt;RLHF (&lt;em&gt;Reinforcement Learning from Human Feedback&lt;/em&gt;)&lt;/a&gt; technique has enabled the model to learn very effectively from human “AI Trainers”, resulting in the impressive conversational skills that ChatGPT has shown.&lt;/p&gt;
&lt;p&gt;The combination of more effective and scalable training techniques and the immense number of parameters enable such models to produce texts in a specific language. They are fed virtually the entire internet, therewith learning almost all human languages. Even programming languages come as an (intentional) extra, enabling GPT-based models to function as programming assistants.&lt;/p&gt;
&lt;h2 id=&quot;modeling-language-the-next-100-years&quot;&gt;Modeling Language: The Next 100 Years&lt;/h2&gt;
&lt;p&gt;Looking back into the history of language modeling illustrates that Artificial Intelligence has not suddenly emerged in the recent past. The current generation of models builds on a rich past of active research in the fields of computational linguistics, natural language processing, information theory, and related fields; to reiterate some milestones: the &lt;a href=&quot;https://proceedings.neurips.cc/paper_files/paper/2022/hash/f978c8f3b5f399cae464e85f72e28503-Abstract-Conference.html&quot;&gt;RLHF method from 2019&lt;/a&gt; fine-tunes models based on the &lt;a href=&quot;https://papers.nips.cc/paper_files/paper/2017/hash/3f5ee243547dee91fbd053c1c4a845aa-Abstract.html&quot;&gt;Transformers neural network architecture from 2017&lt;/a&gt;. Transformer-based models have improved upon the word embeddings as introduced by &lt;a href=&quot;https://papers.nips.cc/paper_files/paper/2013/hash/9aa42b31882ec039965f3c4923ce901b-Abstract.html&quot;&gt;Word2Vec (2013)&lt;/a&gt;. Linguistic and stochastic theory has laid the basis for such algorithms.&lt;/p&gt;
&lt;p&gt;The race has now shifted into the arena of engineering and productizing, as in making language models smaller and faster and embedding them into useful applications. Significant progress on the quality side is nowhere to be seen currently. As an &lt;a href=&quot;https://www.semianalysis.com/p/google-we-have-no-moat-and-neither&quot;&gt;internal Google document&lt;/a&gt; stated recently, none of the big companies like OpenAI, Microsoft, Google or Facebook seem to have a model or strategy that could outcompete the others. More efficient, often free, and qualitatively competitive models appear on a weekly basis.&lt;/p&gt;
&lt;p&gt;On the other hand, language models can generate incredibly fluent language, but are intransparent and inaccurate &lt;a href=&quot;https://www.newyorker.com/tech/annals-of-technology/chatgpt-is-a-blurry-jpeg-of-the-web&quot;&gt;by definition&lt;/a&gt;. These properties make them credible actors in conversations with humans, while posing difficulties on applications like search and coding assistance.&lt;/p&gt;
&lt;p&gt;Debates about imminent singularity in which Artificial Intelligence spontaneously starts improving itself live in the realm of fiction rather than science. Such mystifications can take both utopian and dystopian angles, but rely on beliefs, lacking specific evidence. Apocalypses have been predicted many times with respect to Artificial Intelligence as well as other technologies. Grand stories about the faith of humanity absorb a lot of attention, but tend to reduce and over-simplify complex matters.&lt;/p&gt;
&lt;p&gt;Technology, however, is only one factor — predictions about the future of our society, let alone humanity, are at best naive if they ignore political, economical, and societal factors. For a productive discussion that takes realistic risks and potentials of new technologies into account, experts from all these fields need to join forces.&lt;/p&gt;</description><pubDate>Thu, 01 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;ChatGPT has become the symbol for a new wave of Artificial Intelligence. New models with even stronger conversational skills are released on a weekly basis, and the world discusses about their impact on humanity. There are utopian and dystopian fantasies, as well as concrete potentials and risks. A view of the history of language modeling helps to understand the present and the future.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-7a4401d7.BU5-v53y_Z1Yf5uV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@brett_jordan?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Brett Jordan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When Andrej Markov sat down with Alexander Pushkin’s poetic book &lt;em&gt;Eugene Onegin&lt;/em&gt; in 1913, he was not planning to distract himself from his work as a mathematician. Instead, he went through the verses and counted letters, resulting in the study “An Example of Statistical Investigation of the Text &lt;em&gt;Eugene Onegin&lt;/em&gt; Concerning the Connection of Samples in Chains”, &lt;a href=&quot;https://www.cambridge.org/core/journals/science-in-context/article/abs/an-example-of-statistical-investigation-of-the-text-eugene-onegin-concerning-the-connection-of-samples-in-chains/EA1E005FA0BC4522399A4E9DA0304862&quot;&gt;translated into English as late as 2006&lt;/a&gt;. The famous mathematician was not so much fascinated by the poetry, but by the distribution of consonants and vowels.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;405&quot; height=&quot;599&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-ffedec5e.7v742PVF_ZV8yce.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Andrej Markov — By Unknown author — Converted into JPEG format from [1], Public Domain, &lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=448609&quot;&gt;https://commons.wikimedia.org/w/index.php?curid=448609&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;causes-and-conditions&quot;&gt;Causes and Conditions&lt;/h2&gt;
&lt;p&gt;Markov demonstrated that the likelihood of a letter being a vowel or a consonant can be approximated from its preceding letters. Based on these findings, he developed a probabilistic model for causal sequences, today known as Markov chain. The so-called Markov assumption holds for language on various levels beyond characters, including words. Look at the following sentence stub:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a big &amp;#x3C;?&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As readers, we cannot say which word should replace the &lt;em&gt;&amp;#x3C;?&gt;&lt;/em&gt;, but based on the preceding words, we know it is likely a noun (e.g. &lt;em&gt;house&lt;/em&gt; or &lt;em&gt;tree&lt;/em&gt;) or another adjective (e.g. &lt;em&gt;beautiful&lt;/em&gt; or &lt;em&gt;green&lt;/em&gt;) and most certainly not a determiner (e.g. &lt;em&gt;the&lt;/em&gt; or &lt;em&gt;a&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Conditional probability plays an important role: while &lt;em&gt;the&lt;/em&gt; is the most frequent word in English, it is very unlikely to occur in the position of the &lt;em&gt;&amp;#x3C;?&gt;&lt;/em&gt; above. Language modeling is about formalizing this kind of linguistic structures: what is the probability of a word &lt;em&gt;w&lt;/em&gt;, given a sequence of words &lt;em&gt;w1&lt;/em&gt;, &lt;em&gt;w2&lt;/em&gt;, … . The language model can be expressed mathematically as &lt;em&gt;P&lt;/em&gt;(&lt;em&gt;w&lt;/em&gt;|&lt;em&gt;c&lt;/em&gt;), where &lt;em&gt;c&lt;/em&gt; is short for the given word sequence. As English speakers, we know that for the context &lt;em&gt;c&lt;/em&gt; given above, the conditional** probability of &lt;em&gt;the&lt;/em&gt; — &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;the&lt;/strong&gt;|&lt;em&gt;c&lt;/em&gt;) — is much lower than, for instance, &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;house&lt;/strong&gt;|&lt;em&gt;c&lt;/em&gt;), even though the &lt;strong&gt;unconditional&lt;/strong&gt; probability &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;the&lt;/strong&gt;) is larger than that of any other word.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;512&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-cd3d68fc.CZlWP48u_Z1FzBIe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Markov Chains — Joxemai4, CC BY-SA 3.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/3.0&quot;&gt;https://creativecommons.org/licenses/by-sa/3.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Apart from the grammatical functions of words, semantics — the meanings of words — play an important role when estimating these probabilities. While, for instance, &lt;em&gt;dwarf&lt;/em&gt; is a noun just like &lt;em&gt;house&lt;/em&gt; or &lt;em&gt;tree&lt;/em&gt;, it is semantically less likely to appear after the adjective &lt;em&gt;big&lt;/em&gt;; while &lt;em&gt;big dwarf&lt;/em&gt; is perfectly valid syntactically, it is an oxymoron and therefore unlikely (but not impossible) to occur. Therefore, &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;tree&lt;/strong&gt;|&lt;strong&gt;big&lt;/strong&gt;) is larger than &lt;em&gt;P&lt;/em&gt;(&lt;strong&gt;dwarf&lt;/strong&gt;|&lt;strong&gt;big&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;By counting word sequences in a text data set — the training data — , these probabilities can be estimated. However, there will always be (new) words that do not occur in the training data which combine letters in previously unseen, but valid sequences. There also is an infinite number of valid sentences; regardless of how many texts a model has processed, words will always be arranged in ways that have never been seen before. Frequency-based methods conceptually suffer from the “&lt;a href=&quot;https://plato.stanford.edu/entries/induction-problem/&quot;&gt;problem of induction&lt;/a&gt;”: what was written in the past can at best approximate what will be written in the future. Taking that uncertainty into account has been the difficult part of language modeling.&lt;/p&gt;
&lt;h2 id=&quot;enigmatic-language&quot;&gt;Enigmatic Language&lt;/h2&gt;
&lt;p&gt;During World War 2, three decades after Markov’s experiments, mathematicians from both sides ran a race to encrypt their radio messages. With the help of statistical knowledge about language (plus some blunders from the other side), the famous team around British mathematician Alan Turing at Bletchley Park eventually managed to decipher the messages encrypted with the Enigma machine used by the German military.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;763&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-2f68a964.BFsFbNva_Z18WXt5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Enigma encryption machine — Museo della Scienza e della Tecnologia “Leonardo da Vinci”, CC BY-SA 4.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0&quot;&gt;https://creativecommons.org/licenses/by-sa/4.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Motivated by the success during the war, information theory and cryptography coined the mental model of language modeling. As a former PhD student of the famous information scientist Claude Shannon, Warren Weaver proposed to apply statistical methods to translate texts from one language into another.&lt;/p&gt;
&lt;p&gt;The basic idea was: let’s look at a text in another language (Russian) as if it was an encrypted (English) text. We could then use the methods used for decryption to translate it from Russian into English. Probably needless to say that this did not work very well. The immense productivity of language does not really align with the way encryption algorithms work.&lt;/p&gt;
&lt;h2 id=&quot;distributional-semantics&quot;&gt;Distributional Semantics&lt;/h2&gt;
&lt;p&gt;From a linguistics perspective, the likelihood of a word occurring in a particular position in a sentence depends on two dimensions: syntax and semantics. For the former, human language tends to develop grammatical rules. Formalizing the grammar of a language by these rules was a focus for computational linguists for a long time, but never fully succeeded because there are many exceptions to these rules. Additionally, they are subject to change over time, and are not always followed even by native speakers of a language.&lt;/p&gt;
&lt;p&gt;Modeling semantics, on the other hand, is essential for modeling not only syntactically valid, but also meaningful sentences. This poses other challenges than grammatical rules. There are identical words that have multiple meanings (homonyms, e.g. &lt;em&gt;bank&lt;/em&gt;), there are different words that have (almost) identical meanings (synonyms, e.g. &lt;em&gt;freedom&lt;/em&gt; and &lt;em&gt;liberty&lt;/em&gt;), and there is a very broad spectrum in between. The nuanced meaning of a word can differ per culture, dialect, and even individual speaker.&lt;/p&gt;
&lt;p&gt;The British linguist John Rupert Firth noted in 1957 that “a word is characterized by the company it keeps”. This insight has opened a beautiful door towards statistically modeling the semantics of a word. If two words appear in similar contexts frequently, it implies that their meaning is related. Note that there are many types of relatedness, including similarity, oppositions, as well as the syntactical function.&lt;/p&gt;
&lt;p&gt;Distributional semantics and the Markov assumption have since melted into a powerful armory in language modeling by the use of &lt;em&gt;n&lt;/em&gt;-grams, windows in a text whereby &lt;em&gt;n&lt;/em&gt; stands for the window size. For instance, three words form a tri-gram (or 3-gram). Like so many techniques for language processing, this can be applied on various levels again, including characters and words.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/N-gram_language_model&quot;&gt;&lt;em&gt;n&lt;/em&gt;-gram models&lt;/a&gt; of varying values for &lt;em&gt;n&lt;/em&gt; have proven to be robust for estimating frequency-based language models without explicitly taking syntactic rules into account. In applications such as machine translation or speech recognition, such models have been combined with a translation model or an acoustic model respectively. They used to form the basis of the state-of-the-art algorithms in these and other sub-fields of Natural Language Processing for a long time.&lt;/p&gt;
&lt;h2 id=&quot;embedding-words&quot;&gt;Embedding Words&lt;/h2&gt;
&lt;p&gt;The rise of artificial neural networks has brought its own methods to implement the distributional semantics hypothesis. &lt;a href=&quot;https://github.com/tmikolov/word2vec&quot;&gt;Word2Vec&lt;/a&gt; (2013), &lt;a href=&quot;https://nlp.stanford.edu/projects/glove/&quot;&gt;Glove&lt;/a&gt; (2014), &lt;a href=&quot;https://fasttext.cc/&quot;&gt;FastText&lt;/a&gt; (2016) and more generate vector representations for each word based on context windows around the word. These algorithms do not directly rely on frequencies, but their parameters are optimized so that the resulting representations of two words end up close in the vector space if they tend to occur in similar contexts. These vector representations are called word embeddings.&lt;/p&gt;
&lt;p&gt;Word embeddings do not only represent the meanings of words, the vector space into which they are embedded also allows arithmetic operations in the semantic space. A notorious example: when you take the vector for &lt;em&gt;king&lt;/em&gt;, then subtract the vector for &lt;em&gt;man&lt;/em&gt;, and add the vector for &lt;em&gt;woman&lt;/em&gt;, you come out close to the vector for &lt;em&gt;queen&lt;/em&gt;. Interestingly, these embeddings tend to encode both semantics and syntactical functions — reflecting the linguistic insight that the boundary between syntax and semantics is often affluent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Language Modeling: The First 100 Years&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-aa3f1bb3.zonGYRj8_Z1NpnxV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Distributional Word Representations — Singerep, CC BY-SA 4.0 &amp;#x3C;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0&quot;&gt;https://creativecommons.org/licenses/by-sa/4.0&lt;/a&gt;&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given those representations of individual words, the next level in language modeling is thus to represent sequences of words — phrases, sentences, or entire documents. The simplest approach is to concatenate or average all the word vectors of a sentence, and use it as input to any machine learning algorithm.&lt;/p&gt;
&lt;p&gt;Recurrent neural networks (RNNs) have been more successful by combining a neural network’s state after processing one word with the embeddings for the following word. After iterating over an entire sentence, the network output yields a vector representation, including linguistic phenomena like negation and references between words.&lt;/p&gt;
&lt;p&gt;RNNs, however, face two major disadvantages: important contextual information can be located at a far distance in a text, and the recursive nature of an RNN prevents parallel computation. LSTM and GRU gates have extended RNNs, but only mitigated the first issue.&lt;/p&gt;
&lt;p&gt;In 2017, the architecture that enables current models was proposed: &lt;em&gt;Transformers&lt;/em&gt;. Dedicated &lt;em&gt;attention matrices&lt;/em&gt; (already &lt;a href=&quot;https://arxiv.org/abs/1409.0473&quot;&gt;proposed in 2014&lt;/a&gt;) learn which parts in an input sequence are important, instead of paying attention to a predefined context window. That allows a language model to, for instance, interpret the meaning of the ambiguous word &lt;em&gt;bank&lt;/em&gt; by paying attention to occurrences of words like &lt;em&gt;river&lt;/em&gt; — or perhaps &lt;em&gt;rob&lt;/em&gt; and &lt;em&gt;money&lt;/em&gt; — anywhere in a text. That mechanism enables Transformer models to take very large contexts into account, while the optimization of the model parameters can be parallelized efficiently.&lt;/p&gt;
&lt;p&gt;There are different techniques for the optimization of these parameters. The famous &lt;a href=&quot;https://aclanthology.org/N19-1423/&quot;&gt;BERT&lt;/a&gt;-family of models is optimized&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;to fill random gaps in the sentences of the training data (masked language modeling), and&lt;/li&gt;
&lt;li&gt;to decide whether a particular sentence follows another one (next sentence prediction).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These techniques are especially effective for generating vector-based, numeric representations of words and texts that can be used for NLP tasks like, for instance, document classification.&lt;/p&gt;
&lt;p&gt;Generative models like GPT on the other hand go back to where Andrej Markov started: they are optimized to predict the next word in a sequence. On top of that, the &lt;a href=&quot;https://proceedings.neurips.cc/paper_files/paper/2022/hash/f978c8f3b5f399cae464e85f72e28503-Abstract-Conference.html&quot;&gt;RLHF (&lt;em&gt;Reinforcement Learning from Human Feedback&lt;/em&gt;)&lt;/a&gt; technique has enabled the model to learn very effectively from human “AI Trainers”, resulting in the impressive conversational skills that ChatGPT has shown.&lt;/p&gt;
&lt;p&gt;The combination of more effective and scalable training techniques and the immense number of parameters enable such models to produce texts in a specific language. They are fed virtually the entire internet, therewith learning almost all human languages. Even programming languages come as an (intentional) extra, enabling GPT-based models to function as programming assistants.&lt;/p&gt;
&lt;h2 id=&quot;modeling-language-the-next-100-years&quot;&gt;Modeling Language: The Next 100 Years&lt;/h2&gt;
&lt;p&gt;Looking back into the history of language modeling illustrates that Artificial Intelligence has not suddenly emerged in the recent past. The current generation of models builds on a rich past of active research in the fields of computational linguistics, natural language processing, information theory, and related fields; to reiterate some milestones: the &lt;a href=&quot;https://proceedings.neurips.cc/paper_files/paper/2022/hash/f978c8f3b5f399cae464e85f72e28503-Abstract-Conference.html&quot;&gt;RLHF method from 2019&lt;/a&gt; fine-tunes models based on the &lt;a href=&quot;https://papers.nips.cc/paper_files/paper/2017/hash/3f5ee243547dee91fbd053c1c4a845aa-Abstract.html&quot;&gt;Transformers neural network architecture from 2017&lt;/a&gt;. Transformer-based models have improved upon the word embeddings as introduced by &lt;a href=&quot;https://papers.nips.cc/paper_files/paper/2013/hash/9aa42b31882ec039965f3c4923ce901b-Abstract.html&quot;&gt;Word2Vec (2013)&lt;/a&gt;. Linguistic and stochastic theory has laid the basis for such algorithms.&lt;/p&gt;
&lt;p&gt;The race has now shifted into the arena of engineering and productizing, as in making language models smaller and faster and embedding them into useful applications. Significant progress on the quality side is nowhere to be seen currently. As an &lt;a href=&quot;https://www.semianalysis.com/p/google-we-have-no-moat-and-neither&quot;&gt;internal Google document&lt;/a&gt; stated recently, none of the big companies like OpenAI, Microsoft, Google or Facebook seem to have a model or strategy that could outcompete the others. More efficient, often free, and qualitatively competitive models appear on a weekly basis.&lt;/p&gt;
&lt;p&gt;On the other hand, language models can generate incredibly fluent language, but are intransparent and inaccurate &lt;a href=&quot;https://www.newyorker.com/tech/annals-of-technology/chatgpt-is-a-blurry-jpeg-of-the-web&quot;&gt;by definition&lt;/a&gt;. These properties make them credible actors in conversations with humans, while posing difficulties on applications like search and coding assistance.&lt;/p&gt;
&lt;p&gt;Debates about imminent singularity in which Artificial Intelligence spontaneously starts improving itself live in the realm of fiction rather than science. Such mystifications can take both utopian and dystopian angles, but rely on beliefs, lacking specific evidence. Apocalypses have been predicted many times with respect to Artificial Intelligence as well as other technologies. Grand stories about the faith of humanity absorb a lot of attention, but tend to reduce and over-simplify complex matters.&lt;/p&gt;
&lt;p&gt;Technology, however, is only one factor — predictions about the future of our society, let alone humanity, are at best naive if they ignore political, economical, and societal factors. For a productive discussion that takes realistic risks and potentials of new technologies into account, experts from all these fields need to join forces.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/language-modeling-the-first-100-years-7a4401d7.BU5-v53y.jpg" medium="image"/><author>Carsten Schnober</author></item><item><title>Research Ethics and Authorship: The Technological Solution</title><link>https://blog.esciencecenter.nl/posts/2023-05-25---research-ethics-and-authorship-the-technological-solution</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-05-25---research-ethics-and-authorship-the-technological-solution</guid><description>&lt;h2 id=&quot;dr-candace-makeda-moore-discusses-the-potential-for-distributed-version-control-as-a-tool-to-prevent-questionable-authorship-practices&quot;&gt;Dr. Candace Makeda Moore discusses the potential for distributed version control as a tool to prevent questionable authorship practices.&lt;/h2&gt;
&lt;p&gt;Recently I read a story in &lt;em&gt;Retraction Watc&lt;/em&gt; h about a service selling authorships on scientific papers in the peer review pipeline. On the same day a colleague physician mentioned that at our hospital, there were many cases where authorship was given in exchange for access to certain patients as potential research subjects. While the former type of blatant research fraud makes headlines, the latter barely raises an eyebrow. But giving authorship for research related favors or other ‘political’ reasons is neither a victimless minor crime, nor it is a problem without an easy, free and enforceable solution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VoR_1wmNArGuE5-2-b031096c.MZpTOGMG_230uL5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Annie Spratt on Unsplash&lt;/p&gt;
&lt;p&gt;Because I come from a medical background, I am most familiar with standards in this field, although problems related to authorship extend to most scientific fields.&lt;/p&gt;
&lt;p&gt;Perhaps at this point it’s worth pointing towards what authorship should actually be, using academic medicine as an example. The International Committee of Medical Journal Editors (ICJME) has &lt;a href=&quot;https://www.icmje.org/recommendations/browse/roles-and-responsibilities/defining-the-role-of-authors-and-contributors.html&quot;&gt;exemplary recommendations&lt;/a&gt;. The spirit of these recommendations is incredibly simple: authors should be involved in the design or analysis as well as the literal writing of research. There is some variation in different fields, and differences from place to place, and of course there can be exceptions with specific kinds of research papers e.g. papers for datasets and/or code. But we probably all agree that in least in principle, an author should be someone who does something significant for the work.&lt;/p&gt;
&lt;p&gt;Unfortunately, in day to day academic medical research it is typical to see people getting authorship on papers for all sorts of illegitimate reasons. Getting someone to sign off that researchers can access patients in a particular department, handing over an existing dataset, and many more tasks are necessary and integral parts of research. Such actions deserve praise, and there should be some system to reward such tasks in place, but as the medical-scientific community has defined authorship, they alone should not confer authorship.&lt;/p&gt;
&lt;p&gt;There are several major impediments to the adoption of proper research ethics in authorship in medicine. Some are simply related to inertia and the infamous conservatism of medicine. At many institutions authorship is given in customary ways including to any principal investigator (PI) who so much as attends meetings around research, because &lt;em&gt;‘that is the way it has been done’&lt;/em&gt;. And of course no one wants to get on the bad side of someone like a powerful principal investigator who can potentially ruin their career.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;912&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_D3cyAE6qwer8JuUl-6d02b345.Unl3AIQ7_Z1AvwIF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by National Cancer Institute on Unsplash&lt;/p&gt;
&lt;p&gt;This is, of course, another reason fraudulent authorships happen quite commonly. Politics. In some cases a principal investigator or high ranking researcher may provide very necessary help to a research group, e.g. without their signature nothing will move. But the truth is that there are well defined rules around authorship. One of the reasons for this is that authorship is so critical to advancing academic careers. Unfortunately, in academic medical centers, in practice what this means is that all levels of researchers enter into a treacherous political game where the bulk of authorships tend to accrue towards more established researchers who have more resources in the way of data access, workers and political capital. Such systems favor researchers who are privileged across almost every other axis of privilege possible.&lt;/p&gt;
&lt;p&gt;A medical researcher who lives in the real world of any large academic hospital may think ‘if I don’t give authorships to important professors who helped me, I’ll never get their help again, or worse, they will open some kind of problems for me’. They feel disempowered about what would be essentially telling the truth by demanding correct authorship lists, because it would be their word against the word of someone more powerful and established in many cases. But there is literally a free solution right beneath the nose of researchers.&lt;/p&gt;
&lt;p&gt;Every modern researcher uses a computer to accomplish aspects of their research from code scripts or programs for statistical analysis to word processing programs for writing articles. The solution to these messy problems of authorship is right at the fingertips, or only a mouse click away from anyone with a computer and internet connection. The solution is &lt;strong&gt;distributed version control systems&lt;/strong&gt; like Git or Mercurial.&lt;/p&gt;
&lt;p&gt;When a version controlled repository is created, there is a history of who wrote what and when. Unlike Google Docs or Word or any other of the more common tools for writing papers, version control makes it almost impossible to erase the trace of someone else’s work, or claim you or someone else made significant contributions in writing an article when it did not happen. Unless, of course, you are part of the extremely tiny group of researchers particularly talented with programming. But let’s face it, most people in medical research don’t want to use version control because they literally don’t even know how. They never learned it because it was never considered a critical skill for research.&lt;/p&gt;
&lt;p&gt;Some people do not find git or other version control languages and programs intuitive. For whatever reason this seems particularly true of physicians. However, even leaving issues of authorship aside, version control is an important skill in terms of modern computational research. The Netherlands eScience Center offers small hands on courses lasting one or a few days to train researchers in this area. An example of one upcoming such course can be viewed &lt;a href=&quot;https://www.esciencecenter.nl/event/good-practices-in-research-software-development/&quot;&gt;here&lt;/a&gt;. We have also contributed to high quality &lt;a href=&quot;https://swcarpentry.github.io/git-novice/index.html&quot;&gt;open source free lesson material&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While such programs are often used in practice with services like Github or Gitlab, they need not be. Technically, you could just create a repository and send files for it to other people. You can even sign commits with and/or make them traceable by servers. If you use git, you can use `git blame` to figure out who did something.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;It looks like I may be to blame for problems in this environment?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LmRkMTNvxvcbQ0k7NXoOZg-33c307bf.CGvKcF-W_1vqOOq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I may have some blame for problems in the environment in this program (output of `git blame` in a terminal)&lt;/p&gt;
&lt;p&gt;Obviously, using version control as the medium through which scientific papers are written favors the young and computer savvy. Would this cause the reverse problem to privileging the old and established? Hardly. Help for Git or any other open source version control system can be found across the internet. Lately, I often run across young students who have taught themselves to use a version control system without anyone asking them to for a class. The biggest barrier to learning version control systems for most high ranking researchers in medicine may be the psychological pain of having to ask people they consider their inferiors for help.&lt;/p&gt;
&lt;p&gt;In a world where people are questioning if what journals actually do is of any value when everyone could just publish on the internet and/or preprint servers, checking authorship should be a task that they are legitimately valued for. Such a task could be accomplished using free open source software like Git. The only thing necessary is a dash of skill in computing, or barring that, some learning.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;346&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_dmCCMU2_nkATdc_qG9xJSQ-c26bf96e.c7qQYxpJ_Z1uUiST.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One approach to begin learning version control is simply searching and reading on the internet&lt;/p&gt;
&lt;p&gt;How am I sure this could work? Because we see these processes everywhere and all the time in terms of the code related to research. I myself am an author on several open code repositories related to medical signal processing and/or image processing, and if anyone were to question my role, I could just point to the lines of code I wrote as evidence that I did in fact do real work. Open source code provides a model for how papers could be made way more transparent in terms of authorship. In fact if researchers were to send their code repository and a related repositories which include study design documents, every aspect of authorship can be verified.&lt;/p&gt;
&lt;p&gt;Physicians are often called upon to lead research in medicine for obvious reasons, but have never really get trained (save a few who had post-graduate training in very select fields such as imaging informatics or public health) to do any computational research at all. A future where physicians and others working in medical research take a few days to learn the fundamental tools of computational research is a better future for everyone, because then we can efficiently combine clinical insight and large datasets. Whether to shield themselves from authorship problems, or go after the larger goal of better science, medical researchers should embrace version control.&lt;/p&gt;</description><pubDate>Thu, 25 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;dr-candace-makeda-moore-discusses-the-potential-for-distributed-version-control-as-a-tool-to-prevent-questionable-authorship-practices&quot;&gt;Dr. Candace Makeda Moore discusses the potential for distributed version control as a tool to prevent questionable authorship practices.&lt;/h2&gt;
&lt;p&gt;Recently I read a story in &lt;em&gt;Retraction Watc&lt;/em&gt; h about a service selling authorships on scientific papers in the peer review pipeline. On the same day a colleague physician mentioned that at our hospital, there were many cases where authorship was given in exchange for access to certain patients as potential research subjects. While the former type of blatant research fraud makes headlines, the latter barely raises an eyebrow. But giving authorship for research related favors or other ‘political’ reasons is neither a victimless minor crime, nor it is a problem without an easy, free and enforceable solution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VoR_1wmNArGuE5-2-b031096c.MZpTOGMG_230uL5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Annie Spratt on Unsplash&lt;/p&gt;
&lt;p&gt;Because I come from a medical background, I am most familiar with standards in this field, although problems related to authorship extend to most scientific fields.&lt;/p&gt;
&lt;p&gt;Perhaps at this point it’s worth pointing towards what authorship should actually be, using academic medicine as an example. The International Committee of Medical Journal Editors (ICJME) has &lt;a href=&quot;https://www.icmje.org/recommendations/browse/roles-and-responsibilities/defining-the-role-of-authors-and-contributors.html&quot;&gt;exemplary recommendations&lt;/a&gt;. The spirit of these recommendations is incredibly simple: authors should be involved in the design or analysis as well as the literal writing of research. There is some variation in different fields, and differences from place to place, and of course there can be exceptions with specific kinds of research papers e.g. papers for datasets and/or code. But we probably all agree that in least in principle, an author should be someone who does something significant for the work.&lt;/p&gt;
&lt;p&gt;Unfortunately, in day to day academic medical research it is typical to see people getting authorship on papers for all sorts of illegitimate reasons. Getting someone to sign off that researchers can access patients in a particular department, handing over an existing dataset, and many more tasks are necessary and integral parts of research. Such actions deserve praise, and there should be some system to reward such tasks in place, but as the medical-scientific community has defined authorship, they alone should not confer authorship.&lt;/p&gt;
&lt;p&gt;There are several major impediments to the adoption of proper research ethics in authorship in medicine. Some are simply related to inertia and the infamous conservatism of medicine. At many institutions authorship is given in customary ways including to any principal investigator (PI) who so much as attends meetings around research, because &lt;em&gt;‘that is the way it has been done’&lt;/em&gt;. And of course no one wants to get on the bad side of someone like a powerful principal investigator who can potentially ruin their career.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;912&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_D3cyAE6qwer8JuUl-6d02b345.Unl3AIQ7_Z1AvwIF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by National Cancer Institute on Unsplash&lt;/p&gt;
&lt;p&gt;This is, of course, another reason fraudulent authorships happen quite commonly. Politics. In some cases a principal investigator or high ranking researcher may provide very necessary help to a research group, e.g. without their signature nothing will move. But the truth is that there are well defined rules around authorship. One of the reasons for this is that authorship is so critical to advancing academic careers. Unfortunately, in academic medical centers, in practice what this means is that all levels of researchers enter into a treacherous political game where the bulk of authorships tend to accrue towards more established researchers who have more resources in the way of data access, workers and political capital. Such systems favor researchers who are privileged across almost every other axis of privilege possible.&lt;/p&gt;
&lt;p&gt;A medical researcher who lives in the real world of any large academic hospital may think ‘if I don’t give authorships to important professors who helped me, I’ll never get their help again, or worse, they will open some kind of problems for me’. They feel disempowered about what would be essentially telling the truth by demanding correct authorship lists, because it would be their word against the word of someone more powerful and established in many cases. But there is literally a free solution right beneath the nose of researchers.&lt;/p&gt;
&lt;p&gt;Every modern researcher uses a computer to accomplish aspects of their research from code scripts or programs for statistical analysis to word processing programs for writing articles. The solution to these messy problems of authorship is right at the fingertips, or only a mouse click away from anyone with a computer and internet connection. The solution is &lt;strong&gt;distributed version control systems&lt;/strong&gt; like Git or Mercurial.&lt;/p&gt;
&lt;p&gt;When a version controlled repository is created, there is a history of who wrote what and when. Unlike Google Docs or Word or any other of the more common tools for writing papers, version control makes it almost impossible to erase the trace of someone else’s work, or claim you or someone else made significant contributions in writing an article when it did not happen. Unless, of course, you are part of the extremely tiny group of researchers particularly talented with programming. But let’s face it, most people in medical research don’t want to use version control because they literally don’t even know how. They never learned it because it was never considered a critical skill for research.&lt;/p&gt;
&lt;p&gt;Some people do not find git or other version control languages and programs intuitive. For whatever reason this seems particularly true of physicians. However, even leaving issues of authorship aside, version control is an important skill in terms of modern computational research. The Netherlands eScience Center offers small hands on courses lasting one or a few days to train researchers in this area. An example of one upcoming such course can be viewed &lt;a href=&quot;https://www.esciencecenter.nl/event/good-practices-in-research-software-development/&quot;&gt;here&lt;/a&gt;. We have also contributed to high quality &lt;a href=&quot;https://swcarpentry.github.io/git-novice/index.html&quot;&gt;open source free lesson material&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While such programs are often used in practice with services like Github or Gitlab, they need not be. Technically, you could just create a repository and send files for it to other people. You can even sign commits with and/or make them traceable by servers. If you use git, you can use `git blame` to figure out who did something.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;It looks like I may be to blame for problems in this environment?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LmRkMTNvxvcbQ0k7NXoOZg-33c307bf.CGvKcF-W_1vqOOq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I may have some blame for problems in the environment in this program (output of `git blame` in a terminal)&lt;/p&gt;
&lt;p&gt;Obviously, using version control as the medium through which scientific papers are written favors the young and computer savvy. Would this cause the reverse problem to privileging the old and established? Hardly. Help for Git or any other open source version control system can be found across the internet. Lately, I often run across young students who have taught themselves to use a version control system without anyone asking them to for a class. The biggest barrier to learning version control systems for most high ranking researchers in medicine may be the psychological pain of having to ask people they consider their inferiors for help.&lt;/p&gt;
&lt;p&gt;In a world where people are questioning if what journals actually do is of any value when everyone could just publish on the internet and/or preprint servers, checking authorship should be a task that they are legitimately valued for. Such a task could be accomplished using free open source software like Git. The only thing necessary is a dash of skill in computing, or barring that, some learning.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;346&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_dmCCMU2_nkATdc_qG9xJSQ-c26bf96e.c7qQYxpJ_Z1uUiST.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One approach to begin learning version control is simply searching and reading on the internet&lt;/p&gt;
&lt;p&gt;How am I sure this could work? Because we see these processes everywhere and all the time in terms of the code related to research. I myself am an author on several open code repositories related to medical signal processing and/or image processing, and if anyone were to question my role, I could just point to the lines of code I wrote as evidence that I did in fact do real work. Open source code provides a model for how papers could be made way more transparent in terms of authorship. In fact if researchers were to send their code repository and a related repositories which include study design documents, every aspect of authorship can be verified.&lt;/p&gt;
&lt;p&gt;Physicians are often called upon to lead research in medicine for obvious reasons, but have never really get trained (save a few who had post-graduate training in very select fields such as imaging informatics or public health) to do any computational research at all. A future where physicians and others working in medical research take a few days to learn the fundamental tools of computational research is a better future for everyone, because then we can efficiently combine clinical insight and large datasets. Whether to shield themselves from authorship problems, or go after the larger goal of better science, medical researchers should embrace version control.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_VoR_1wmNArGuE5-2-b031096c.MZpTOGMG.webp" medium="image"/><author>Candace Moore</author></item><item><title>Creating a Community by Integrating Expertise, Tools and Ideas</title><link>https://blog.esciencecenter.nl/posts/2023-05-16---creating-a-community-by-integrating-expertise-tools-and-idea</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-05-16---creating-a-community-by-integrating-expertise-tools-and-idea</guid><description>&lt;p&gt;A personal reflection on the first NPLinker eScience workshop for Natural Product Discovery&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://vdhooftcompmet.github.io/&quot;&gt;Justin van der Hooft&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post is written by Wageningen University &amp;#x26; Research Assistant Professor Justin van der Hooft who participates in the Netherlands eScience Center’s &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/open-escience-call-2021/&quot;&gt;&lt;em&gt;Open eScience Call 2021&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;. His project, “A community-supported workflow connecting microbial genes, and organisms to their molecular products”, aims to facilitate the finding of novel bioactive molecules from nature. It does so by enabling the integrated use of various omics data types.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-7878c100.C_Xe3aQK_2rb83I.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@vollkornapfel?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Adrian Lange&lt;/a&gt; on [Unsplash](&lt;a href=&quot;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&quot;&gt;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Text)&lt;/p&gt;
&lt;h3 id=&quot;motivation-for-the-workshop&quot;&gt;Motivation for the workshop**&lt;/h3&gt;
&lt;p&gt;Nature is still full of unknown chemistry with possible beneficial properties such as antibiotic ones. Genomics technologies measure the genetic content of organisms in which the blueprint of their chemical output is present. Metabolomics technologies generate tons of spectral data of actually produced molecules. However, the analysis of large-scale omics datasets is still very challenging, especially when several types need to be integrated. What can we predict from genomics? What can we understand from metabolomics? And how best to connect these two workflows when doing exploratory data analysis without drowning in the data?&lt;/p&gt;
&lt;h3 id=&quot;outline-of-the-workshop&quot;&gt;Outline of the workshop**&lt;/h3&gt;
&lt;p&gt;During this first workshop in a series of two, we aimed to bring together researchers interested in integrative omics analysis with various backgrounds in terms of their career stage, the technologies they are already familiar with, and the organisms they work on. Following a selection process, 30 participants were selected to come to Wageningen to learn about analyzing genomes and metabolomes, and to get an outlook towards the integration of the two. The aims of &lt;a href=&quot;https://www.wur.nl/en/research-results/chair-groups/plant-sciences/bioinformatics/teaching/nplinker_workshop.htm&quot;&gt;the workshop&lt;/a&gt; were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bring together Genome &amp;#x26; Metabolome Miners and learn the motivation and key characteristics of main genome and metabolome mining tools.&lt;/li&gt;
&lt;li&gt;Educate and train natural product researchers and other interested scientists in genome and metabolome mining.&lt;/li&gt;
&lt;li&gt;Establish together with the community what are the perceived main challenges in combining genomics and metabolomics, and the wishes for tools that address these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To stimulate networking amongst the participants and instructors, several measures were put in place: extended coffee and tea breaks, the opportunity to present a poster, and group discussions in changing compositions. We are grateful for the financial support from the eScience Center to make the workshop affordable for participants from across the globe through a travel reimbursement scheme and to enable the presence of 4 international instructors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;474&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-799c43e7.COzav1a3_Z1qBUcH.webp&quot; srcset=&quot;&quot;&gt;
All 30 participants from across the globe together with the instructors in front of the &lt;a href=&quot;https://www.wur.nl/en/location/omnia-2.htm&quot;&gt;Omnia building&lt;/a&gt; at the &lt;a href=&quot;https://www.wur.nl/en.htm&quot;&gt;Wageningen University &amp;#x26; Research&lt;/a&gt; campus.&lt;/p&gt;
&lt;h3 id=&quot;key-insights&quot;&gt;&lt;strong&gt;Key insights&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If there is one thing that became clear to me during the workshop, then it is this: multidisciplinary research requires open science and collaborative efforts to come to full fruition. During the workshop, one of the most heard perceived difficulties to do integrative omics analysis, is the (perceived) steep learning curve to get familiar with another type of omics data and the analysis workflow that comes with it. How to judge if this data is of good quality? How do you know if you used the right settings during the analysis? Hence, to do integrative omics analyses for natural product discovery, effective knowledge and skill transfer is needed. Here, having open access materials available is one part of the solution: researchers can use them to get familiar with the topic and the main things to consider for a successful project outcome, and teachers can use the materials to get inspired to teach this topic to students. We have also discussed the need for clear guidelines and instructions to run analysis software tools, and how the collaborative writing of documentation could be a solution to get to instructions that are clear(er) for a wide(r) audience. Finally, most tools, especially those relying on machine learning principles, perform best with increasing amounts of available data: all participants agreed that sharing is caring, and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-cunliang-geng/&quot;&gt;Cunliang Geng&lt;/a&gt;, research software engineer from the eScience Center, also provided an overview of how to make your data and software FAIR.&lt;/p&gt;
&lt;h3 id=&quot;practice-as-you-preach&quot;&gt;&lt;strong&gt;Practice as you preach&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;There was a lot of knowledge and skill exchange between participants themselves and participants and instructors that cannot be easily captured here. One tangible outcome for the workshop partipicants is the collaborative notes document that they collectively created and which is full of useful links and thoughts. Another tangible outcome of the workshop for the broader community is that the instructors all made as much as &lt;a href=&quot;https://doi.org/10.5281/zenodo.7801713&quot;&gt;possible the materials available under an open access licence&lt;/a&gt;! I hope that this initiative will help to further foster teaching the future generation of omics miners, to aid in setting up teaching materials for genome mining, metabolomics, and metabolome mining, and to promote discussions in between and bring together the fields of genome mining and metabolome mining.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;421&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-485272b5.DCcNMSI__2nFqGv.webp&quot; srcset=&quot;&quot;&gt;
With huge thanks to all the NPLinker eScience Workshop instructors who came from across the globe to Wageningen to teach the participants many facets of genome mining and metabolome mining.&lt;/p&gt;
&lt;h3 id=&quot;personal-reflection&quot;&gt;&lt;strong&gt;Personal reflection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Overall, I am glad that the participants generally liked the workshop format and content and that they look back at a great week in Wageningen. In particular, I was curious if the group discussions after lunch were appreciated, and based on the evaluation this was a good move, as it prevented the “after-lunch dip”, yet at the same time the participants could share their insights and frustrations. Furthermore, many of them were happy to realize that there are more scientists out there that struggle with integrating omics analyses and that have complementary skills and background to them. This was exactly the idea behind the community building! Also, we got some valuable feedback when organizing future workshops as this one: it is challenging to find the right balance for everyone between theoretical lectures and hands-on tutorials. Big thanks go out to all involved for their active participation, including the secretarial support in Wageningen. Finally, I look forward to organizing the second NPLinker eScience workshop that will be fully focused on how integrating genome and metabolome analysis can boost natural product discovery. The final day of the current workshop already demonstrated the currently ongoing developments within the NPLinker eScience project as well as by research groups around the world.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-a4afe6a8.C78hIVMS_1Ibc7m.webp&quot; srcset=&quot;&quot;&gt;
Community building during the workshop dinner&lt;/p&gt;</description><pubDate>Tue, 16 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A personal reflection on the first NPLinker eScience workshop for Natural Product Discovery&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://vdhooftcompmet.github.io/&quot;&gt;Justin van der Hooft&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post is written by Wageningen University &amp;#x26; Research Assistant Professor Justin van der Hooft who participates in the Netherlands eScience Center’s &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/open-escience-call-2021/&quot;&gt;&lt;em&gt;Open eScience Call 2021&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;. His project, “A community-supported workflow connecting microbial genes, and organisms to their molecular products”, aims to facilitate the finding of novel bioactive molecules from nature. It does so by enabling the integrated use of various omics data types.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-7878c100.C_Xe3aQK_2rb83I.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@vollkornapfel?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Adrian Lange&lt;/a&gt; on [Unsplash](&lt;a href=&quot;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&quot;&gt;https://unsplash.com/photos/Wk902ZLaA7M?utm_source=unsplash&amp;#x26;amp;utm_medium=referral&amp;#x26;amp;utm_content=creditCopy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Text)&lt;/p&gt;
&lt;h3 id=&quot;motivation-for-the-workshop&quot;&gt;Motivation for the workshop**&lt;/h3&gt;
&lt;p&gt;Nature is still full of unknown chemistry with possible beneficial properties such as antibiotic ones. Genomics technologies measure the genetic content of organisms in which the blueprint of their chemical output is present. Metabolomics technologies generate tons of spectral data of actually produced molecules. However, the analysis of large-scale omics datasets is still very challenging, especially when several types need to be integrated. What can we predict from genomics? What can we understand from metabolomics? And how best to connect these two workflows when doing exploratory data analysis without drowning in the data?&lt;/p&gt;
&lt;h3 id=&quot;outline-of-the-workshop&quot;&gt;Outline of the workshop**&lt;/h3&gt;
&lt;p&gt;During this first workshop in a series of two, we aimed to bring together researchers interested in integrative omics analysis with various backgrounds in terms of their career stage, the technologies they are already familiar with, and the organisms they work on. Following a selection process, 30 participants were selected to come to Wageningen to learn about analyzing genomes and metabolomes, and to get an outlook towards the integration of the two. The aims of &lt;a href=&quot;https://www.wur.nl/en/research-results/chair-groups/plant-sciences/bioinformatics/teaching/nplinker_workshop.htm&quot;&gt;the workshop&lt;/a&gt; were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bring together Genome &amp;#x26; Metabolome Miners and learn the motivation and key characteristics of main genome and metabolome mining tools.&lt;/li&gt;
&lt;li&gt;Educate and train natural product researchers and other interested scientists in genome and metabolome mining.&lt;/li&gt;
&lt;li&gt;Establish together with the community what are the perceived main challenges in combining genomics and metabolomics, and the wishes for tools that address these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To stimulate networking amongst the participants and instructors, several measures were put in place: extended coffee and tea breaks, the opportunity to present a poster, and group discussions in changing compositions. We are grateful for the financial support from the eScience Center to make the workshop affordable for participants from across the globe through a travel reimbursement scheme and to enable the presence of 4 international instructors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;474&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-799c43e7.COzav1a3_Z1qBUcH.webp&quot; srcset=&quot;&quot;&gt;
All 30 participants from across the globe together with the instructors in front of the &lt;a href=&quot;https://www.wur.nl/en/location/omnia-2.htm&quot;&gt;Omnia building&lt;/a&gt; at the &lt;a href=&quot;https://www.wur.nl/en.htm&quot;&gt;Wageningen University &amp;#x26; Research&lt;/a&gt; campus.&lt;/p&gt;
&lt;h3 id=&quot;key-insights&quot;&gt;&lt;strong&gt;Key insights&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If there is one thing that became clear to me during the workshop, then it is this: multidisciplinary research requires open science and collaborative efforts to come to full fruition. During the workshop, one of the most heard perceived difficulties to do integrative omics analysis, is the (perceived) steep learning curve to get familiar with another type of omics data and the analysis workflow that comes with it. How to judge if this data is of good quality? How do you know if you used the right settings during the analysis? Hence, to do integrative omics analyses for natural product discovery, effective knowledge and skill transfer is needed. Here, having open access materials available is one part of the solution: researchers can use them to get familiar with the topic and the main things to consider for a successful project outcome, and teachers can use the materials to get inspired to teach this topic to students. We have also discussed the need for clear guidelines and instructions to run analysis software tools, and how the collaborative writing of documentation could be a solution to get to instructions that are clear(er) for a wide(r) audience. Finally, most tools, especially those relying on machine learning principles, perform best with increasing amounts of available data: all participants agreed that sharing is caring, and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-cunliang-geng/&quot;&gt;Cunliang Geng&lt;/a&gt;, research software engineer from the eScience Center, also provided an overview of how to make your data and software FAIR.&lt;/p&gt;
&lt;h3 id=&quot;practice-as-you-preach&quot;&gt;&lt;strong&gt;Practice as you preach&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;There was a lot of knowledge and skill exchange between participants themselves and participants and instructors that cannot be easily captured here. One tangible outcome for the workshop partipicants is the collaborative notes document that they collectively created and which is full of useful links and thoughts. Another tangible outcome of the workshop for the broader community is that the instructors all made as much as &lt;a href=&quot;https://doi.org/10.5281/zenodo.7801713&quot;&gt;possible the materials available under an open access licence&lt;/a&gt;! I hope that this initiative will help to further foster teaching the future generation of omics miners, to aid in setting up teaching materials for genome mining, metabolomics, and metabolome mining, and to promote discussions in between and bring together the fields of genome mining and metabolome mining.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;421&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-485272b5.DCcNMSI__2nFqGv.webp&quot; srcset=&quot;&quot;&gt;
With huge thanks to all the NPLinker eScience Workshop instructors who came from across the globe to Wageningen to teach the participants many facets of genome mining and metabolome mining.&lt;/p&gt;
&lt;h3 id=&quot;personal-reflection&quot;&gt;&lt;strong&gt;Personal reflection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Overall, I am glad that the participants generally liked the workshop format and content and that they look back at a great week in Wageningen. In particular, I was curious if the group discussions after lunch were appreciated, and based on the evaluation this was a good move, as it prevented the “after-lunch dip”, yet at the same time the participants could share their insights and frustrations. Furthermore, many of them were happy to realize that there are more scientists out there that struggle with integrating omics analyses and that have complementary skills and background to them. This was exactly the idea behind the community building! Also, we got some valuable feedback when organizing future workshops as this one: it is challenging to find the right balance for everyone between theoretical lectures and hands-on tutorials. Big thanks go out to all involved for their active participation, including the secretarial support in Wageningen. Finally, I look forward to organizing the second NPLinker eScience workshop that will be fully focused on how integrating genome and metabolome analysis can boost natural product discovery. The final day of the current workshop already demonstrated the currently ongoing developments within the NPLinker eScience project as well as by research groups around the world.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Creating a Community by Integrating Expertise, Tools and Ideas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-a4afe6a8.C78hIVMS_1Ibc7m.webp&quot; srcset=&quot;&quot;&gt;
Community building during the workshop dinner&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/creating-a-community-by-integrating-expe-7878c100.C_Xe3aQK.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Molecular Simulations using Machine Learning, Part 3</title><link>https://blog.esciencecenter.nl/posts/2023-05-04---molecular-simulations-using-machine-learning-part-3</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-05-04---molecular-simulations-using-machine-learning-part-3</guid><description>&lt;p&gt;24&lt;/p&gt;
&lt;p&gt;In the first part of this series we looked at the physics of simulating molecules, and went from quantum mechanics to something that is more efficient to solve, namely density functional theory and molecular dynamics. These both required the introduction of an unknown potential. In the second part we looked at designing a machine learning model tailored to approximating this potential.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-202fe83c.z9dqxaIK_Z1mJNuo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@dkoi?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;D koi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this final part we will discuss what goes into training this model, in particular how to obtain the training data. And we will conclude with some caveats.&lt;/p&gt;
&lt;p&gt;It’s possible to read this without having read the previous parts, but I would recommend at least reading &lt;a href=&quot;https://blog.esciencecenter.nl/molecular-simulations-using-machine-learning-part-2-1d647acd242c&quot;&gt;part 2&lt;/a&gt;, and &lt;a href=&quot;https://medium.com/escience-center/molecular-simulations-using-machine-learning-part-1-e8624a82f680&quot;&gt;part 1&lt;/a&gt; only if you’re interested in the physical background.&lt;/p&gt;
&lt;p&gt;I hope that these considerations will also be useful for anyone thinking of applying machine learning to their own field, even if it is not related to molecular simulations.&lt;/p&gt;
&lt;h2 id=&quot;how-to-obtain-the-training-data&quot;&gt;How to obtain the training data&lt;/h2&gt;
&lt;p&gt;To be able to train the model, we need lots of examples of nuclei positions and the corresponding interatomic potential. To see how we can obtain this, we have to go back to the figure summarizing the first part:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;553&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-b6950ebc.D9WZcrba_sTNER.webp&quot; srcset=&quot;&quot;&gt;
Remember we decoupled the electrons from the nuclei, the electrons being described by Density Functional Theory (DFT), and the nuclei by molecular dynamics (MD). For MD we needed an interatomic potential, which captures the effect the electrons have on the nuclei. But since we do have a way to compute the electron density, namely through DFT, the obvious solution is to use DFT to compute the interatomic potential that we then use in MD, this is called ab-initio Molecular Dynamics (aiMD).&lt;/p&gt;
&lt;p&gt;The downside as we discussed was that this is very slow, which was the reason to try using machine learning in the first place. We can still use it to compute the training data though! Note that this does assume that we can do DFT, i.e. that we know a density functional that is accurate for the system we want to study.&lt;/p&gt;
&lt;p&gt;After designing the machine learning model to be specifically tailored for this application, and thus very data-efficient, the hope is that with relatively little training data we can train a model, that we can then use to do much more and bigger simulations. The hope then is that once the model is trained, it will be as accurate as ab-initio molecular dynamics, but as fast as molecular dynamics using a simple potential, combining the best of both worlds.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;481&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-9c38fba1.TbqBRSxe_7QUBX.webp&quot; srcset=&quot;&quot;&gt;
When it comes to generating the training data, there are several tradeoffs that must be carefully considered. We will discuss several of them here.&lt;/p&gt;
&lt;h3 id=&quot;system-size&quot;&gt;system size&lt;/h3&gt;
&lt;p&gt;Since computing the potential for the training data is so expensive, ideally we want to be able to train the model on a small system, and once trained use it to simulate a larger system.&lt;/p&gt;
&lt;p&gt;To be more concrete, we could take for example 10 water molecules, and for 10.000 different configurations of these 10 nuclei use DFT to compute the interatomic potential. That gives us the input and output pairs on which we can train the model. Once it is trained, we can use this model to simulate millions of water molecules for many more steps.&lt;/p&gt;
&lt;p&gt;The tradeoff here is that if we make the training system &lt;em&gt;too&lt;/em&gt; small, it will never be able to learn enough about the larger system. In an extreme case, if we take as the training system a single water molecule, the model wouldn’t see any interactions between two molecules during training.&lt;/p&gt;
&lt;p&gt;So we must choose a training system that is small enough to be able to use DFT to generate the data, yet large enough that it captures all the interactions present in the much larger system the model will be used on once trained. What this is will depend heavily on the system considered, and will be a matter of trial and error combined with chemical intuition.&lt;/p&gt;
&lt;h3 id=&quot;system-configurations&quot;&gt;system configurations&lt;/h3&gt;
&lt;p&gt;Another question is how to choose the inputs, i.e. the nuclei positions on which we compute the interatomic potential. One option is to just do an aiMD simulation and use all of the steps as inputs. This has the advantage that, with the exception of the initial steps, all of the configurations were obtained by following an MD trajectory, so we can expect that they are typical and we are likely to run into similar (but bigger) configurations once we use the model. So it’s very beneficial if the model performs well on these configurations.&lt;/p&gt;
&lt;p&gt;Ideally we want all the inputs to be independent from each other, this maximizes the added value of each additional sample. So the other extreme is to sample the nuclear configurations at random, then they will indeed be completely independent from each other. However, configurations sampled at random are likely not to be physically realistic. So instead of samples being irrelevant because they are very similar to other samples, now they are irrelevant because they won’t be encountered when the trained model is used.&lt;/p&gt;
&lt;p&gt;So there is a tradeoff between diversity and representativeness. A good tradeoff between these two extremes can be made by first doing an MD simulation using not DFT but a faster, less accurate potential. These configurations will be much more representative than random ones, but much faster to obtain than using aiMD the whole time. Then, to minimise the correlation between steps, we only take every say 100th step. Finally, because the potential we used was less accurate, only for the steps we picked do we recompute the potential using DFT.&lt;/p&gt;
&lt;p&gt;In addition it helps to run the training simulation at a higher temperature than the system you want to use the model on. This makes the system explore more of the configuration space, and prevents the model running into unknown territory during its use.¹&lt;/p&gt;
&lt;h3 id=&quot;quality-vs-quantity&quot;&gt;Quality vs quantity&lt;/h3&gt;
&lt;p&gt;A final consideration is between the quality and the quantity of the data. Since we compute everything from DFT, and within DFT there are several choices that can make it more accurate and slower or vice versa, choices must be made here too. There need to be enough samples for the model to be able to generalise to configurations it hasn’t seen, but it also needs to be done within our computational budget.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;271&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-aba560be._jrghfx3_2dWoe5.webp&quot; srcset=&quot;&quot;&gt;
Tradeoffs to be navigated in generating training data.&lt;/p&gt;
&lt;h3 id=&quot;many-more-considerations&quot;&gt;Many more considerations&lt;/h3&gt;
&lt;p&gt;There are tons of other things to consider, here I have focussed on some of the issues that are most particular to this application, rather than providing a full overview of deep learning. I have also focussed on the more conceptually interesting questions. There are lots of details though that can have a significant effect on the final performance, such as what activation function is used, or what optimizer². It is best to start with an existing method if possible, and if improvement is necessary experiment with varying these details and seeing what effect they have on the final performance.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot;&gt;Getting started&lt;/h3&gt;
&lt;p&gt;If you are a chemist and want to try this for yourself, a good place to start might be &lt;a href=&quot;https://github.com/mir-group/nequip&quot;&gt;nequip&lt;/a&gt;, &lt;a href=&quot;https://github.com/mir-group/allegro&quot;&gt;allegro&lt;/a&gt; or &lt;a href=&quot;https://github.com/deepmodeling/deepmd-kit&quot;&gt;DeepMD-Kit&lt;/a&gt;, these work smoothly with the molecular dynamics code LAMMPS. &lt;a href=&quot;https://github.com/atomistic-machine-learning/schnetpack&quot;&gt;SchNetPack&lt;/a&gt; works with python’s atomic simulation environment. They all implement different models, so it is a matter of figuring out which model works best for your use case and with which software you are most familiar.&lt;/p&gt;
&lt;p&gt;Unfortunately due to personal circumstances I didn’t have time to do any experiments myself, so I can’t recommend any particular one.&lt;/p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;
&lt;p&gt;After all this theory let’s look at one example from the &lt;a href=&quot;https://arxiv.org/abs/2204.05249&quot;&gt;Allegro&lt;/a&gt; paper. In the figure below a small system of Li_3 PO_4 is shown, consisting of 192 atoms. The training data the authors made consisted of 11,000 configurations selected randomly from a 50,000 step ab-initio MD simulation. To get a sense of the time scales involved, the time step in this case was 2 femtoseconds, where a femtosecond is 1/10⁶ nanoseconds. The model was trained on this for machine learning standards very small dataset.&lt;/p&gt;
&lt;p&gt;It then was able to simulate a much bigger version of the same system, consisting of 421,824 atoms, at a speed of half a nanosecond per day on a single GPU, or even 50,331,648 atoms at half that speed using 128 GPUs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;238&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-566c4cd9.DeeuxsRw_Zq5sxm.webp&quot; srcset=&quot;&quot;&gt;
Example taken from &lt;a href=&quot;https://arxiv.org/abs/2204.05249&quot;&gt;https://arxiv.org/abs/2204.05249&lt;/a&gt;.Assessing the accuracy of the model is a much more subtle question than say for a model that classifies whether an image is a cat or a dog. I will just explain one plot from the paper that is just one measure of the accuracy. What is shown on the right in the figure above is the radial distribution function. This is a measure of the probability of finding a pair of atoms at a given distance. The peaks in the graph reveal characteristic structures or patterns in the material, such as the most common atomic bonds or the preferred spacing between certain atom types The figure shows that Allegro managed to come very close to the accurate but slow ab-initio Molecular Dynamics, at least in this measure.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Deep learning can be used to model the potential energy between molecules, needed in molecular dynamics simulations. This is a rapidly evolving field, with multiple libraries under active development, and regular papers with further improvements in methodology. It is exciting to follow these developments, and the larger scale simulations they will enable. For a relatively recent review, see &lt;a href=&quot;https://www.nature.com/articles/s41563-020-0777-6&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;footnotes&quot;&gt;footnotes&lt;/h3&gt;
&lt;p&gt;1: Thanks to Simon Batzner for correspondence on these issues.&lt;/p&gt;
&lt;p&gt;2: In fact as I write this blog, the &lt;a href=&quot;https://arxiv.org/abs/2303.08169&quot;&gt;latest innovation&lt;/a&gt; is exactly a new optimizer.&lt;/p&gt;</description><pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;24&lt;/p&gt;
&lt;p&gt;In the first part of this series we looked at the physics of simulating molecules, and went from quantum mechanics to something that is more efficient to solve, namely density functional theory and molecular dynamics. These both required the introduction of an unknown potential. In the second part we looked at designing a machine learning model tailored to approximating this potential.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-202fe83c.z9dqxaIK_Z1mJNuo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@dkoi?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;D koi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this final part we will discuss what goes into training this model, in particular how to obtain the training data. And we will conclude with some caveats.&lt;/p&gt;
&lt;p&gt;It’s possible to read this without having read the previous parts, but I would recommend at least reading &lt;a href=&quot;https://blog.esciencecenter.nl/molecular-simulations-using-machine-learning-part-2-1d647acd242c&quot;&gt;part 2&lt;/a&gt;, and &lt;a href=&quot;https://medium.com/escience-center/molecular-simulations-using-machine-learning-part-1-e8624a82f680&quot;&gt;part 1&lt;/a&gt; only if you’re interested in the physical background.&lt;/p&gt;
&lt;p&gt;I hope that these considerations will also be useful for anyone thinking of applying machine learning to their own field, even if it is not related to molecular simulations.&lt;/p&gt;
&lt;h2 id=&quot;how-to-obtain-the-training-data&quot;&gt;How to obtain the training data&lt;/h2&gt;
&lt;p&gt;To be able to train the model, we need lots of examples of nuclei positions and the corresponding interatomic potential. To see how we can obtain this, we have to go back to the figure summarizing the first part:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;553&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-b6950ebc.D9WZcrba_sTNER.webp&quot; srcset=&quot;&quot;&gt;
Remember we decoupled the electrons from the nuclei, the electrons being described by Density Functional Theory (DFT), and the nuclei by molecular dynamics (MD). For MD we needed an interatomic potential, which captures the effect the electrons have on the nuclei. But since we do have a way to compute the electron density, namely through DFT, the obvious solution is to use DFT to compute the interatomic potential that we then use in MD, this is called ab-initio Molecular Dynamics (aiMD).&lt;/p&gt;
&lt;p&gt;The downside as we discussed was that this is very slow, which was the reason to try using machine learning in the first place. We can still use it to compute the training data though! Note that this does assume that we can do DFT, i.e. that we know a density functional that is accurate for the system we want to study.&lt;/p&gt;
&lt;p&gt;After designing the machine learning model to be specifically tailored for this application, and thus very data-efficient, the hope is that with relatively little training data we can train a model, that we can then use to do much more and bigger simulations. The hope then is that once the model is trained, it will be as accurate as ab-initio molecular dynamics, but as fast as molecular dynamics using a simple potential, combining the best of both worlds.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;481&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-9c38fba1.TbqBRSxe_7QUBX.webp&quot; srcset=&quot;&quot;&gt;
When it comes to generating the training data, there are several tradeoffs that must be carefully considered. We will discuss several of them here.&lt;/p&gt;
&lt;h3 id=&quot;system-size&quot;&gt;system size&lt;/h3&gt;
&lt;p&gt;Since computing the potential for the training data is so expensive, ideally we want to be able to train the model on a small system, and once trained use it to simulate a larger system.&lt;/p&gt;
&lt;p&gt;To be more concrete, we could take for example 10 water molecules, and for 10.000 different configurations of these 10 nuclei use DFT to compute the interatomic potential. That gives us the input and output pairs on which we can train the model. Once it is trained, we can use this model to simulate millions of water molecules for many more steps.&lt;/p&gt;
&lt;p&gt;The tradeoff here is that if we make the training system &lt;em&gt;too&lt;/em&gt; small, it will never be able to learn enough about the larger system. In an extreme case, if we take as the training system a single water molecule, the model wouldn’t see any interactions between two molecules during training.&lt;/p&gt;
&lt;p&gt;So we must choose a training system that is small enough to be able to use DFT to generate the data, yet large enough that it captures all the interactions present in the much larger system the model will be used on once trained. What this is will depend heavily on the system considered, and will be a matter of trial and error combined with chemical intuition.&lt;/p&gt;
&lt;h3 id=&quot;system-configurations&quot;&gt;system configurations&lt;/h3&gt;
&lt;p&gt;Another question is how to choose the inputs, i.e. the nuclei positions on which we compute the interatomic potential. One option is to just do an aiMD simulation and use all of the steps as inputs. This has the advantage that, with the exception of the initial steps, all of the configurations were obtained by following an MD trajectory, so we can expect that they are typical and we are likely to run into similar (but bigger) configurations once we use the model. So it’s very beneficial if the model performs well on these configurations.&lt;/p&gt;
&lt;p&gt;Ideally we want all the inputs to be independent from each other, this maximizes the added value of each additional sample. So the other extreme is to sample the nuclear configurations at random, then they will indeed be completely independent from each other. However, configurations sampled at random are likely not to be physically realistic. So instead of samples being irrelevant because they are very similar to other samples, now they are irrelevant because they won’t be encountered when the trained model is used.&lt;/p&gt;
&lt;p&gt;So there is a tradeoff between diversity and representativeness. A good tradeoff between these two extremes can be made by first doing an MD simulation using not DFT but a faster, less accurate potential. These configurations will be much more representative than random ones, but much faster to obtain than using aiMD the whole time. Then, to minimise the correlation between steps, we only take every say 100th step. Finally, because the potential we used was less accurate, only for the steps we picked do we recompute the potential using DFT.&lt;/p&gt;
&lt;p&gt;In addition it helps to run the training simulation at a higher temperature than the system you want to use the model on. This makes the system explore more of the configuration space, and prevents the model running into unknown territory during its use.¹&lt;/p&gt;
&lt;h3 id=&quot;quality-vs-quantity&quot;&gt;Quality vs quantity&lt;/h3&gt;
&lt;p&gt;A final consideration is between the quality and the quantity of the data. Since we compute everything from DFT, and within DFT there are several choices that can make it more accurate and slower or vice versa, choices must be made here too. There need to be enough samples for the model to be able to generalise to configurations it hasn’t seen, but it also needs to be done within our computational budget.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;271&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-aba560be._jrghfx3_2dWoe5.webp&quot; srcset=&quot;&quot;&gt;
Tradeoffs to be navigated in generating training data.&lt;/p&gt;
&lt;h3 id=&quot;many-more-considerations&quot;&gt;Many more considerations&lt;/h3&gt;
&lt;p&gt;There are tons of other things to consider, here I have focussed on some of the issues that are most particular to this application, rather than providing a full overview of deep learning. I have also focussed on the more conceptually interesting questions. There are lots of details though that can have a significant effect on the final performance, such as what activation function is used, or what optimizer². It is best to start with an existing method if possible, and if improvement is necessary experiment with varying these details and seeing what effect they have on the final performance.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot;&gt;Getting started&lt;/h3&gt;
&lt;p&gt;If you are a chemist and want to try this for yourself, a good place to start might be &lt;a href=&quot;https://github.com/mir-group/nequip&quot;&gt;nequip&lt;/a&gt;, &lt;a href=&quot;https://github.com/mir-group/allegro&quot;&gt;allegro&lt;/a&gt; or &lt;a href=&quot;https://github.com/deepmodeling/deepmd-kit&quot;&gt;DeepMD-Kit&lt;/a&gt;, these work smoothly with the molecular dynamics code LAMMPS. &lt;a href=&quot;https://github.com/atomistic-machine-learning/schnetpack&quot;&gt;SchNetPack&lt;/a&gt; works with python’s atomic simulation environment. They all implement different models, so it is a matter of figuring out which model works best for your use case and with which software you are most familiar.&lt;/p&gt;
&lt;p&gt;Unfortunately due to personal circumstances I didn’t have time to do any experiments myself, so I can’t recommend any particular one.&lt;/p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;
&lt;p&gt;After all this theory let’s look at one example from the &lt;a href=&quot;https://arxiv.org/abs/2204.05249&quot;&gt;Allegro&lt;/a&gt; paper. In the figure below a small system of Li_3 PO_4 is shown, consisting of 192 atoms. The training data the authors made consisted of 11,000 configurations selected randomly from a 50,000 step ab-initio MD simulation. To get a sense of the time scales involved, the time step in this case was 2 femtoseconds, where a femtosecond is 1/10⁶ nanoseconds. The model was trained on this for machine learning standards very small dataset.&lt;/p&gt;
&lt;p&gt;It then was able to simulate a much bigger version of the same system, consisting of 421,824 atoms, at a speed of half a nanosecond per day on a single GPU, or even 50,331,648 atoms at half that speed using 128 GPUs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Molecular Simulations using Machine Learning, Part 3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;238&quot; src=&quot;https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-566c4cd9.DeeuxsRw_Zq5sxm.webp&quot; srcset=&quot;&quot;&gt;
Example taken from &lt;a href=&quot;https://arxiv.org/abs/2204.05249&quot;&gt;https://arxiv.org/abs/2204.05249&lt;/a&gt;.Assessing the accuracy of the model is a much more subtle question than say for a model that classifies whether an image is a cat or a dog. I will just explain one plot from the paper that is just one measure of the accuracy. What is shown on the right in the figure above is the radial distribution function. This is a measure of the probability of finding a pair of atoms at a given distance. The peaks in the graph reveal characteristic structures or patterns in the material, such as the most common atomic bonds or the preferred spacing between certain atom types The figure shows that Allegro managed to come very close to the accurate but slow ab-initio Molecular Dynamics, at least in this measure.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Deep learning can be used to model the potential energy between molecules, needed in molecular dynamics simulations. This is a rapidly evolving field, with multiple libraries under active development, and regular papers with further improvements in methodology. It is exciting to follow these developments, and the larger scale simulations they will enable. For a relatively recent review, see &lt;a href=&quot;https://www.nature.com/articles/s41563-020-0777-6&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;footnotes&quot;&gt;footnotes&lt;/h3&gt;
&lt;p&gt;1: Thanks to Simon Batzner for correspondence on these issues.&lt;/p&gt;
&lt;p&gt;2: In fact as I write this blog, the &lt;a href=&quot;https://arxiv.org/abs/2303.08169&quot;&gt;latest innovation&lt;/a&gt; is exactly a new optimizer.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/molecular-simulations-using-machine-lear-202fe83c.z9dqxaIK.jpg" medium="image"/><author>Aron</author></item><item><title>Researchers are not born engineers — why are they expected to know how to code?</title><link>https://blog.esciencecenter.nl/posts/2023-04-20---researchers-are-not-born-engineers-why-are-they-expected-to-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-04-20---researchers-are-not-born-engineers-why-are-they-expected-to-</guid><description>&lt;p&gt;I refuse to be too hard on my past self. It’s understandable that researchers, who juggle multiple projects and deadlines, do not have the time, energy or resources to become coding experts. But research is increasingly reliant on technology, so it’s important that researchers have access to the support and education they need to develop and use high-quality code. Learning good coding practices (or having access to those who know them) not only improves the reproducibility and reliability of research, but it adds to the fun of coding, saves time and prevents future headaches.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Researchers are not born engineers — why are they expected to know how to code?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/researchers-are-not-born-engineers-why-a-448a811f.E8sRjKrA_Z29SuPn.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@clemhlrdt?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Clément Hélardot&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When I sat in on a &lt;a href=&quot;https://www.esciencecenter.nl/event/best-practices-in-research-software-development-coderefinery-3/&quot;&gt;course on good coding practices&lt;/a&gt; at the eScience Center two years ago, I first realized why my own code had been bad: I did not know about good practices. I learned how to properly &lt;a href=&quot;https://coderefinery.github.io/git-collaborative/&quot;&gt;collaborate on projects via GitHub&lt;/a&gt;, which was eye-opening. The fact that you could use branches to work together on solutions to different problems was completely novel to me. The fact that you could write tests to make sure you would realize if part of your code failed was mind-blowing. Also, making my code modular, so that scripts would not contain upwards of 2000 lines, made the entire project so much easier to read and understand. Writing proper help functions was something I used to feel was not that important, because I never wanted anyone to look at my code. Now, documentation is something I strongly believe in.&lt;/p&gt;
&lt;p&gt;I am currently farther away from being a researcher in my daily job than ever, but in this job I did write an R package, together with my eScience Center colleague &lt;a href=&quot;https://github.com/bvreede&quot;&gt;Barbara Vreede&lt;/a&gt;. Barbara is an amazing research software engineer who guided me through the process. The package is called &lt;a href=&quot;https://github.com/esciencecenter-digital-skills/training-infrastructure&quot;&gt;traininginfrastructure*&lt;/a&gt;and creates all necessary communication documents and folders for the workshops we run at the eScience Center. I’m very happy to say the package works and is used by my colleagues. It saves engineers who teach time on repetitive administrative duties and prevents mistakes in creating communication (no more copy-pasting emails with typos).&lt;/p&gt;
&lt;p&gt;By no means did I become a perfect research software engineer. But I realized how much I had learned when recently, a researcher contacted me to ask if she could use the same analysis that I had used during a project for my PhD. I reluctantly gave her access to the old private GitHub repo with my project’s scripts and had to dig some non-version controlled other scripts out of my email inbox. Being confronted with that code was sobering. One day, I may try to clean it up so that they are usable for more researchers in the future. But it made one wider point very clear to me: my work at the eScience Center really serves a purpose. It can bring people like me, researchers who write scripts that work, but that they hate, to write code that they can be proud of and freely share with those that may need it. It can save all of us time and effort. And what I learned here really did not take that much time: a 1-week course and some quality guidance in building a fairly simple R package.&lt;/p&gt;
&lt;p&gt;Some of those who collaborate with us on projects at the eScience Center find it difficult to accept our engineers’ wishes that they use the same practices we do in research software projects. I now understand that using good practices is the only way to build quality tools for research. If you are ever in a situation where someone forces you, you may end up gratefully learning about (and putting into practice!) version control, collaborative software engineering, testing, and documentation. It can be painful in the beginning, but it will make your and others’ life so much easier in the future, and your software a worthy research output on your CV.&lt;/p&gt;
&lt;p&gt;If you want to learn how to write quality code for research, check out &lt;a href=&quot;https://www.esciencecenter.nl/events/?f=workshops&quot;&gt;our free workshops&lt;/a&gt;! You can also apply for &lt;a href=&quot;https://www.esciencecenter.nl/calls-for-proposals/&quot;&gt;our calls&lt;/a&gt;, or sign up to our &lt;a href=&quot;http://eepurl.com/dtjzwP&quot;&gt;newsletter&lt;/a&gt; to stay tuned.&lt;/p&gt;</description><pubDate>Thu, 20 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I refuse to be too hard on my past self. It’s understandable that researchers, who juggle multiple projects and deadlines, do not have the time, energy or resources to become coding experts. But research is increasingly reliant on technology, so it’s important that researchers have access to the support and education they need to develop and use high-quality code. Learning good coding practices (or having access to those who know them) not only improves the reproducibility and reliability of research, but it adds to the fun of coding, saves time and prevents future headaches.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Researchers are not born engineers — why are they expected to know how to code?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/researchers-are-not-born-engineers-why-a-448a811f.E8sRjKrA_Z29SuPn.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@clemhlrdt?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Clément Hélardot&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When I sat in on a &lt;a href=&quot;https://www.esciencecenter.nl/event/best-practices-in-research-software-development-coderefinery-3/&quot;&gt;course on good coding practices&lt;/a&gt; at the eScience Center two years ago, I first realized why my own code had been bad: I did not know about good practices. I learned how to properly &lt;a href=&quot;https://coderefinery.github.io/git-collaborative/&quot;&gt;collaborate on projects via GitHub&lt;/a&gt;, which was eye-opening. The fact that you could use branches to work together on solutions to different problems was completely novel to me. The fact that you could write tests to make sure you would realize if part of your code failed was mind-blowing. Also, making my code modular, so that scripts would not contain upwards of 2000 lines, made the entire project so much easier to read and understand. Writing proper help functions was something I used to feel was not that important, because I never wanted anyone to look at my code. Now, documentation is something I strongly believe in.&lt;/p&gt;
&lt;p&gt;I am currently farther away from being a researcher in my daily job than ever, but in this job I did write an R package, together with my eScience Center colleague &lt;a href=&quot;https://github.com/bvreede&quot;&gt;Barbara Vreede&lt;/a&gt;. Barbara is an amazing research software engineer who guided me through the process. The package is called &lt;a href=&quot;https://github.com/esciencecenter-digital-skills/training-infrastructure&quot;&gt;traininginfrastructure*&lt;/a&gt;and creates all necessary communication documents and folders for the workshops we run at the eScience Center. I’m very happy to say the package works and is used by my colleagues. It saves engineers who teach time on repetitive administrative duties and prevents mistakes in creating communication (no more copy-pasting emails with typos).&lt;/p&gt;
&lt;p&gt;By no means did I become a perfect research software engineer. But I realized how much I had learned when recently, a researcher contacted me to ask if she could use the same analysis that I had used during a project for my PhD. I reluctantly gave her access to the old private GitHub repo with my project’s scripts and had to dig some non-version controlled other scripts out of my email inbox. Being confronted with that code was sobering. One day, I may try to clean it up so that they are usable for more researchers in the future. But it made one wider point very clear to me: my work at the eScience Center really serves a purpose. It can bring people like me, researchers who write scripts that work, but that they hate, to write code that they can be proud of and freely share with those that may need it. It can save all of us time and effort. And what I learned here really did not take that much time: a 1-week course and some quality guidance in building a fairly simple R package.&lt;/p&gt;
&lt;p&gt;Some of those who collaborate with us on projects at the eScience Center find it difficult to accept our engineers’ wishes that they use the same practices we do in research software projects. I now understand that using good practices is the only way to build quality tools for research. If you are ever in a situation where someone forces you, you may end up gratefully learning about (and putting into practice!) version control, collaborative software engineering, testing, and documentation. It can be painful in the beginning, but it will make your and others’ life so much easier in the future, and your software a worthy research output on your CV.&lt;/p&gt;
&lt;p&gt;If you want to learn how to write quality code for research, check out &lt;a href=&quot;https://www.esciencecenter.nl/events/?f=workshops&quot;&gt;our free workshops&lt;/a&gt;! You can also apply for &lt;a href=&quot;https://www.esciencecenter.nl/calls-for-proposals/&quot;&gt;our calls&lt;/a&gt;, or sign up to our &lt;a href=&quot;http://eepurl.com/dtjzwP&quot;&gt;newsletter&lt;/a&gt; to stay tuned.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/researchers-are-not-born-engineers-why-a-448a811f.E8sRjKrA.jpg" medium="image"/><author>Lieke de Boer</author></item><item><title>Molecular Simulations using Machine Learning, Part 2</title><link>https://blog.esciencecenter.nl/posts/2023-04-13---molecular-simulations-using-machine-learning-part-2</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-04-13---molecular-simulations-using-machine-learning-part-2</guid><description>&lt;p&gt;&lt;em&gt;In this post, I will walk through the process of designing a model used in molecular simulations, from essential to state of the art. This is the second part of a series on using machine learning for molecular simulations. It is relatively self-contained if you haven’t read&lt;/em&gt; &lt;a href=&quot;https://blog.esciencecenter.nl/molecular-simulations-using-machine-learning-part-1-e8624a82f680?sk=8c9902b39588261826ab77e3e24f8766&quot;&gt;&lt;em&gt;the first part&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;875&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_GVOnfCp1wScCos1_-b1c8ae9b.BJjMZttk_Z1wrR14.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by BoliviaInteligente on Unsplash&lt;/p&gt;
&lt;p&gt;We will design a model that approximates a potential used in molecular simulations. We will start from the simplest possible model, and reason our way step by step towards the essentials of the current state of the art models. This at the same time roughly follows the historical development of these models, although we will not attempt to be precise in this regard.&lt;/p&gt;
&lt;p&gt;The principles we use to arrive at a good model are quite general. Although they will lead to different models in different applications, I hope this can be helpful for scientists in different fields thinking about applying machine learning to their own field.&lt;/p&gt;
&lt;h3 id=&quot;quick-recap&quot;&gt;Quick recap&lt;/h3&gt;
&lt;p&gt;The figure below summarizes part 1 in a bit more detail. We saw how quantum mechanics was simplified into Density Functional Theory describing electrons, and Molecular Dynamics describing the atomic nuclei. The clouds in the figure indicate a-priori unknown ingredients that arose from these approximations: the density functional and the interatomic potential.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1131&quot; height=&quot;894&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zwvn0X4z6_mG4zyQ4acULw-036d0626.CR6qfiv9_5UqRY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We will focus on the interatomic potential: a single function depending on the positions of all the nuclei. The same principles that we use to derive a model for this also apply to the density functional, but the details will be different, because its inputs are different.&lt;/p&gt;
&lt;h2 id=&quot;simplest-machine-learning-model&quot;&gt;Simplest machine learning model&lt;/h2&gt;
&lt;p&gt;When designing a machine learning model, it is useful to start from the very basic question: what should go into it, and what should come out.&lt;/p&gt;
&lt;p&gt;Well, we want the model to compute a potential, which is a single number, depending on the coordinates of all nuclei. So if we have N nuclei in 3-dimensional space, the model should take 3N numbers and turn them into a single number.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;749&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jCcxDmDEo7BTHXhrdDLR_g-832dfe19.Dc0wIY9X_Z2dnAc6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The simplest machine learning model: a linear model.&lt;/p&gt;
&lt;p&gt;The simplest possible machine learning model that meets this requirement would be multiplication by a 1 by 3N matrix W: M(x) = W x. This would multiply every one of the 3N inputs with a weight, and sum them all up. These weights are the trainable parameters. These are initially set to random values, and updated during training by correcting the errors the model makes. That part will remain the same throughout.&lt;/p&gt;
&lt;p&gt;This model has many undesirable properties, the most problematic one being that it is way too simple. A more precise way of saying this is that it is linear. This means that if we multiply all of the inputs by 2, the output will be multiplied by 2 as well. Or if we add 3 to say input x₁, the output will be the original output plus 3 w₁, where w₁ is the corresponding weight. In reality of course the effect of this change of one coordinate on the potential depends in a complicated way on its relationships to the coordinates of other particles. This model will never be able to capture that, no matter how much data you throw at it.&lt;/p&gt;
&lt;h2 id=&quot;deep-learning&quot;&gt;Deep learning&lt;/h2&gt;
&lt;p&gt;Removing this restriction takes us from machine learning to deep learning. The simplest neural network is basically a sequence of the simpler models from above, intermingled with nonlinear functions called activation functions. (Without these, the end result would still be linear!)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;657&quot; height=&quot;491&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_MNG8au1e0VGNe723I3Fv1A-338974de.DjMYcLzq_Z1SL8p9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The simplest deep learning model: a fully connected neural network.&lt;/p&gt;
&lt;p&gt;The simplest example of this class of models has one hidden layer: it takes the 3N inputs to say 100 numbers by a matrix multiplication, and applicaties an activation function to each one separately. Then through a second matrix multiplication it takes those to the one number we need as an output.&lt;/p&gt;
&lt;p&gt;There are many different activation functions, conceptually the only important thing is that they are nonlinear. A simple often used example is the ReLU, which is 0 if its input is negative, and otherwise just passes on the input unchanged.&lt;/p&gt;
&lt;p&gt;The effect of adding just one of these hidden layers is profound. In a sense, this immediately fixes the problem with the previous model. That is, this model can approximate anything now, given enough parameters. This statement is known as the &lt;em&gt;universal approximation theorem&lt;/em&gt;. However, that is quite a theoretical result. It doesn’t say how large the hidden layer should be, how much data is necessary, or even if it’s possible to find the right parameters through training at all, only that they exist.&lt;/p&gt;
&lt;p&gt;To address all of these other concerns, we need to specialise the model further to our particular application. In other words, we want our model to not only take into account just the &lt;em&gt;size&lt;/em&gt; of the in- and outputs, but also its &lt;em&gt;structure&lt;/em&gt;. As a first example, although the model above has the correct number of 3N inputs, it is not aware at all that actually these have the structure of N triplets of coordinates.&lt;/p&gt;
&lt;p&gt;To elaborate on this and make it more precise, we’ll look at the concept of equivariance. For a book and lectures on exploiting the structure of our data that is much more detailed, but also quite technical, see &lt;a href=&quot;https://geometricdeeplearning.com/&quot;&gt;https://geometricdeeplearning.com/&lt;/a&gt;, and &lt;a href=&quot;https://www.nature.com/articles/s42256-021-00418-8&quot;&gt;this paper&lt;/a&gt; for applications specifically to molecules.&lt;/p&gt;
&lt;h3 id=&quot;equivariance&quot;&gt;Equivariance&lt;/h3&gt;
&lt;p&gt;Equivariance means that if we &lt;em&gt;first&lt;/em&gt; transform the input and &lt;em&gt;then&lt;/em&gt; apply the model to it, we get the same result as when we &lt;em&gt;first&lt;/em&gt; apply the model, and &lt;em&gt;then&lt;/em&gt; apply a similar transformation to the output. It is a property that a model can have for some transformations but not for others. For example if this is true for a model M when the transformations are rotations, we say that M is rotation equivariant or equivariant with respect to rotations, illustrated in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;480&quot; height=&quot;420&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ez5PyIJRW8XGHQdlBjxxkQ-a83a4fc2.CH-zISRo_1gF3wY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Example of equivariance of a hypothetical model M that just detects edges. No matter if we first apply the model and then rotate the result, or first rotate the input and then apply the model, we end up with the same result.&lt;/p&gt;
&lt;p&gt;Note that the definition refers to a &lt;em&gt;similar&lt;/em&gt; transformation on the output, not necessarily exactly the same as we applied to the input. In fact, usually the output of the model will be of a different shape than the input, so we cannot even do the exact same transformation. The important part is that we know a-priori what the transformation on the output is, and it depends only on what transformation we did on the input.&lt;/p&gt;
&lt;p&gt;A special case of equivariance is &lt;em&gt;invariance&lt;/em&gt;, which is when this similar transformation is actually the identity. In other words, if we transform the input, the output will remain unchanged. For a simple example of this, if the hypothetical model in the image above were just a classifier saying whether the image is a cat or a dog, we’d expect it to be invariant: for both inputs on the left of the image, the outputs on the right should be “cat”.&lt;/p&gt;
&lt;p&gt;Requiring the model to be equivariant with respect to some transformation imposes some constraints on it, it decreases the freedom in the model, or the number of parameters. So as long as the equivariances we impose are also satisfied by the true solution we are trying to approximate with the model, it makes it more data efficient and easier to train. If we didn’t impose equivariance, the model could potentially have learned it from the data, but that would require more data, more time and more parameters. If we know this property beforehand, clearly it pays off to enforce it, preventing the model from the get go to make mistakes of this kind.&lt;/p&gt;
&lt;p&gt;There are many different transformations that the true interatomic potential must be equivariant to. We will discuss these one by one and use them to refine our model.&lt;/p&gt;
&lt;h3 id=&quot;permutations&quot;&gt;Permutations&lt;/h3&gt;
&lt;p&gt;In turning the positions of all nuclei into a 3N-dimensional input vector, we had to implicitly decide an order: which particle is the first particle, which is the second, etc. Clearly this is just a choice of labelling; if we pick a different order for the exact same configuration of particles, the potential shouldn’t change. So we want our model to be &lt;em&gt;invariant&lt;/em&gt; with respect to permutations.&lt;/p&gt;
&lt;p&gt;Currently it is not, it has no idea that the output should be the same, and so it would have to learn that by seeing lots of examples of identical configurations that are labelled differently, but with the same training label. Clearly this is a huge waste of time, and we want to avoid this.&lt;/p&gt;
&lt;p&gt;There are several common functions that do not depend on the order of their arguments, i.e. that are permutation invariant, such as the sum, or the mean, or the maximum. We will just take the sum, as it preserves more information than the maximum. So the very simplest permutation-invariant model would just take all of the nuclei’s positions and sum them. (Actually this would still leave us with 3 coordinates, so we’d need a 1 by 3 matrix at the end to turn it into a single number.)&lt;/p&gt;
&lt;p&gt;This is of course again much too simple, in fact even more so than what we started with. We can improve the situation while still taking permutations into account by having only the &lt;em&gt;last&lt;/em&gt; layer be invariant, and adding &lt;em&gt;equivariant&lt;/em&gt; layers in between.&lt;/p&gt;
&lt;p&gt;Any function that does exactly the same to every nucleus will be equivariant with respect to permutations: if we reorder the inputs, the outputs will be the same as the original, except that they are also reordered in exactly the same way. For this function we can use what we ended up with in the previous section: a fully connected neural network. So that takes a nucleus’s 3 coordinates, and does several matrix multiplications and activation functions on it to end up with a different amount of numbers for each atom, that we can choose.&lt;/p&gt;
&lt;p&gt;Note that if the intermediate layers were &lt;em&gt;not&lt;/em&gt; equivariant, there would be no way to guarantee invariance at the final layer. Furthermore, it also already makes the model more data efficient, as one training sample automatically teaches it about all the different orderings of that same sample.&lt;/p&gt;
&lt;p&gt;Another important consequence of this is that, unlike the fully connected level, we now have a model that works regardless of how many nuclei there are. This is great, because it will allow us to train the model on a small system, and then use it on a larger system.&lt;/p&gt;
&lt;h3 id=&quot;locality-graph-neural-networks&quot;&gt;Locality, graph neural networks&lt;/h3&gt;
&lt;p&gt;The above modification does impose permutation invariance, but it was still too restrictive. It treats all the nuclei independently, finally just summing “individual potentials” to obtain the total potential. This is not realistic, we expect the potential to depend also on the distance &lt;em&gt;between&lt;/em&gt; nuclei, something that this model cannot learn.&lt;/p&gt;
&lt;p&gt;We can relax this restriction and at the same time incorporate another physical prior by adding more structure to the input.&lt;/p&gt;
&lt;p&gt;The physical principle is locality: what happens at some point x only depends on things close to x. More concretely in this case, the Coulomb potential between two particles at a distance r decreases as 1/r. This means that the interaction between two nuclei that are very far from each other doesn’t have any significant contribution to the potential.&lt;/p&gt;
&lt;p&gt;So for nuclei closer to each other than some cutoff distance r_c, we want to take their interaction into account, and we can connect them by an edge. Those that are further away are not connected by an edge. This way we turn the original point cloud input into a graph.&lt;/p&gt;
&lt;p&gt;We then extend the operation that previously did the same to all nuclei, to allow it to depend on an atom’s neighbours as well. However, the number of neighbours will be different for different nuclei, and if we allow this to make the output shapes of each atom different things will quickly grow out of hand. So we need a way to combine the neighbours in such a way as to keep the shape independent of the number of neighbours. Furthermore we again have the issue of permutation invariance, now at a smaller local scale. The solution to both problems is the same: we sum over the features of the neighbours.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;692&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_6pHDwX0OUPtuHWqbD0vUJw-f0843c46.d1xFbZ-o_Z1ORWx7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Illustration of message passing in a graph neural network. An atom c receives “messages” from its neighbours n and updates its state using those. The neighbours at the same time do the same. Multiple steps of this allow the message to propagate further.&lt;/p&gt;
&lt;p&gt;This is another permutation equivariant operation, now on graph inputs. It is called message passing, because it can be thought of as all of an atom’s neighbours passing messages to the central atom, who adds them all up. Doing this multiple times for all nuclei increases the region to which an atom is sensitive, because in the second step it can indirectly receive messages from its neighbours’ neighbours.&lt;/p&gt;
&lt;p&gt;At the end we have to sum over all nuclei again to obtain something invariant to permutations. These types of models are called Graph Neural Networks (GNNs).&lt;/p&gt;
&lt;h3 id=&quot;spatial-invariances&quot;&gt;Spatial invariances&lt;/h3&gt;
&lt;p&gt;While permutation invariance was more about the way we describe the system, how we label the nuclei, the remaining ones are actual spatial transformations: translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;If we move (“translate”) all nuclei in the same direction by the same amount, the interatomic potential doesn’t change. That is, whether we perform an experiment in Amsterdam, or we perform the exact same experiment in New York, the outcome should be the same. And the same holds for rotations and reflections. (If there were any external influence like gravity this would be different, but that is insignificant at the atomic scale.)&lt;/p&gt;
&lt;p&gt;As the model is now, it doesn’t know any of this. Building this in to the model makes it a lot more data efficient. From just one training simulation it would learn automatically about all its translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;The simplest way to enforce this is to only give the model inputs that are themselves invariant to these transformations. Clearly, if the inputs are not affected, the output is also not affected.&lt;/p&gt;
&lt;p&gt;That means we cannot have an atom’s position as an input by itself, as clearly that is not invariant under any of the transformations. But since we now have a graph, we can focus on &lt;em&gt;pairs&lt;/em&gt; of nuclei, and take the difference of their positions as an input. That is already invariant with respect to translations: if we add the same vector to both positions, it will cancel out in the difference. It is not yet invariant with respect to rotations or reflections, but if we reduce it further to just the absolute value of the difference, it is.&lt;/p&gt;
&lt;p&gt;That does the job, but it is again quite restrictive. Note the parallel here with the permutations we discussed previously: the simplest is to make everything invariant from the start, but it will turn out to be unnecessarily restrictive.&lt;/p&gt;
&lt;p&gt;For an example of something that is missed in this approach, consider a central atom with two two of its neighbours. The vectors pointing from the central atom to those two neighbours make up a certain angle to each other. If you think about it, this angle is also invariant with respect to all of the transformations. And it might well be a useful feature that has an effect on the potential that we want the model to represent. But there is no way to reconstruct this angle just from the absolute value of the differences in positions. Had we not thrown away that much information so early on, we &lt;em&gt;would&lt;/em&gt; be able to recover this angle: it’s related to the inner product between the two vectors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;554&quot; height=&quot;437&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_a_4d0GaMmdDN6ZJ8s81Rqg-6d8dab71.BVg6UK_y_Z2daGhj.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The angle φ is invariant to translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;We could of course add these angles to the input “by hand” and stick to imposing invariance from the start, and there are models that do this. But there are many more features that we are throwing away. A more systematic approach would again be to only impose invariance in the final layer, and keep the others equivariant.&lt;/p&gt;
&lt;h3 id=&quot;higher-representationsorbitals&quot;&gt;Higher representations/orbitals&lt;/h3&gt;
&lt;p&gt;It gets a bit more complicated though. The complication is that there are many ways that things can transform under rotations. Chemists know these as orbitals, physicists and mathematicians as different representations of the rotation group.&lt;/p&gt;
&lt;p&gt;I’ll give an idea that, while not mathematically rigorous, captures the intuition of what’s important for us here. Imagine we start with two vectors representing the positions of two nuclei, which are in what is called the L=1 representation or the p orbital; here, the vector remains unchanged when rotated along its own axis but changes its position when rotated in any other way.&lt;/p&gt;
&lt;p&gt;We can combine these two vectors by taking the length of their difference. As mentioned before, this is invariant, it is called the L=0 representation or the s orbital. It is a single number that doesn’t change under any rotation. We can also simply add them, then it remains a vector.&lt;/p&gt;
&lt;p&gt;The two vectors together define a plane, a two dimensional surface that they both lie in (assuming that they are not parallel). Or more concretely imagine one vector pointing out of the cockpit of an actual plane and one along one wing. The plane they define together would be the floor of the inside of the actual plane.&lt;/p&gt;
&lt;p&gt;Loosely speaking this is how the two vectors can be combined to a higher representation, this would be the L=2 representation or the d orbital. Note that this plane depends on both vectors: if we rotate along the wing of the plane, that vector doesn’t change, but the one pointing out the cockpit certainly does, and so does the floor of the plane.&lt;/p&gt;
&lt;p&gt;This pattern continues: every time we add a new vector into the mix, we can either lower the representation by one, keep it the same, or increase it by one. For example if we start with a plane and a vector, you can imagine projecting the vector into the plane, that gives us a new vector, lowering the representation by one.&lt;/p&gt;
&lt;p&gt;So, crucially, the more complex combinations can be reduced down to something that is invariant, as we require for the output of the model.&lt;/p&gt;
&lt;p&gt;If we are very precise in how a layer is allowed to combine its inputs to form its outputs (how it combines the orbitals/representations), we can have intermediate layers that are equivariant, and a final equivariant output. This will then not only automatically capture the angles we mentioned before, but also more complex structures.&lt;/p&gt;
&lt;p&gt;This again makes the model more data-efficient, without paying the price of oversimplifying the input and throwing away a lot of information.&lt;/p&gt;
&lt;p&gt;This is implemented in the &lt;a href=&quot;https://github.com/e3nn/e3nn&quot;&gt;e3nn&lt;/a&gt; library, and used for example in the molecular dynamics models &lt;a href=&quot;https://github.com/mir-group/nequip&quot;&gt;nequip&lt;/a&gt; and &lt;a href=&quot;https://github.com/mir-group/allegro&quot;&gt;allegro&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By looking carefully at the structure of the problem, in particular how the true interatomic potential must transform under several transformations of its input, we have constructed a model that is very data efficient. The arguments to get here were very generic, and apply to any model that approximates an invariant function of particle positions.&lt;/p&gt;
&lt;p&gt;First we saw that we needed more than one layer in order to learn more than just linear functions. We used permutation invariance combined with locality to arrive at a graph neural network. On top of this we required invariance with respect to the spatial transformations of translations, rotations and reflections. This gives us what is called an E(3)-equivariant GNN (E(3) is the name for these transformations in 3-dimensional space).&lt;/p&gt;
&lt;p&gt;In the final part we will look at considerations that go into training this model.&lt;/p&gt;</description><pubDate>Thu, 13 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;In this post, I will walk through the process of designing a model used in molecular simulations, from essential to state of the art. This is the second part of a series on using machine learning for molecular simulations. It is relatively self-contained if you haven’t read&lt;/em&gt; &lt;a href=&quot;https://blog.esciencecenter.nl/molecular-simulations-using-machine-learning-part-1-e8624a82f680?sk=8c9902b39588261826ab77e3e24f8766&quot;&gt;&lt;em&gt;the first part&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;875&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_GVOnfCp1wScCos1_-b1c8ae9b.BJjMZttk_Z1wrR14.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by BoliviaInteligente on Unsplash&lt;/p&gt;
&lt;p&gt;We will design a model that approximates a potential used in molecular simulations. We will start from the simplest possible model, and reason our way step by step towards the essentials of the current state of the art models. This at the same time roughly follows the historical development of these models, although we will not attempt to be precise in this regard.&lt;/p&gt;
&lt;p&gt;The principles we use to arrive at a good model are quite general. Although they will lead to different models in different applications, I hope this can be helpful for scientists in different fields thinking about applying machine learning to their own field.&lt;/p&gt;
&lt;h3 id=&quot;quick-recap&quot;&gt;Quick recap&lt;/h3&gt;
&lt;p&gt;The figure below summarizes part 1 in a bit more detail. We saw how quantum mechanics was simplified into Density Functional Theory describing electrons, and Molecular Dynamics describing the atomic nuclei. The clouds in the figure indicate a-priori unknown ingredients that arose from these approximations: the density functional and the interatomic potential.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1131&quot; height=&quot;894&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zwvn0X4z6_mG4zyQ4acULw-036d0626.CR6qfiv9_5UqRY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We will focus on the interatomic potential: a single function depending on the positions of all the nuclei. The same principles that we use to derive a model for this also apply to the density functional, but the details will be different, because its inputs are different.&lt;/p&gt;
&lt;h2 id=&quot;simplest-machine-learning-model&quot;&gt;Simplest machine learning model&lt;/h2&gt;
&lt;p&gt;When designing a machine learning model, it is useful to start from the very basic question: what should go into it, and what should come out.&lt;/p&gt;
&lt;p&gt;Well, we want the model to compute a potential, which is a single number, depending on the coordinates of all nuclei. So if we have N nuclei in 3-dimensional space, the model should take 3N numbers and turn them into a single number.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;749&quot; height=&quot;424&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jCcxDmDEo7BTHXhrdDLR_g-832dfe19.Dc0wIY9X_Z2dnAc6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The simplest machine learning model: a linear model.&lt;/p&gt;
&lt;p&gt;The simplest possible machine learning model that meets this requirement would be multiplication by a 1 by 3N matrix W: M(x) = W x. This would multiply every one of the 3N inputs with a weight, and sum them all up. These weights are the trainable parameters. These are initially set to random values, and updated during training by correcting the errors the model makes. That part will remain the same throughout.&lt;/p&gt;
&lt;p&gt;This model has many undesirable properties, the most problematic one being that it is way too simple. A more precise way of saying this is that it is linear. This means that if we multiply all of the inputs by 2, the output will be multiplied by 2 as well. Or if we add 3 to say input x₁, the output will be the original output plus 3 w₁, where w₁ is the corresponding weight. In reality of course the effect of this change of one coordinate on the potential depends in a complicated way on its relationships to the coordinates of other particles. This model will never be able to capture that, no matter how much data you throw at it.&lt;/p&gt;
&lt;h2 id=&quot;deep-learning&quot;&gt;Deep learning&lt;/h2&gt;
&lt;p&gt;Removing this restriction takes us from machine learning to deep learning. The simplest neural network is basically a sequence of the simpler models from above, intermingled with nonlinear functions called activation functions. (Without these, the end result would still be linear!)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;657&quot; height=&quot;491&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_MNG8au1e0VGNe723I3Fv1A-338974de.DjMYcLzq_Z1SL8p9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The simplest deep learning model: a fully connected neural network.&lt;/p&gt;
&lt;p&gt;The simplest example of this class of models has one hidden layer: it takes the 3N inputs to say 100 numbers by a matrix multiplication, and applicaties an activation function to each one separately. Then through a second matrix multiplication it takes those to the one number we need as an output.&lt;/p&gt;
&lt;p&gt;There are many different activation functions, conceptually the only important thing is that they are nonlinear. A simple often used example is the ReLU, which is 0 if its input is negative, and otherwise just passes on the input unchanged.&lt;/p&gt;
&lt;p&gt;The effect of adding just one of these hidden layers is profound. In a sense, this immediately fixes the problem with the previous model. That is, this model can approximate anything now, given enough parameters. This statement is known as the &lt;em&gt;universal approximation theorem&lt;/em&gt;. However, that is quite a theoretical result. It doesn’t say how large the hidden layer should be, how much data is necessary, or even if it’s possible to find the right parameters through training at all, only that they exist.&lt;/p&gt;
&lt;p&gt;To address all of these other concerns, we need to specialise the model further to our particular application. In other words, we want our model to not only take into account just the &lt;em&gt;size&lt;/em&gt; of the in- and outputs, but also its &lt;em&gt;structure&lt;/em&gt;. As a first example, although the model above has the correct number of 3N inputs, it is not aware at all that actually these have the structure of N triplets of coordinates.&lt;/p&gt;
&lt;p&gt;To elaborate on this and make it more precise, we’ll look at the concept of equivariance. For a book and lectures on exploiting the structure of our data that is much more detailed, but also quite technical, see &lt;a href=&quot;https://geometricdeeplearning.com/&quot;&gt;https://geometricdeeplearning.com/&lt;/a&gt;, and &lt;a href=&quot;https://www.nature.com/articles/s42256-021-00418-8&quot;&gt;this paper&lt;/a&gt; for applications specifically to molecules.&lt;/p&gt;
&lt;h3 id=&quot;equivariance&quot;&gt;Equivariance&lt;/h3&gt;
&lt;p&gt;Equivariance means that if we &lt;em&gt;first&lt;/em&gt; transform the input and &lt;em&gt;then&lt;/em&gt; apply the model to it, we get the same result as when we &lt;em&gt;first&lt;/em&gt; apply the model, and &lt;em&gt;then&lt;/em&gt; apply a similar transformation to the output. It is a property that a model can have for some transformations but not for others. For example if this is true for a model M when the transformations are rotations, we say that M is rotation equivariant or equivariant with respect to rotations, illustrated in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;480&quot; height=&quot;420&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ez5PyIJRW8XGHQdlBjxxkQ-a83a4fc2.CH-zISRo_1gF3wY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Example of equivariance of a hypothetical model M that just detects edges. No matter if we first apply the model and then rotate the result, or first rotate the input and then apply the model, we end up with the same result.&lt;/p&gt;
&lt;p&gt;Note that the definition refers to a &lt;em&gt;similar&lt;/em&gt; transformation on the output, not necessarily exactly the same as we applied to the input. In fact, usually the output of the model will be of a different shape than the input, so we cannot even do the exact same transformation. The important part is that we know a-priori what the transformation on the output is, and it depends only on what transformation we did on the input.&lt;/p&gt;
&lt;p&gt;A special case of equivariance is &lt;em&gt;invariance&lt;/em&gt;, which is when this similar transformation is actually the identity. In other words, if we transform the input, the output will remain unchanged. For a simple example of this, if the hypothetical model in the image above were just a classifier saying whether the image is a cat or a dog, we’d expect it to be invariant: for both inputs on the left of the image, the outputs on the right should be “cat”.&lt;/p&gt;
&lt;p&gt;Requiring the model to be equivariant with respect to some transformation imposes some constraints on it, it decreases the freedom in the model, or the number of parameters. So as long as the equivariances we impose are also satisfied by the true solution we are trying to approximate with the model, it makes it more data efficient and easier to train. If we didn’t impose equivariance, the model could potentially have learned it from the data, but that would require more data, more time and more parameters. If we know this property beforehand, clearly it pays off to enforce it, preventing the model from the get go to make mistakes of this kind.&lt;/p&gt;
&lt;p&gt;There are many different transformations that the true interatomic potential must be equivariant to. We will discuss these one by one and use them to refine our model.&lt;/p&gt;
&lt;h3 id=&quot;permutations&quot;&gt;Permutations&lt;/h3&gt;
&lt;p&gt;In turning the positions of all nuclei into a 3N-dimensional input vector, we had to implicitly decide an order: which particle is the first particle, which is the second, etc. Clearly this is just a choice of labelling; if we pick a different order for the exact same configuration of particles, the potential shouldn’t change. So we want our model to be &lt;em&gt;invariant&lt;/em&gt; with respect to permutations.&lt;/p&gt;
&lt;p&gt;Currently it is not, it has no idea that the output should be the same, and so it would have to learn that by seeing lots of examples of identical configurations that are labelled differently, but with the same training label. Clearly this is a huge waste of time, and we want to avoid this.&lt;/p&gt;
&lt;p&gt;There are several common functions that do not depend on the order of their arguments, i.e. that are permutation invariant, such as the sum, or the mean, or the maximum. We will just take the sum, as it preserves more information than the maximum. So the very simplest permutation-invariant model would just take all of the nuclei’s positions and sum them. (Actually this would still leave us with 3 coordinates, so we’d need a 1 by 3 matrix at the end to turn it into a single number.)&lt;/p&gt;
&lt;p&gt;This is of course again much too simple, in fact even more so than what we started with. We can improve the situation while still taking permutations into account by having only the &lt;em&gt;last&lt;/em&gt; layer be invariant, and adding &lt;em&gt;equivariant&lt;/em&gt; layers in between.&lt;/p&gt;
&lt;p&gt;Any function that does exactly the same to every nucleus will be equivariant with respect to permutations: if we reorder the inputs, the outputs will be the same as the original, except that they are also reordered in exactly the same way. For this function we can use what we ended up with in the previous section: a fully connected neural network. So that takes a nucleus’s 3 coordinates, and does several matrix multiplications and activation functions on it to end up with a different amount of numbers for each atom, that we can choose.&lt;/p&gt;
&lt;p&gt;Note that if the intermediate layers were &lt;em&gt;not&lt;/em&gt; equivariant, there would be no way to guarantee invariance at the final layer. Furthermore, it also already makes the model more data efficient, as one training sample automatically teaches it about all the different orderings of that same sample.&lt;/p&gt;
&lt;p&gt;Another important consequence of this is that, unlike the fully connected level, we now have a model that works regardless of how many nuclei there are. This is great, because it will allow us to train the model on a small system, and then use it on a larger system.&lt;/p&gt;
&lt;h3 id=&quot;locality-graph-neural-networks&quot;&gt;Locality, graph neural networks&lt;/h3&gt;
&lt;p&gt;The above modification does impose permutation invariance, but it was still too restrictive. It treats all the nuclei independently, finally just summing “individual potentials” to obtain the total potential. This is not realistic, we expect the potential to depend also on the distance &lt;em&gt;between&lt;/em&gt; nuclei, something that this model cannot learn.&lt;/p&gt;
&lt;p&gt;We can relax this restriction and at the same time incorporate another physical prior by adding more structure to the input.&lt;/p&gt;
&lt;p&gt;The physical principle is locality: what happens at some point x only depends on things close to x. More concretely in this case, the Coulomb potential between two particles at a distance r decreases as 1/r. This means that the interaction between two nuclei that are very far from each other doesn’t have any significant contribution to the potential.&lt;/p&gt;
&lt;p&gt;So for nuclei closer to each other than some cutoff distance r_c, we want to take their interaction into account, and we can connect them by an edge. Those that are further away are not connected by an edge. This way we turn the original point cloud input into a graph.&lt;/p&gt;
&lt;p&gt;We then extend the operation that previously did the same to all nuclei, to allow it to depend on an atom’s neighbours as well. However, the number of neighbours will be different for different nuclei, and if we allow this to make the output shapes of each atom different things will quickly grow out of hand. So we need a way to combine the neighbours in such a way as to keep the shape independent of the number of neighbours. Furthermore we again have the issue of permutation invariance, now at a smaller local scale. The solution to both problems is the same: we sum over the features of the neighbours.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;692&quot; height=&quot;526&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_6pHDwX0OUPtuHWqbD0vUJw-f0843c46.d1xFbZ-o_Z1ORWx7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Illustration of message passing in a graph neural network. An atom c receives “messages” from its neighbours n and updates its state using those. The neighbours at the same time do the same. Multiple steps of this allow the message to propagate further.&lt;/p&gt;
&lt;p&gt;This is another permutation equivariant operation, now on graph inputs. It is called message passing, because it can be thought of as all of an atom’s neighbours passing messages to the central atom, who adds them all up. Doing this multiple times for all nuclei increases the region to which an atom is sensitive, because in the second step it can indirectly receive messages from its neighbours’ neighbours.&lt;/p&gt;
&lt;p&gt;At the end we have to sum over all nuclei again to obtain something invariant to permutations. These types of models are called Graph Neural Networks (GNNs).&lt;/p&gt;
&lt;h3 id=&quot;spatial-invariances&quot;&gt;Spatial invariances&lt;/h3&gt;
&lt;p&gt;While permutation invariance was more about the way we describe the system, how we label the nuclei, the remaining ones are actual spatial transformations: translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;If we move (“translate”) all nuclei in the same direction by the same amount, the interatomic potential doesn’t change. That is, whether we perform an experiment in Amsterdam, or we perform the exact same experiment in New York, the outcome should be the same. And the same holds for rotations and reflections. (If there were any external influence like gravity this would be different, but that is insignificant at the atomic scale.)&lt;/p&gt;
&lt;p&gt;As the model is now, it doesn’t know any of this. Building this in to the model makes it a lot more data efficient. From just one training simulation it would learn automatically about all its translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;The simplest way to enforce this is to only give the model inputs that are themselves invariant to these transformations. Clearly, if the inputs are not affected, the output is also not affected.&lt;/p&gt;
&lt;p&gt;That means we cannot have an atom’s position as an input by itself, as clearly that is not invariant under any of the transformations. But since we now have a graph, we can focus on &lt;em&gt;pairs&lt;/em&gt; of nuclei, and take the difference of their positions as an input. That is already invariant with respect to translations: if we add the same vector to both positions, it will cancel out in the difference. It is not yet invariant with respect to rotations or reflections, but if we reduce it further to just the absolute value of the difference, it is.&lt;/p&gt;
&lt;p&gt;That does the job, but it is again quite restrictive. Note the parallel here with the permutations we discussed previously: the simplest is to make everything invariant from the start, but it will turn out to be unnecessarily restrictive.&lt;/p&gt;
&lt;p&gt;For an example of something that is missed in this approach, consider a central atom with two two of its neighbours. The vectors pointing from the central atom to those two neighbours make up a certain angle to each other. If you think about it, this angle is also invariant with respect to all of the transformations. And it might well be a useful feature that has an effect on the potential that we want the model to represent. But there is no way to reconstruct this angle just from the absolute value of the differences in positions. Had we not thrown away that much information so early on, we &lt;em&gt;would&lt;/em&gt; be able to recover this angle: it’s related to the inner product between the two vectors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;554&quot; height=&quot;437&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_a_4d0GaMmdDN6ZJ8s81Rqg-6d8dab71.BVg6UK_y_Z2daGhj.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The angle φ is invariant to translations, rotations and reflections.&lt;/p&gt;
&lt;p&gt;We could of course add these angles to the input “by hand” and stick to imposing invariance from the start, and there are models that do this. But there are many more features that we are throwing away. A more systematic approach would again be to only impose invariance in the final layer, and keep the others equivariant.&lt;/p&gt;
&lt;h3 id=&quot;higher-representationsorbitals&quot;&gt;Higher representations/orbitals&lt;/h3&gt;
&lt;p&gt;It gets a bit more complicated though. The complication is that there are many ways that things can transform under rotations. Chemists know these as orbitals, physicists and mathematicians as different representations of the rotation group.&lt;/p&gt;
&lt;p&gt;I’ll give an idea that, while not mathematically rigorous, captures the intuition of what’s important for us here. Imagine we start with two vectors representing the positions of two nuclei, which are in what is called the L=1 representation or the p orbital; here, the vector remains unchanged when rotated along its own axis but changes its position when rotated in any other way.&lt;/p&gt;
&lt;p&gt;We can combine these two vectors by taking the length of their difference. As mentioned before, this is invariant, it is called the L=0 representation or the s orbital. It is a single number that doesn’t change under any rotation. We can also simply add them, then it remains a vector.&lt;/p&gt;
&lt;p&gt;The two vectors together define a plane, a two dimensional surface that they both lie in (assuming that they are not parallel). Or more concretely imagine one vector pointing out of the cockpit of an actual plane and one along one wing. The plane they define together would be the floor of the inside of the actual plane.&lt;/p&gt;
&lt;p&gt;Loosely speaking this is how the two vectors can be combined to a higher representation, this would be the L=2 representation or the d orbital. Note that this plane depends on both vectors: if we rotate along the wing of the plane, that vector doesn’t change, but the one pointing out the cockpit certainly does, and so does the floor of the plane.&lt;/p&gt;
&lt;p&gt;This pattern continues: every time we add a new vector into the mix, we can either lower the representation by one, keep it the same, or increase it by one. For example if we start with a plane and a vector, you can imagine projecting the vector into the plane, that gives us a new vector, lowering the representation by one.&lt;/p&gt;
&lt;p&gt;So, crucially, the more complex combinations can be reduced down to something that is invariant, as we require for the output of the model.&lt;/p&gt;
&lt;p&gt;If we are very precise in how a layer is allowed to combine its inputs to form its outputs (how it combines the orbitals/representations), we can have intermediate layers that are equivariant, and a final equivariant output. This will then not only automatically capture the angles we mentioned before, but also more complex structures.&lt;/p&gt;
&lt;p&gt;This again makes the model more data-efficient, without paying the price of oversimplifying the input and throwing away a lot of information.&lt;/p&gt;
&lt;p&gt;This is implemented in the &lt;a href=&quot;https://github.com/e3nn/e3nn&quot;&gt;e3nn&lt;/a&gt; library, and used for example in the molecular dynamics models &lt;a href=&quot;https://github.com/mir-group/nequip&quot;&gt;nequip&lt;/a&gt; and &lt;a href=&quot;https://github.com/mir-group/allegro&quot;&gt;allegro&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By looking carefully at the structure of the problem, in particular how the true interatomic potential must transform under several transformations of its input, we have constructed a model that is very data efficient. The arguments to get here were very generic, and apply to any model that approximates an invariant function of particle positions.&lt;/p&gt;
&lt;p&gt;First we saw that we needed more than one layer in order to learn more than just linear functions. We used permutation invariance combined with locality to arrive at a graph neural network. On top of this we required invariance with respect to the spatial transformations of translations, rotations and reflections. This gives us what is called an E(3)-equivariant GNN (E(3) is the name for these transformations in 3-dimensional space).&lt;/p&gt;
&lt;p&gt;In the final part we will look at considerations that go into training this model.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_GVOnfCp1wScCos1_-b1c8ae9b.BJjMZttk.webp" medium="image"/><author>Aron</author></item><item><title>Ditching Docker Hub: serve research software with GHCR + Zenodo</title><link>https://blog.esciencecenter.nl/posts/2023-04-06---ditching-docker-hub-serve-research-software-with-ghcr-zenodo</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-04-06---ditching-docker-hub-serve-research-software-with-ghcr-zenodo</guid><description>&lt;h2 id=&quot;or-pay-the-price-that-docker-hub-may-charge-you&quot;&gt;Or pay the price… that Docker Hub may charge you&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;768&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uLU5uRex4V9KagumXjzzpw-85a5ef6c.02ncUoQr_1ATE6R.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Scrooge McDuck who throws a Docker container in the trash in the style of Disney… according to Stable Diffusion.&lt;/p&gt;
&lt;p&gt;As a researcher, and especially as a research software engineer, you may find yourself writing software that needs to be shared with others in a &lt;strong&gt;reproducible&lt;/strong&gt; way. So, you containerize it. In the past, you might then have used Docker Hub to store your containerized software.&lt;/p&gt;
&lt;p&gt;However, recent attempts to change Docker Hub’s pricing model have made it less attractive as a long-term repository. Frankly, it has made us uncertain about Docker Hub’s reliability as a long-term archive. &lt;a href=&quot;https://devclass.com/2023/03/15/docker-to-users-of-free-team-orgs-one-month-to-pay-up-or-we-freeze-account-and-images-go/&quot;&gt;Docker’s recent trial balloon about deleting Docker images in “Free Team” accounts&lt;/a&gt; (which they apologized for the next day, and was completely reverted after 10 days, but still…) does not foster trust, to say the least.&lt;/p&gt;
&lt;p&gt;To minimize the risk of having to pay for Docker Hub use at any unexpected time, we now recommend using GitHub Container Registry (GHCR) for use during development and Zenodo for archiving.&lt;/p&gt;
&lt;h2 id=&quot;during-development-github-container-registry&quot;&gt;During development: GitHub Container Registry&lt;/h2&gt;
&lt;p&gt;GitHub Container Registry (GHCR) is a relatively new addition to the GitHub ecosystem, but it’s already proving to be a powerful tool for developers. As the name suggests, GHCR allows you to store and distribute Docker images directly from your GitHub repositories. This means that you can keep all of your code and its associated container images in one place, which makes it easier to manage and collaborate on.&lt;/p&gt;
&lt;p&gt;One of the biggest advantages of GHCR is that it integrates seamlessly with other GitHub tools, such as Actions and Packages, which can be used to automate workflows and improve collaboration. Also, it’s free (for public images; for private ones you have to pay, which should not pose an issue in this day and age of Open Science). GHCR is included as part of your GitHub account. This means that you can store as many Docker images as you like without worrying about the costs.&lt;/p&gt;
&lt;p&gt;At the eScience Center, we have been using GHCR for a while already, for instance for the &lt;a href=&quot;https://github.com/research-software-directory/RSD-as-a-service&quot;&gt;Research Software Directory&lt;/a&gt;. You can see in the right-hand panel the packages menu which lists a couple of the available images:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;329&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jixBfMoQwy4kUZB2OurKkg-6dc258e7.Cu6JU-rG_1n5qsE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Packages widget listing the Docker images stored in GHCR for the Research Software Directory.&lt;/p&gt;
&lt;p&gt;Clicking for instance on &lt;strong&gt;rsd-saas/database&lt;/strong&gt; brings you to the page where you get clear instructions on how to get the image on your machine using:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker pull ghcr.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;research&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;software&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;directory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;rsd&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;saas&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;database:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;18.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Couldn’t get much easier!&lt;/p&gt;
&lt;h2 id=&quot;long-term-archiving-zenodo&quot;&gt;Long term archiving: Zenodo&lt;/h2&gt;
&lt;p&gt;However, GHCR is not a long-term archiving solution. While it’s great for development and sharing with collaborators, you’ll still need to find a way to archive your software for the long term. This is where Zenodo comes in.&lt;/p&gt;
&lt;p&gt;Zenodo is a free, open-access repository that’s designed specifically for research outputs. This includes software, data, and other digital objects. By archiving your software on Zenodo, you’ll be ensuring that it’s accessible and discoverable for the long term. Zenodo also provides persistent identifiers (DOIs) for your software, which can be used to cite it in publications.&lt;/p&gt;
&lt;p&gt;To archive your software on Zenodo, simply &lt;a href=&quot;https://zenodo.org/deposit/new&quot;&gt;create a new record and upload your Docker image as a file&lt;/a&gt;. To create such a file from an image called &lt;code&gt;hello-world:latest&lt;/code&gt; you can create a zipped tarball like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker image save hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gzip &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also include additional metadata, such as a description of your software and the research project it’s associated with. Once your record is published, it will be available for anyone to access and download. One project we came across that has been doing this already is &lt;a href=&quot;https://spex-xray.github.io/spex-help/getstarted/docker.html#step-2-download-the-spex-docker-image-from-zenodo&quot;&gt;Spex&lt;/a&gt;, a popular X-ray astronomy package. Following their lead, after someone downloads the &lt;code&gt;hello-world:latest.tar.gz&lt;/code&gt; file, firing your container back up with Docker is as easy as:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;i hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;one-repo-to-rule-them-all&quot;&gt;One repo to rule them all?&lt;/h2&gt;
&lt;p&gt;Why not use Zenodo for all images, you may wonder? For us, the reason is that GHCR is meant to be used together with GitHub Actions as well. It’s the fastest option for continuous integration and also for running tests locally. It is also a one-command option, as opposed to the Zenodo option where you have a manual download step to do before using the image.&lt;/p&gt;
&lt;p&gt;Why not use GHCR for all images, then? Zenodo is a dedicated research “artifact” storage repository. Like Docker Hub, GitHub, a commercial company, may change its policies at any time and start charging to preserve your containers. This would in fact be totally reasonable for them to do. We trust Zenodo to be a reliable long-term archiving solution for research.&lt;/p&gt;
&lt;p&gt;Of course, Docker Hub can still be an option for you, if you are willing to pay them. It is, after all, still the simplest way to use Docker. This requires long-term institutional funding, though, which unfortunately is rare in academia, especially for supporting research software. &lt;a href=&quot;https://dspace.library.uu.nl/handle/1874/424547&quot;&gt;An issue which is being worked on, by the way…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In conclusion, if you’re a researcher writing software that needs to be shared with others, we recommend using GitHub Container Registry for development and Zenodo for archiving. GHCR is a powerful and free tool that integrates seamlessly with GitHub, while Zenodo provides a long-term archiving solution that’s designed specifically for research outputs. By using these tools together, you can ensure that your software is both accessible and discoverable for the long term.&lt;/p&gt;
&lt;h2 id=&quot;credits--meta-sub-blogpost&quot;&gt;Credits / meta-sub-blogpost&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This article was written based on a discussion in the eScience Center’s Software Sustainability special interest group (SIG).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Actually, “written” is not fully accurate. I fed the SIG meeting notes into ChatGPT and asked it to process that into a blogpost; the above is mostly the result of that, with some minor edits from my side.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;939&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_40yq4tQyLhtUsNsmhZzH7Q-f0aaae37.DM2UbHWW_ZLkjAL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn’t really like the titles it proposed though:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;823&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_RdBrqE58a6a00BnrXEw7hA-a0fc042c.DDvILlWh_ZuOXnv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Close enough, though!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Tom Bakker, Stefan Verhoeven, Luisa Orozco and Carlos Martinez for improving on ChatGPT’s draft!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;768&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_1z7VDm5f7eSfYql5M4lZAw-dd23f63e.w9gtqVBa_Z1q4tkP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Same as above, but now in the style of Looney Tunes… You AIs, you!&lt;/p&gt;</description><pubDate>Thu, 06 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;or-pay-the-price-that-docker-hub-may-charge-you&quot;&gt;Or pay the price… that Docker Hub may charge you&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;768&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uLU5uRex4V9KagumXjzzpw-85a5ef6c.02ncUoQr_1ATE6R.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Scrooge McDuck who throws a Docker container in the trash in the style of Disney… according to Stable Diffusion.&lt;/p&gt;
&lt;p&gt;As a researcher, and especially as a research software engineer, you may find yourself writing software that needs to be shared with others in a &lt;strong&gt;reproducible&lt;/strong&gt; way. So, you containerize it. In the past, you might then have used Docker Hub to store your containerized software.&lt;/p&gt;
&lt;p&gt;However, recent attempts to change Docker Hub’s pricing model have made it less attractive as a long-term repository. Frankly, it has made us uncertain about Docker Hub’s reliability as a long-term archive. &lt;a href=&quot;https://devclass.com/2023/03/15/docker-to-users-of-free-team-orgs-one-month-to-pay-up-or-we-freeze-account-and-images-go/&quot;&gt;Docker’s recent trial balloon about deleting Docker images in “Free Team” accounts&lt;/a&gt; (which they apologized for the next day, and was completely reverted after 10 days, but still…) does not foster trust, to say the least.&lt;/p&gt;
&lt;p&gt;To minimize the risk of having to pay for Docker Hub use at any unexpected time, we now recommend using GitHub Container Registry (GHCR) for use during development and Zenodo for archiving.&lt;/p&gt;
&lt;h2 id=&quot;during-development-github-container-registry&quot;&gt;During development: GitHub Container Registry&lt;/h2&gt;
&lt;p&gt;GitHub Container Registry (GHCR) is a relatively new addition to the GitHub ecosystem, but it’s already proving to be a powerful tool for developers. As the name suggests, GHCR allows you to store and distribute Docker images directly from your GitHub repositories. This means that you can keep all of your code and its associated container images in one place, which makes it easier to manage and collaborate on.&lt;/p&gt;
&lt;p&gt;One of the biggest advantages of GHCR is that it integrates seamlessly with other GitHub tools, such as Actions and Packages, which can be used to automate workflows and improve collaboration. Also, it’s free (for public images; for private ones you have to pay, which should not pose an issue in this day and age of Open Science). GHCR is included as part of your GitHub account. This means that you can store as many Docker images as you like without worrying about the costs.&lt;/p&gt;
&lt;p&gt;At the eScience Center, we have been using GHCR for a while already, for instance for the &lt;a href=&quot;https://github.com/research-software-directory/RSD-as-a-service&quot;&gt;Research Software Directory&lt;/a&gt;. You can see in the right-hand panel the packages menu which lists a couple of the available images:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;329&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jixBfMoQwy4kUZB2OurKkg-6dc258e7.Cu6JU-rG_1n5qsE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Packages widget listing the Docker images stored in GHCR for the Research Software Directory.&lt;/p&gt;
&lt;p&gt;Clicking for instance on &lt;strong&gt;rsd-saas/database&lt;/strong&gt; brings you to the page where you get clear instructions on how to get the image on your machine using:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker pull ghcr.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;research&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;software&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;directory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;rsd&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;saas&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;database:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;18.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Couldn’t get much easier!&lt;/p&gt;
&lt;h2 id=&quot;long-term-archiving-zenodo&quot;&gt;Long term archiving: Zenodo&lt;/h2&gt;
&lt;p&gt;However, GHCR is not a long-term archiving solution. While it’s great for development and sharing with collaborators, you’ll still need to find a way to archive your software for the long term. This is where Zenodo comes in.&lt;/p&gt;
&lt;p&gt;Zenodo is a free, open-access repository that’s designed specifically for research outputs. This includes software, data, and other digital objects. By archiving your software on Zenodo, you’ll be ensuring that it’s accessible and discoverable for the long term. Zenodo also provides persistent identifiers (DOIs) for your software, which can be used to cite it in publications.&lt;/p&gt;
&lt;p&gt;To archive your software on Zenodo, simply &lt;a href=&quot;https://zenodo.org/deposit/new&quot;&gt;create a new record and upload your Docker image as a file&lt;/a&gt;. To create such a file from an image called &lt;code&gt;hello-world:latest&lt;/code&gt; you can create a zipped tarball like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker image save hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gzip &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also include additional metadata, such as a description of your software and the research project it’s associated with. Once your record is published, it will be available for anyone to access and download. One project we came across that has been doing this already is &lt;a href=&quot;https://spex-xray.github.io/spex-help/getstarted/docker.html#step-2-download-the-spex-docker-image-from-zenodo&quot;&gt;Spex&lt;/a&gt;, a popular X-ray astronomy package. Following their lead, after someone downloads the &lt;code&gt;hello-world:latest.tar.gz&lt;/code&gt; file, firing your container back up with Docker is as easy as:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;docker &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;i hello&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;world:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;one-repo-to-rule-them-all&quot;&gt;One repo to rule them all?&lt;/h2&gt;
&lt;p&gt;Why not use Zenodo for all images, you may wonder? For us, the reason is that GHCR is meant to be used together with GitHub Actions as well. It’s the fastest option for continuous integration and also for running tests locally. It is also a one-command option, as opposed to the Zenodo option where you have a manual download step to do before using the image.&lt;/p&gt;
&lt;p&gt;Why not use GHCR for all images, then? Zenodo is a dedicated research “artifact” storage repository. Like Docker Hub, GitHub, a commercial company, may change its policies at any time and start charging to preserve your containers. This would in fact be totally reasonable for them to do. We trust Zenodo to be a reliable long-term archiving solution for research.&lt;/p&gt;
&lt;p&gt;Of course, Docker Hub can still be an option for you, if you are willing to pay them. It is, after all, still the simplest way to use Docker. This requires long-term institutional funding, though, which unfortunately is rare in academia, especially for supporting research software. &lt;a href=&quot;https://dspace.library.uu.nl/handle/1874/424547&quot;&gt;An issue which is being worked on, by the way…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In conclusion, if you’re a researcher writing software that needs to be shared with others, we recommend using GitHub Container Registry for development and Zenodo for archiving. GHCR is a powerful and free tool that integrates seamlessly with GitHub, while Zenodo provides a long-term archiving solution that’s designed specifically for research outputs. By using these tools together, you can ensure that your software is both accessible and discoverable for the long term.&lt;/p&gt;
&lt;h2 id=&quot;credits--meta-sub-blogpost&quot;&gt;Credits / meta-sub-blogpost&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This article was written based on a discussion in the eScience Center’s Software Sustainability special interest group (SIG).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Actually, “written” is not fully accurate. I fed the SIG meeting notes into ChatGPT and asked it to process that into a blogpost; the above is mostly the result of that, with some minor edits from my side.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;939&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_40yq4tQyLhtUsNsmhZzH7Q-f0aaae37.DM2UbHWW_ZLkjAL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn’t really like the titles it proposed though:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;823&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_RdBrqE58a6a00BnrXEw7hA-a0fc042c.DDvILlWh_ZuOXnv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Close enough, though!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Tom Bakker, Stefan Verhoeven, Luisa Orozco and Carlos Martinez for improving on ChatGPT’s draft!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;768&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_1z7VDm5f7eSfYql5M4lZAw-dd23f63e.w9gtqVBa_Z1q4tkP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Same as above, but now in the style of Looney Tunes… You AIs, you!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_jixBfMoQwy4kUZB2OurKkg-6dc258e7.Cu6JU-rG.png" medium="image"/><author>Patrick Bos</author></item><item><title>Molecular Simulations using Machine Learning, Part 1</title><link>https://blog.esciencecenter.nl/posts/2023-03-31---molecular-simulations-using-machine-learning-part-1</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-03-31---molecular-simulations-using-machine-learning-part-1</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;480&quot; height=&quot;270&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YCtoB6VF8ntOvbyl4Oy5OQ-c1205a48.DO7ORMD9_ZlzXvd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simulation of water molecules from Wikipedia.&lt;/p&gt;
&lt;p&gt;Are you curious about how scientists study the properties of materials, proteins, and drugs? It all starts with molecular simulation. By creating virtual models and running simulations at the molecular level, researchers can unlock the secrets of these substances and design new ones. The gif above shows a short such simulation, in this case simply of water.&lt;/p&gt;
&lt;p&gt;In this three-part blog series, we’ll explore the exciting world of molecular simulation and how machine learning is revolutionizing the field. This first part is purely about the physics. If you have a somewhat technical background and an interest in the topic, it might be interesting to you. If it becomes too technical, the next two parts about machine learning will be relatively stand-alone, and should be interesting also to scientists thinking about applying machine learning to their own fields.&lt;/p&gt;
&lt;p&gt;Here we’ll look at the fundamental theory of quantum mechanics, which underpins molecular simulation. But simulating molecules using this theory directly is too difficult computationally. So, we’ll explore how physicists and chemists have simplified the theory to make it workable for simulation.&lt;/p&gt;
&lt;p&gt;While simplifying the theory makes it more efficient, it also creates some gaps that need to be filled. That’s where the machine learning will come in, allowing us to learn these from data.&lt;/p&gt;
&lt;h2 id=&quot;quantum-mechanics-and-the-schrödinger-equation&quot;&gt;Quantum Mechanics and the Schrödinger Equation&lt;/h2&gt;
&lt;p&gt;We will start with quantum mechanics in a simplified setting where the system we study is in equilibrium. This is described by the time-independent Schrödinger equation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;562&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_7i7tcw7VNt8GURTaOs1P6g-3a40b70c.3E80kelT_2axLfz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Schrödinger equation in its simplest form.&lt;/p&gt;
&lt;p&gt;Here m is the mass, p the momentum, V the potential energy, and E the total energy of the system.&lt;/p&gt;
&lt;p&gt;What we want to solve this equation for is ψ, which is called the wave function. It encodes the density of the particles we are studying, at every point in space.&lt;/p&gt;
&lt;p&gt;While superficially this may look quite short and simple, it hides a lot of complexity, both conceptual and computational. In this blog I will focus on the computational complexity.&lt;/p&gt;
&lt;p&gt;One thing I have swept under the rug in the equation above is that our system has not just one but many particles. Each of them has their own momentum and their own mass (although electrons all have the same mass, and for simplicity we can think of the nuclei all being the same, so having the same mass as well). So actually there should be a sum over all particles in the left most term.&lt;/p&gt;
&lt;p&gt;The momentum p is actually a derivative with respect to the position in quantum mechanics. More precisely, p = — i ℏ ∂, where ℏ is a very small number called Planck’s constant. Its smallness is the reason we can get through everyday life without thinking about quantum mechanics.&lt;/p&gt;
&lt;p&gt;This leads to something more problematic that I have also swept under the rug. Since the momentum is a derivative with respect to the position, acting on the wave function, and each particle has its own momentum, the wave function is not just a function of the position, it is a function of &lt;em&gt;the positions of every single particle&lt;/em&gt;. A block of material the size of your smartphone has about 10²⁵ electrons and nuclei, that’s a lot of arguments!&lt;/p&gt;
&lt;p&gt;The potential by the way is the Coulomb potential that charged particles exert on each other, so that also depends on all of the coordinates.&lt;/p&gt;
&lt;p&gt;To understand the computational complexity better it is insightful to look at how we would solve this numerically. Basically, the way most numerical methods go about solving a differential equation is to evaluate the equation itself on a certain number of points. This allows translating the differential equation into linear algebra, a matrix equation essentially of the form A x = b, where A is a matrix and b a vector that we both obtain from this procedure, and if we solve this for the vector x we get an approximation of the solution we’re after on this same set of points.&lt;/p&gt;
&lt;p&gt;How many points we need depends heavily on the details, but let’s say for simplicity the system is constrained to be on a single line, in other words space is only 1-dimensional. Let’s also restrict it to the interval between 0 and 1, and say we use K points, located at the positions x_i = i /K on the interval.&lt;/p&gt;
&lt;p&gt;Maybe K=20 could be sufficient in some very simple situation, so that doesn’t seem too bad. Remember though that every single particle has a position, and the wave function depends on all of them. So we need all &lt;em&gt;combinations&lt;/em&gt; of positions. So for a system with 10²⁵ particles that amounts to 20 &lt;em&gt;to the power&lt;/em&gt; 10²⁵ points.&lt;/p&gt;
&lt;p&gt;Another way to think about this is that if we add only a single electron to our system, we’d now need to solve the original system once for every possible location of the added electron. So in our example this would make the problem a 20 times larger, this is known as exponential complexity.&lt;/p&gt;
&lt;p&gt;These ridiculous numbers come from the combination of the exponential complexity of the problem with the already huge number of particles involved.&lt;/p&gt;
&lt;p&gt;This means that using this equation directly is only feasible for the smallest of systems, which really means practically only the hydrogen atom: a single nucleus with a single electron.&lt;/p&gt;
&lt;h2 id=&quot;approximations&quot;&gt;Approximations&lt;/h2&gt;
&lt;p&gt;Clearly then we need to do some approximations to this equation. I will illustrate conceptually a series of explanations that is very standard.&lt;/p&gt;
&lt;p&gt;The first and simplest step follows from the observation that the proton is much heavier than the electron, by a factor of about 1000. So even for hydrogen, whose nucleus is just a single proton, this is a significant factor, and for bigger cores the ratio is even larger, for example carbon contains 12 protons and neutrons (which have similar mass to protons), so their mass is about 10⁴ times that of an electron.&lt;/p&gt;
&lt;p&gt;Now heavy things tend to move more slowly than light things, this is the essence of what is called the &lt;em&gt;clamped nuclei approximation&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;From the point of view of an electron, on the typical timescale at which it itself moves, the nuclei are basically standing still. So assuming we know the positions of all the nuclei, we can treat those as fixed, and we can compute the force they exert on the electrons, and solve for the electrons separately.&lt;/p&gt;
&lt;p&gt;Conversely, from the point of view of a nucleus, by the time it itself moves, all the electrons will have had enough time to settle down to their equilibrium positions, into what is called their ground state.&lt;/p&gt;
&lt;p&gt;So this allows us to in a sense decouple the electrons from the nuclei. By itself this doesn’t give a significant improvement yet, so we need to simplify each part separately.&lt;/p&gt;
&lt;h3 id=&quot;the-electrons-density-functional-theory-dft&quot;&gt;The electrons: Density Functional Theory (DFT)&lt;/h3&gt;
&lt;p&gt;First we’ll look at the electrons. The difficulty of the problem lies in the interactions between them. If they were all independent it would be a much simpler problem, but clearly that is too crude of an approximation: they exert a Coulomb force on each other, so they are not independent. There are additional quantum mechanical effects that make them even less independent.&lt;/p&gt;
&lt;p&gt;What we &lt;em&gt;can&lt;/em&gt; do is to simplify all interactions to just interactions between each individual particle and some kind of averaged out particle, this is known as the mean field approximation. That is, we imagine that all of the electrons contribute to an average electron density. This density creates some potential energy that is felt by every electron. If that sounds recursive, that’s because it is. That is the price we pay for this approximation: we get a simpler problem, but we have to solve it many times until it is self consistent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;663&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_nYX_YbciZm8swnTDX1AJ5g-0177e0e1.Dg_ExSH0_2eueTy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Adapted in simplified form from Materials Modelling using Density Functional Theory, Feliciano Giustino.&lt;/p&gt;
&lt;p&gt;The process is illustrated in the figure above. Assume we know where the nuclei are, that gives a potential coming from the nuclei which is the input to the problem. Then we make a guess for this electron density, and use that to compute another potential, caused by the electrons themselves. Now we know the equation for every electron separately, which we can then solve independently from each other. But the total density should be the sum over the individual electron densities, so we compute that. Likely we won’t get the same as the density we started with, and we have to repeat this whole procedure until we do.&lt;/p&gt;
&lt;p&gt;This approach is called Density Functional Theory (DFT).&lt;/p&gt;
&lt;p&gt;What I’ve glossed over is what this potential is that each electron feels due to the total density. This is what gives this theory its name: the density functional. A functional is just what mathematicians call a function whose argument is itself a function. In this case the potential is a function of the electron density, which itself is a function of the position (a single position this time!).&lt;/p&gt;
&lt;p&gt;The interesting situation is that this whole “approximation” is known to be &lt;em&gt;exact&lt;/em&gt;. So at this point it is not an approximation at all, we do not lose any accuracy by doing this. There is a catch however. The theory only tells us that an appropriate density functional &lt;em&gt;exists&lt;/em&gt;, that makes it exact in any situation, but it does not tell us &lt;em&gt;what&lt;/em&gt; &lt;em&gt;it is&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So the actual approximation comes in the form of a guess of the density functional. Coming up with density functionals that perform well in certain situations is a whole field of research, and there is a whole zoo of density functionals out there.&lt;/p&gt;
&lt;p&gt;In terms of the computational complexity, the bottleneck lies in solving for the individual electrons, combined with the fact that we have to keep doing this until convergence. ==The time taken scales roughly with the third power of the number of electrons==. This is not great, but still much better than the exponential scaling we started with!&lt;/p&gt;
&lt;p&gt;Concretely, in the example where we used 10 grid points, going from 100 to 101 particles made using the Schrödinger equation directly 10 times slower, whereas DFT only becomes it 3% slower. You see how important these scalings of computational complexities are.&lt;/p&gt;
&lt;p&gt;In practice, whereas the Schrödinger equation could almost only be applied to the simplest of atoms, DFT can be used not just for single atoms, but for molecules and even multiple molecules together. It is still very expensive computationally though, not something you can run on your laptop, rather on a cluster and potentially having to wait a few weeks depending on the problem. From where we started though, this is already a big step up.&lt;/p&gt;
&lt;h3 id=&quot;the-nuclei-molecular-dynamics-md&quot;&gt;The nuclei: Molecular Dynamics (MD)&lt;/h3&gt;
&lt;p&gt;Now we turn back to the nuclei. Here the most important source of approximation is their mass. We already used this to decouple them from the electrons, as their mass is much larger. We can now use this in another way.&lt;/p&gt;
&lt;p&gt;Quantum mechanics only becomes necessary to describe a system if it is very small and light. For the movement of billiard balls on a pool table, we can fortunately just use classical mechanics. Formally this is a limit of quantum mechanics, prosaically known as the classical limit. Remember that in the Schrödinger equation I said that the momentum is actually a derivative with respect to the position, and the wave function encodes the probability of finding a particle somewhere. In the classical limit, the momentum goes back to being just a number, and the probability goes away, so that a particle is just described by its position and its momentum.&lt;/p&gt;
&lt;p&gt;Perhaps surprisingly, even for something as small as a nucleus, this is a good approximation. That is true for all but the smallest nuclei, such as hydrogen.&lt;/p&gt;
&lt;p&gt;This leads to a very simple system, where we have a potential coming from the electrons in addition to the Coulomb potential between the nuclei themselves. We obtain the forces just by taking the derivative of the potential, and with these forces we can evolve the nuclei in time.&lt;/p&gt;
&lt;p&gt;This approach is called &lt;em&gt;Molecular Dynamics (MD)&lt;/em&gt;, and is illustrated in the flowchart below.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;771&quot; height=&quot;393&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_0xhgXYMhL1XVf6LXSjUsMg-4bf2a6ea.D64hjsCJ_uEIJK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Adapted in simplified form from Materials Modelling using Density Functional Theory, Feliciano Giustino.&lt;/p&gt;
&lt;p&gt;Here again we had to introduce an unknown potential, in this case called the &lt;em&gt;interatomic potential&lt;/em&gt;. This captures the effect of the electrons on the nuclei. And again this is a priori unknown, so we have to guess it.&lt;/p&gt;
&lt;p&gt;In this case, there is a very natural candidate. We have just discussed a way to compute the electron density for any configuration of nuclei, namely DFT. So we could do that, and then simply use the Coulomb potential coming from this electron density. This is known as &lt;em&gt;ab-initio Molecular Dynamics (aiMD)&lt;/em&gt;, because we didn’t need to make another guess on a potential.&lt;/p&gt;
&lt;p&gt;The good thing about aiMD is that it is usually very accurate. However it requires a full DFT computation for every step of MD, making it very expensive computationally.&lt;/p&gt;
&lt;p&gt;The alternative is to come up with a simple form of the interatomic potential that is very fast to evaluate, and may be accurate for certain systems. Many such guesses exist.&lt;/p&gt;
&lt;p&gt;So here the computational complexity is very strongly dependent on the interatomic potential used, the other steps are usually negligible in comparison. Less expensive potentials can be used to simulate millions of atoms, for example in large proteins or crystal structures.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The diagram below summarizes what we have discussed.&lt;br&gt;
Through a series of physically motivated, and for many situations very accurate, approximations we have reduced the elegant but computationally intractable formulation of the Schrödinger equation into two parts: density functional theory (DFT) for the electrons and molecular dynamics (MD) for the nuclei.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1131&quot; height=&quot;894&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zwvn0X4z6_mG4zyQ4acULw-036d0626.CR6qfiv9_5UqRY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simplified illustration of the approximations done to go from quantum mechanics to Density Functional Theory (DFT) describing the electrons and Molecular Dynamics (MD) describing the nuclei. The clouds contain the ingredients that need to be specified to complete each theory.&lt;/p&gt;
&lt;p&gt;For both parts, this required the introduction of a priori unknown potentials: the density functional for DFT and the interatomic potential for MD. For both of these, a whole zoo of guesses exist, each of varying accuracy depending on the system at hand.&lt;/p&gt;
&lt;p&gt;This is where machine learning comes into the picture: rather than guessing these potentials ourselves, we can let a machine learning model learn them from data. We will discuss this in part 2 of this series.&lt;/p&gt;</description><pubDate>Fri, 31 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;480&quot; height=&quot;270&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YCtoB6VF8ntOvbyl4Oy5OQ-c1205a48.DO7ORMD9_ZlzXvd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simulation of water molecules from Wikipedia.&lt;/p&gt;
&lt;p&gt;Are you curious about how scientists study the properties of materials, proteins, and drugs? It all starts with molecular simulation. By creating virtual models and running simulations at the molecular level, researchers can unlock the secrets of these substances and design new ones. The gif above shows a short such simulation, in this case simply of water.&lt;/p&gt;
&lt;p&gt;In this three-part blog series, we’ll explore the exciting world of molecular simulation and how machine learning is revolutionizing the field. This first part is purely about the physics. If you have a somewhat technical background and an interest in the topic, it might be interesting to you. If it becomes too technical, the next two parts about machine learning will be relatively stand-alone, and should be interesting also to scientists thinking about applying machine learning to their own fields.&lt;/p&gt;
&lt;p&gt;Here we’ll look at the fundamental theory of quantum mechanics, which underpins molecular simulation. But simulating molecules using this theory directly is too difficult computationally. So, we’ll explore how physicists and chemists have simplified the theory to make it workable for simulation.&lt;/p&gt;
&lt;p&gt;While simplifying the theory makes it more efficient, it also creates some gaps that need to be filled. That’s where the machine learning will come in, allowing us to learn these from data.&lt;/p&gt;
&lt;h2 id=&quot;quantum-mechanics-and-the-schrödinger-equation&quot;&gt;Quantum Mechanics and the Schrödinger Equation&lt;/h2&gt;
&lt;p&gt;We will start with quantum mechanics in a simplified setting where the system we study is in equilibrium. This is described by the time-independent Schrödinger equation:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;562&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_7i7tcw7VNt8GURTaOs1P6g-3a40b70c.3E80kelT_2axLfz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Schrödinger equation in its simplest form.&lt;/p&gt;
&lt;p&gt;Here m is the mass, p the momentum, V the potential energy, and E the total energy of the system.&lt;/p&gt;
&lt;p&gt;What we want to solve this equation for is ψ, which is called the wave function. It encodes the density of the particles we are studying, at every point in space.&lt;/p&gt;
&lt;p&gt;While superficially this may look quite short and simple, it hides a lot of complexity, both conceptual and computational. In this blog I will focus on the computational complexity.&lt;/p&gt;
&lt;p&gt;One thing I have swept under the rug in the equation above is that our system has not just one but many particles. Each of them has their own momentum and their own mass (although electrons all have the same mass, and for simplicity we can think of the nuclei all being the same, so having the same mass as well). So actually there should be a sum over all particles in the left most term.&lt;/p&gt;
&lt;p&gt;The momentum p is actually a derivative with respect to the position in quantum mechanics. More precisely, p = — i ℏ ∂, where ℏ is a very small number called Planck’s constant. Its smallness is the reason we can get through everyday life without thinking about quantum mechanics.&lt;/p&gt;
&lt;p&gt;This leads to something more problematic that I have also swept under the rug. Since the momentum is a derivative with respect to the position, acting on the wave function, and each particle has its own momentum, the wave function is not just a function of the position, it is a function of &lt;em&gt;the positions of every single particle&lt;/em&gt;. A block of material the size of your smartphone has about 10²⁵ electrons and nuclei, that’s a lot of arguments!&lt;/p&gt;
&lt;p&gt;The potential by the way is the Coulomb potential that charged particles exert on each other, so that also depends on all of the coordinates.&lt;/p&gt;
&lt;p&gt;To understand the computational complexity better it is insightful to look at how we would solve this numerically. Basically, the way most numerical methods go about solving a differential equation is to evaluate the equation itself on a certain number of points. This allows translating the differential equation into linear algebra, a matrix equation essentially of the form A x = b, where A is a matrix and b a vector that we both obtain from this procedure, and if we solve this for the vector x we get an approximation of the solution we’re after on this same set of points.&lt;/p&gt;
&lt;p&gt;How many points we need depends heavily on the details, but let’s say for simplicity the system is constrained to be on a single line, in other words space is only 1-dimensional. Let’s also restrict it to the interval between 0 and 1, and say we use K points, located at the positions x_i = i /K on the interval.&lt;/p&gt;
&lt;p&gt;Maybe K=20 could be sufficient in some very simple situation, so that doesn’t seem too bad. Remember though that every single particle has a position, and the wave function depends on all of them. So we need all &lt;em&gt;combinations&lt;/em&gt; of positions. So for a system with 10²⁵ particles that amounts to 20 &lt;em&gt;to the power&lt;/em&gt; 10²⁵ points.&lt;/p&gt;
&lt;p&gt;Another way to think about this is that if we add only a single electron to our system, we’d now need to solve the original system once for every possible location of the added electron. So in our example this would make the problem a 20 times larger, this is known as exponential complexity.&lt;/p&gt;
&lt;p&gt;These ridiculous numbers come from the combination of the exponential complexity of the problem with the already huge number of particles involved.&lt;/p&gt;
&lt;p&gt;This means that using this equation directly is only feasible for the smallest of systems, which really means practically only the hydrogen atom: a single nucleus with a single electron.&lt;/p&gt;
&lt;h2 id=&quot;approximations&quot;&gt;Approximations&lt;/h2&gt;
&lt;p&gt;Clearly then we need to do some approximations to this equation. I will illustrate conceptually a series of explanations that is very standard.&lt;/p&gt;
&lt;p&gt;The first and simplest step follows from the observation that the proton is much heavier than the electron, by a factor of about 1000. So even for hydrogen, whose nucleus is just a single proton, this is a significant factor, and for bigger cores the ratio is even larger, for example carbon contains 12 protons and neutrons (which have similar mass to protons), so their mass is about 10⁴ times that of an electron.&lt;/p&gt;
&lt;p&gt;Now heavy things tend to move more slowly than light things, this is the essence of what is called the &lt;em&gt;clamped nuclei approximation&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;From the point of view of an electron, on the typical timescale at which it itself moves, the nuclei are basically standing still. So assuming we know the positions of all the nuclei, we can treat those as fixed, and we can compute the force they exert on the electrons, and solve for the electrons separately.&lt;/p&gt;
&lt;p&gt;Conversely, from the point of view of a nucleus, by the time it itself moves, all the electrons will have had enough time to settle down to their equilibrium positions, into what is called their ground state.&lt;/p&gt;
&lt;p&gt;So this allows us to in a sense decouple the electrons from the nuclei. By itself this doesn’t give a significant improvement yet, so we need to simplify each part separately.&lt;/p&gt;
&lt;h3 id=&quot;the-electrons-density-functional-theory-dft&quot;&gt;The electrons: Density Functional Theory (DFT)&lt;/h3&gt;
&lt;p&gt;First we’ll look at the electrons. The difficulty of the problem lies in the interactions between them. If they were all independent it would be a much simpler problem, but clearly that is too crude of an approximation: they exert a Coulomb force on each other, so they are not independent. There are additional quantum mechanical effects that make them even less independent.&lt;/p&gt;
&lt;p&gt;What we &lt;em&gt;can&lt;/em&gt; do is to simplify all interactions to just interactions between each individual particle and some kind of averaged out particle, this is known as the mean field approximation. That is, we imagine that all of the electrons contribute to an average electron density. This density creates some potential energy that is felt by every electron. If that sounds recursive, that’s because it is. That is the price we pay for this approximation: we get a simpler problem, but we have to solve it many times until it is self consistent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;663&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_nYX_YbciZm8swnTDX1AJ5g-0177e0e1.Dg_ExSH0_2eueTy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Adapted in simplified form from Materials Modelling using Density Functional Theory, Feliciano Giustino.&lt;/p&gt;
&lt;p&gt;The process is illustrated in the figure above. Assume we know where the nuclei are, that gives a potential coming from the nuclei which is the input to the problem. Then we make a guess for this electron density, and use that to compute another potential, caused by the electrons themselves. Now we know the equation for every electron separately, which we can then solve independently from each other. But the total density should be the sum over the individual electron densities, so we compute that. Likely we won’t get the same as the density we started with, and we have to repeat this whole procedure until we do.&lt;/p&gt;
&lt;p&gt;This approach is called Density Functional Theory (DFT).&lt;/p&gt;
&lt;p&gt;What I’ve glossed over is what this potential is that each electron feels due to the total density. This is what gives this theory its name: the density functional. A functional is just what mathematicians call a function whose argument is itself a function. In this case the potential is a function of the electron density, which itself is a function of the position (a single position this time!).&lt;/p&gt;
&lt;p&gt;The interesting situation is that this whole “approximation” is known to be &lt;em&gt;exact&lt;/em&gt;. So at this point it is not an approximation at all, we do not lose any accuracy by doing this. There is a catch however. The theory only tells us that an appropriate density functional &lt;em&gt;exists&lt;/em&gt;, that makes it exact in any situation, but it does not tell us &lt;em&gt;what&lt;/em&gt; &lt;em&gt;it is&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So the actual approximation comes in the form of a guess of the density functional. Coming up with density functionals that perform well in certain situations is a whole field of research, and there is a whole zoo of density functionals out there.&lt;/p&gt;
&lt;p&gt;In terms of the computational complexity, the bottleneck lies in solving for the individual electrons, combined with the fact that we have to keep doing this until convergence. ==The time taken scales roughly with the third power of the number of electrons==. This is not great, but still much better than the exponential scaling we started with!&lt;/p&gt;
&lt;p&gt;Concretely, in the example where we used 10 grid points, going from 100 to 101 particles made using the Schrödinger equation directly 10 times slower, whereas DFT only becomes it 3% slower. You see how important these scalings of computational complexities are.&lt;/p&gt;
&lt;p&gt;In practice, whereas the Schrödinger equation could almost only be applied to the simplest of atoms, DFT can be used not just for single atoms, but for molecules and even multiple molecules together. It is still very expensive computationally though, not something you can run on your laptop, rather on a cluster and potentially having to wait a few weeks depending on the problem. From where we started though, this is already a big step up.&lt;/p&gt;
&lt;h3 id=&quot;the-nuclei-molecular-dynamics-md&quot;&gt;The nuclei: Molecular Dynamics (MD)&lt;/h3&gt;
&lt;p&gt;Now we turn back to the nuclei. Here the most important source of approximation is their mass. We already used this to decouple them from the electrons, as their mass is much larger. We can now use this in another way.&lt;/p&gt;
&lt;p&gt;Quantum mechanics only becomes necessary to describe a system if it is very small and light. For the movement of billiard balls on a pool table, we can fortunately just use classical mechanics. Formally this is a limit of quantum mechanics, prosaically known as the classical limit. Remember that in the Schrödinger equation I said that the momentum is actually a derivative with respect to the position, and the wave function encodes the probability of finding a particle somewhere. In the classical limit, the momentum goes back to being just a number, and the probability goes away, so that a particle is just described by its position and its momentum.&lt;/p&gt;
&lt;p&gt;Perhaps surprisingly, even for something as small as a nucleus, this is a good approximation. That is true for all but the smallest nuclei, such as hydrogen.&lt;/p&gt;
&lt;p&gt;This leads to a very simple system, where we have a potential coming from the electrons in addition to the Coulomb potential between the nuclei themselves. We obtain the forces just by taking the derivative of the potential, and with these forces we can evolve the nuclei in time.&lt;/p&gt;
&lt;p&gt;This approach is called &lt;em&gt;Molecular Dynamics (MD)&lt;/em&gt;, and is illustrated in the flowchart below.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;771&quot; height=&quot;393&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_0xhgXYMhL1XVf6LXSjUsMg-4bf2a6ea.D64hjsCJ_uEIJK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Adapted in simplified form from Materials Modelling using Density Functional Theory, Feliciano Giustino.&lt;/p&gt;
&lt;p&gt;Here again we had to introduce an unknown potential, in this case called the &lt;em&gt;interatomic potential&lt;/em&gt;. This captures the effect of the electrons on the nuclei. And again this is a priori unknown, so we have to guess it.&lt;/p&gt;
&lt;p&gt;In this case, there is a very natural candidate. We have just discussed a way to compute the electron density for any configuration of nuclei, namely DFT. So we could do that, and then simply use the Coulomb potential coming from this electron density. This is known as &lt;em&gt;ab-initio Molecular Dynamics (aiMD)&lt;/em&gt;, because we didn’t need to make another guess on a potential.&lt;/p&gt;
&lt;p&gt;The good thing about aiMD is that it is usually very accurate. However it requires a full DFT computation for every step of MD, making it very expensive computationally.&lt;/p&gt;
&lt;p&gt;The alternative is to come up with a simple form of the interatomic potential that is very fast to evaluate, and may be accurate for certain systems. Many such guesses exist.&lt;/p&gt;
&lt;p&gt;So here the computational complexity is very strongly dependent on the interatomic potential used, the other steps are usually negligible in comparison. Less expensive potentials can be used to simulate millions of atoms, for example in large proteins or crystal structures.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The diagram below summarizes what we have discussed.&lt;br&gt;
Through a series of physically motivated, and for many situations very accurate, approximations we have reduced the elegant but computationally intractable formulation of the Schrödinger equation into two parts: density functional theory (DFT) for the electrons and molecular dynamics (MD) for the nuclei.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1131&quot; height=&quot;894&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zwvn0X4z6_mG4zyQ4acULw-036d0626.CR6qfiv9_5UqRY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simplified illustration of the approximations done to go from quantum mechanics to Density Functional Theory (DFT) describing the electrons and Molecular Dynamics (MD) describing the nuclei. The clouds contain the ingredients that need to be specified to complete each theory.&lt;/p&gt;
&lt;p&gt;For both parts, this required the introduction of a priori unknown potentials: the density functional for DFT and the interatomic potential for MD. For both of these, a whole zoo of guesses exist, each of varying accuracy depending on the system at hand.&lt;/p&gt;
&lt;p&gt;This is where machine learning comes into the picture: rather than guessing these potentials ourselves, we can let a machine learning model learn them from data. We will discuss this in part 2 of this series.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_7i7tcw7VNt8GURTaOs1P6g-3a40b70c.3E80kelT.png" medium="image"/><author>Aron</author></item><item><title>Defining the roles of research software</title><link>https://blog.esciencecenter.nl/posts/2023-03-21---defining-the-roles-of-research-software</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-03-21---defining-the-roles-of-research-software</guid><description>&lt;p&gt;Examples: In the biochemistry realm, software is used for modeling molecules for use in a next-gen diagnostics or therapeutics: we want to design some molecule in software with some characteristics that we can experimentally validate later. Other examples include designing and modeling medical devices, devices to help with environmental monitoring or cleanup, CAD tools, or designing new compute hardware [suggested by Jonathan Romano].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-cf81259f.BB-6dpt2_Z1caRgP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-analyses-research-data&quot;&gt;Research software analyses research data&lt;/h2&gt;
&lt;p&gt;Research software is important for analysing research data as well. Sometimes this analysis is automated, such as data access and processing, model fitting, filtering, aggregation, and search. In other cases, the software supports and facilitates researchers in doing the analysis, for example, for qualitative data analysis. Other examples of software-supported analysis include natural language processing pipelines, data science tools (a concrete example could be &lt;a href=&quot;https://www.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt;), software notebooks (Jupyter), machine learning pipelines for classification and anomaly detection, etc.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-4d883c98.BN3fiPoa_ZN0wsg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-presents-research-results&quot;&gt;Research software presents research results&lt;/h2&gt;
&lt;p&gt;Research software can also be used to explain data, or to present research results. Scientific visualizations are a prime example, but so is software with the specific purpose of generating plots in research papers, or interactive visualizations on websites. Note that software is used to disseminate research in general, not only to researchers but also to a broader audience. It also is applicable for transitioning the research from academia to industrial applications. Having well-written software can help encourage the adoption of the research software in companies [suggested by Ian McInerney].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-21d8eeff.Bk9-_V2M_WE9Cv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-assembles-or-integrates-existing-components-into-a-working-whole&quot;&gt;Research software assembles or integrates existing components into a working whole&lt;/h2&gt;
&lt;p&gt;[suggested by Mark Hoemmen] An important, but often overlooked purpose of research software is integration and automation. This includes making efficient use of infrastructure, as well as repetition and scaling of experiments or analysis. A growing number of experimental systems (more than just an instrument) need to be run simultaneously in an orchestrated manner [suggested by Ian Cosden]. The research software performing these tasks is becoming ever more complex. Software supporting workflows, for example, can help in structured and reproducible automation and repetition.&lt;/p&gt;
&lt;p&gt;Another form of integration is the coupling of different computational models, combining computational models with data-driven models (AI-based surrogate models), potentially while assimilating observational data. Consider the construction of digital twins, for example. Specifically designed research software in the form of model-coupling frameworks can facilitate this, helping with the coupling and deployment, but also for example with the propagation of uncertainty quantification between models.&lt;/p&gt;
&lt;p&gt;A third class of integration software also deserves attention: Python or shell scripts that automate things, connect components and tools, or let data flow between different executables. Note that small scripts especially often are not adequately tested and maintained, even though they are critical to reproducing scientific results.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-0660c420.CcaN3mCe_ZS2bON.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-is-infrastructure-or-an-underlying-tool&quot;&gt;Research software is infrastructure or an underlying tool&lt;/h2&gt;
&lt;p&gt;[suggested by Jed Brown] In all areas of research, there is a role for “infrastructure software,” which sometimes is not unique to research-oriented organizations, but is heavily relied upon [suggested by Jordan Perr-Sauer]. Some lower-level software was created specifically for research (i.e., known as research software,) while other software infrastructure is meant for general utility and happens to be important for research (i.e., software in research.) Examples include compilers and programming languages, generic software libraries, code repositories, data repositories, and open source software in general. (Note that this is discipline-dependent, as a compiler would likely be research software within computer science research on programming languages.) As described by the Ford Foundation: “Free, publicly available source code is the infrastructure on which all of digital society relies. It is vital to the functioning of governments, private companies, and individual lives.” (See &lt;a href=&quot;https://www.fordfoundation.org/work/learning/research-reports/roads-and-bridges-the-unseen-labor-behind-our-digital-infrastructure/&quot;&gt;Roads and Bridges: The Unseen Labor Behind Our Digital Infrastructure / Ford Foundation&lt;/a&gt;.) It is equally vital to research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-ab3a3c28.BvdY8_PI_EgGJJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-facilitates-distinctively-research-oriented-collaboration&quot;&gt;Research software facilitates distinctively research-oriented collaboration&lt;/h2&gt;
&lt;p&gt;[suggested by Lee Liming] A lot of software and services have been specifically designed to facilitate research-oriented collaboration. Although sometimes not considered research software as such, this class certainly is important in research, and deserves a mention. With research becoming more and more open, team-based, interdisciplinary, collaborative, and inclusive (e.g., citizen science,) the usage and value of software facilitating collaboration is exploding. Examples include platforms to collaborate on software (GitHub, GitLab, Stack Overflow,) papers (Overleaf, ORCID, Zotero,) data (Zenodo, HUBzero, CyVerse,) computing (SciTokens, SciGaP,) software that is employed in citizen science [suggested by Chris Erdman] and many others.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;It is clear that there are many different types of research software, fulfilling many different roles and functions. This huge variety makes it hard to come up with a good classification that captures all aspects and does justice to all the hard work done by the developers of the software. Nevertheless, we hope that we have succeeded in providing a bit more insight into the value of research software, the importance of sustaining said software, and recognizing the people involved in developing the software.&lt;/p&gt;
&lt;p&gt;You can contact us at &lt;a href=&quot;mailto:R.vanNieuwpoort@esciencecenter.nl&quot;&gt;R.vanNieuwpoort@esciencecenter.nl&lt;/a&gt; and &lt;a href=&quot;mailto:%22Daniel%20S.%20Katz%22%20%3Cd.katz%40ieee.org%3E&quot;&gt;d.katz@ieee.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Copyright © 2023 Rob van Nieuwpoort, Daniel S. Katz. Distributed under the terms of the &lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/legalcode&quot;&gt;Creative Commons Attribution 4.0 License.&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 21 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Examples: In the biochemistry realm, software is used for modeling molecules for use in a next-gen diagnostics or therapeutics: we want to design some molecule in software with some characteristics that we can experimentally validate later. Other examples include designing and modeling medical devices, devices to help with environmental monitoring or cleanup, CAD tools, or designing new compute hardware [suggested by Jonathan Romano].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-cf81259f.BB-6dpt2_Z1caRgP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-analyses-research-data&quot;&gt;Research software analyses research data&lt;/h2&gt;
&lt;p&gt;Research software is important for analysing research data as well. Sometimes this analysis is automated, such as data access and processing, model fitting, filtering, aggregation, and search. In other cases, the software supports and facilitates researchers in doing the analysis, for example, for qualitative data analysis. Other examples of software-supported analysis include natural language processing pipelines, data science tools (a concrete example could be &lt;a href=&quot;https://www.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt;), software notebooks (Jupyter), machine learning pipelines for classification and anomaly detection, etc.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-4d883c98.BN3fiPoa_ZN0wsg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-presents-research-results&quot;&gt;Research software presents research results&lt;/h2&gt;
&lt;p&gt;Research software can also be used to explain data, or to present research results. Scientific visualizations are a prime example, but so is software with the specific purpose of generating plots in research papers, or interactive visualizations on websites. Note that software is used to disseminate research in general, not only to researchers but also to a broader audience. It also is applicable for transitioning the research from academia to industrial applications. Having well-written software can help encourage the adoption of the research software in companies [suggested by Ian McInerney].&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-21d8eeff.Bk9-_V2M_WE9Cv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-assembles-or-integrates-existing-components-into-a-working-whole&quot;&gt;Research software assembles or integrates existing components into a working whole&lt;/h2&gt;
&lt;p&gt;[suggested by Mark Hoemmen] An important, but often overlooked purpose of research software is integration and automation. This includes making efficient use of infrastructure, as well as repetition and scaling of experiments or analysis. A growing number of experimental systems (more than just an instrument) need to be run simultaneously in an orchestrated manner [suggested by Ian Cosden]. The research software performing these tasks is becoming ever more complex. Software supporting workflows, for example, can help in structured and reproducible automation and repetition.&lt;/p&gt;
&lt;p&gt;Another form of integration is the coupling of different computational models, combining computational models with data-driven models (AI-based surrogate models), potentially while assimilating observational data. Consider the construction of digital twins, for example. Specifically designed research software in the form of model-coupling frameworks can facilitate this, helping with the coupling and deployment, but also for example with the propagation of uncertainty quantification between models.&lt;/p&gt;
&lt;p&gt;A third class of integration software also deserves attention: Python or shell scripts that automate things, connect components and tools, or let data flow between different executables. Note that small scripts especially often are not adequately tested and maintained, even though they are critical to reproducing scientific results.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-0660c420.CcaN3mCe_ZS2bON.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-is-infrastructure-or-an-underlying-tool&quot;&gt;Research software is infrastructure or an underlying tool&lt;/h2&gt;
&lt;p&gt;[suggested by Jed Brown] In all areas of research, there is a role for “infrastructure software,” which sometimes is not unique to research-oriented organizations, but is heavily relied upon [suggested by Jordan Perr-Sauer]. Some lower-level software was created specifically for research (i.e., known as research software,) while other software infrastructure is meant for general utility and happens to be important for research (i.e., software in research.) Examples include compilers and programming languages, generic software libraries, code repositories, data repositories, and open source software in general. (Note that this is discipline-dependent, as a compiler would likely be research software within computer science research on programming languages.) As described by the Ford Foundation: “Free, publicly available source code is the infrastructure on which all of digital society relies. It is vital to the functioning of governments, private companies, and individual lives.” (See &lt;a href=&quot;https://www.fordfoundation.org/work/learning/research-reports/roads-and-bridges-the-unseen-labor-behind-our-digital-infrastructure/&quot;&gt;Roads and Bridges: The Unseen Labor Behind Our Digital Infrastructure / Ford Foundation&lt;/a&gt;.) It is equally vital to research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Defining the roles of research software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-ab3a3c28.BvdY8_PI_EgGJJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;research-software-facilitates-distinctively-research-oriented-collaboration&quot;&gt;Research software facilitates distinctively research-oriented collaboration&lt;/h2&gt;
&lt;p&gt;[suggested by Lee Liming] A lot of software and services have been specifically designed to facilitate research-oriented collaboration. Although sometimes not considered research software as such, this class certainly is important in research, and deserves a mention. With research becoming more and more open, team-based, interdisciplinary, collaborative, and inclusive (e.g., citizen science,) the usage and value of software facilitating collaboration is exploding. Examples include platforms to collaborate on software (GitHub, GitLab, Stack Overflow,) papers (Overleaf, ORCID, Zotero,) data (Zenodo, HUBzero, CyVerse,) computing (SciTokens, SciGaP,) software that is employed in citizen science [suggested by Chris Erdman] and many others.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;It is clear that there are many different types of research software, fulfilling many different roles and functions. This huge variety makes it hard to come up with a good classification that captures all aspects and does justice to all the hard work done by the developers of the software. Nevertheless, we hope that we have succeeded in providing a bit more insight into the value of research software, the importance of sustaining said software, and recognizing the people involved in developing the software.&lt;/p&gt;
&lt;p&gt;You can contact us at &lt;a href=&quot;mailto:R.vanNieuwpoort@esciencecenter.nl&quot;&gt;R.vanNieuwpoort@esciencecenter.nl&lt;/a&gt; and &lt;a href=&quot;mailto:%22Daniel%20S.%20Katz%22%20%3Cd.katz%40ieee.org%3E&quot;&gt;d.katz@ieee.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Copyright © 2023 Rob van Nieuwpoort, Daniel S. Katz. Distributed under the terms of the &lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/legalcode&quot;&gt;Creative Commons Attribution 4.0 License.&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/defining-the-roles-of-research-software-cf81259f.BB-6dpt2.jpg" medium="image"/><author>Rob van Nieuwpoort</author></item><item><title>The bike and the laptop</title><link>https://blog.esciencecenter.nl/posts/2023-03-16---the-bike-and-the-laptop</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-03-16---the-bike-and-the-laptop</guid><description>&lt;p&gt;Reflections on machines that help you&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JHZz_VHUJPss2HCC-d181572b.BCi5rSHQ_Z1hBWrq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Cale Weaver on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;students-pay-attention-sometimes&quot;&gt;Students pay attention (sometimes)&lt;/h2&gt;
&lt;p&gt;I was 17, my face was covered in acne and my hair was (awkwardly) long. I was sitting in a high school lecture room. For some reason, I still remember the topic of the day: the efficiency of different transportation means. There was this figure in our natural sciences book comparing several of them. Something along the lines of how much energy per kilometer and person was consumed by a plane, a car, a train, …&lt;/p&gt;
&lt;p&gt;Unsurprisingly, airplanes and cars were marked as less efficient than a bus or a train. The figure seemed pretty obvious and boring, but there was something that surprised me to the point I still remember it today: a bike was more efficient than… walking!&lt;/p&gt;
&lt;p&gt;A decade later, I came across an old pal from my high school years. Our paths diverged at university: he chose a career in computer science, and I did in physics. As often happens, we ended up talking about the (arguably) good-old teenage years. To my surprise, he mentioned the bicycle figure from that day’s lecture. He told me that it was that figure that convinced him to study computer science. I was puzzled… what? how?!&lt;/p&gt;
&lt;p&gt;His reasoning was the following: &lt;em&gt;“I immediately made the link to computers. If a bike can improve your legs’ efficiency, a computer can improve your brain’s”&lt;/em&gt;. Sounds a bit far-fetched… but I cannot disagree. Furthermore, 20 years and many lines of code later I want to stretch this analogy even further.&lt;/p&gt;
&lt;h2 id=&quot;laptops-and-bikes-a-far-fetched-analogy&quot;&gt;Laptops and bikes. A far-fetched analogy&lt;/h2&gt;
&lt;p&gt;Let’s start with two obvious statements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bike can help you move faster and more efficiently than you would achieve walking or running.&lt;/li&gt;
&lt;li&gt;A laptop (or any computer) can perform calculations and manage information in ways your brain cannot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But as Uncle Ben said to Peter Parker: &lt;em&gt;“with great power comes great responsibility”.&lt;/em&gt; I mean… superpowers come with their own dangers and disadvantages. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bike can increase your chances of getting involved in an accident, or, less dramatically, hurt your knees if you don’t properly adjust the saddle.&lt;/li&gt;
&lt;li&gt;A laptop can flood your brain with distractions and multitasking to the point of paralyzing your workflow. Less dramatically, you can use it in a way so inefficient that it just doesn’t scale, turning your tasks into a painful experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is another obvious, yet subtler similarity: both a bike and a laptop require learning how to use them. I remember very well how I learned to ride my bike as a kid: by driving in circles inside a parking lot with my dad running by my side. I was terrified, and he needed a lot of patience, but eventually, it worked out.&lt;/p&gt;
&lt;p&gt;Ironically, I don’t have such a clear and well-defined memory of how I learned to program and efficiently use my personal computer. Not my dad, nor anyone, seems to have been my mentor. I had to learn by myself. Too often, I had these &lt;em&gt;“Eureka”&lt;/em&gt; moments… shortly followed by a &lt;em&gt;“how in the world has nobody told me about this before?”.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;my-eureka-moments&quot;&gt;My “Eureka” moments&lt;/h2&gt;
&lt;p&gt;If my computer had been a bike, those &lt;em&gt;“Eureka”&lt;/em&gt; moments felt like discovering I had been riding it backward for years. Let me share some of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up an environment that works for you, that helps you keep focused and minimizes the time searching for information, maps to adapting the bike saddle to your length.&lt;/li&gt;
&lt;li&gt;Learning how to debug is like learning how to fix a punctured tire or a loose chain.&lt;/li&gt;
&lt;li&gt;Starting using version control is like installing a GPS holder on your bike. Now you know where you come from, and also where are you going!&lt;/li&gt;
&lt;li&gt;Getting started with unit tests is like learning, sometimes the hard way, that it is a good idea to wear a helmet if you are race-biking.&lt;/li&gt;
&lt;li&gt;Incorporating multiple best practices together, such as unit tests, linting, etc… is like discovering that your bike has different gears and you don’t need to suffer that much every time you want to climb a slope.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know. Laptops and bikes. A bit of an odd analogy but… what did you expect? After all, this is a Dutch Software center.&lt;/p&gt;
&lt;p&gt;PS: are you interested in experiencing some of those &lt;em&gt;“Eureka”&lt;/em&gt; moments? Take a look at our &lt;strong&gt;free&lt;/strong&gt; &lt;a href=&quot;https://www.esciencecenter.nl/training-materials/&quot;&gt;training materials&lt;/a&gt; and courses.&lt;/p&gt;</description><pubDate>Thu, 16 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Reflections on machines that help you&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JHZz_VHUJPss2HCC-d181572b.BCi5rSHQ_Z1hBWrq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Cale Weaver on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;students-pay-attention-sometimes&quot;&gt;Students pay attention (sometimes)&lt;/h2&gt;
&lt;p&gt;I was 17, my face was covered in acne and my hair was (awkwardly) long. I was sitting in a high school lecture room. For some reason, I still remember the topic of the day: the efficiency of different transportation means. There was this figure in our natural sciences book comparing several of them. Something along the lines of how much energy per kilometer and person was consumed by a plane, a car, a train, …&lt;/p&gt;
&lt;p&gt;Unsurprisingly, airplanes and cars were marked as less efficient than a bus or a train. The figure seemed pretty obvious and boring, but there was something that surprised me to the point I still remember it today: a bike was more efficient than… walking!&lt;/p&gt;
&lt;p&gt;A decade later, I came across an old pal from my high school years. Our paths diverged at university: he chose a career in computer science, and I did in physics. As often happens, we ended up talking about the (arguably) good-old teenage years. To my surprise, he mentioned the bicycle figure from that day’s lecture. He told me that it was that figure that convinced him to study computer science. I was puzzled… what? how?!&lt;/p&gt;
&lt;p&gt;His reasoning was the following: &lt;em&gt;“I immediately made the link to computers. If a bike can improve your legs’ efficiency, a computer can improve your brain’s”&lt;/em&gt;. Sounds a bit far-fetched… but I cannot disagree. Furthermore, 20 years and many lines of code later I want to stretch this analogy even further.&lt;/p&gt;
&lt;h2 id=&quot;laptops-and-bikes-a-far-fetched-analogy&quot;&gt;Laptops and bikes. A far-fetched analogy&lt;/h2&gt;
&lt;p&gt;Let’s start with two obvious statements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bike can help you move faster and more efficiently than you would achieve walking or running.&lt;/li&gt;
&lt;li&gt;A laptop (or any computer) can perform calculations and manage information in ways your brain cannot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But as Uncle Ben said to Peter Parker: &lt;em&gt;“with great power comes great responsibility”.&lt;/em&gt; I mean… superpowers come with their own dangers and disadvantages. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bike can increase your chances of getting involved in an accident, or, less dramatically, hurt your knees if you don’t properly adjust the saddle.&lt;/li&gt;
&lt;li&gt;A laptop can flood your brain with distractions and multitasking to the point of paralyzing your workflow. Less dramatically, you can use it in a way so inefficient that it just doesn’t scale, turning your tasks into a painful experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is another obvious, yet subtler similarity: both a bike and a laptop require learning how to use them. I remember very well how I learned to ride my bike as a kid: by driving in circles inside a parking lot with my dad running by my side. I was terrified, and he needed a lot of patience, but eventually, it worked out.&lt;/p&gt;
&lt;p&gt;Ironically, I don’t have such a clear and well-defined memory of how I learned to program and efficiently use my personal computer. Not my dad, nor anyone, seems to have been my mentor. I had to learn by myself. Too often, I had these &lt;em&gt;“Eureka”&lt;/em&gt; moments… shortly followed by a &lt;em&gt;“how in the world has nobody told me about this before?”.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;my-eureka-moments&quot;&gt;My “Eureka” moments&lt;/h2&gt;
&lt;p&gt;If my computer had been a bike, those &lt;em&gt;“Eureka”&lt;/em&gt; moments felt like discovering I had been riding it backward for years. Let me share some of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up an environment that works for you, that helps you keep focused and minimizes the time searching for information, maps to adapting the bike saddle to your length.&lt;/li&gt;
&lt;li&gt;Learning how to debug is like learning how to fix a punctured tire or a loose chain.&lt;/li&gt;
&lt;li&gt;Starting using version control is like installing a GPS holder on your bike. Now you know where you come from, and also where are you going!&lt;/li&gt;
&lt;li&gt;Getting started with unit tests is like learning, sometimes the hard way, that it is a good idea to wear a helmet if you are race-biking.&lt;/li&gt;
&lt;li&gt;Incorporating multiple best practices together, such as unit tests, linting, etc… is like discovering that your bike has different gears and you don’t need to suffer that much every time you want to climb a slope.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know. Laptops and bikes. A bit of an odd analogy but… what did you expect? After all, this is a Dutch Software center.&lt;/p&gt;
&lt;p&gt;PS: are you interested in experiencing some of those &lt;em&gt;“Eureka”&lt;/em&gt; moments? Take a look at our &lt;strong&gt;free&lt;/strong&gt; &lt;a href=&quot;https://www.esciencecenter.nl/training-materials/&quot;&gt;training materials&lt;/a&gt; and courses.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_JHZz_VHUJPss2HCC-d181572b.BCi5rSHQ.webp" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>eWaterCycle: Anecdotes of a FAIR expedition</title><link>https://blog.esciencecenter.nl/posts/2023-03-09---ewatercycle-anecdotes-of-a-fair-expedition</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-03-09---ewatercycle-anecdotes-of-a-fair-expedition</guid><description>&lt;p&gt;The journey of a group of hydrologists and research software engineers after FAIRer research software.&lt;/p&gt;
&lt;h2 id=&quot;a-grand-challenge&quot;&gt;A grand challenge&lt;/h2&gt;
&lt;p&gt;This story begins in April, 2019. A group of hydrologists and research software engineers had &lt;a href=&quot;https://www.lorentzcenter.nl/fair-hydrological-models-automated-comparisons-using-escience-tools.html&quot;&gt;gathered in Leiden&lt;/a&gt; to discuss one of the grand challenges in contemporary research: &lt;em&gt;how to make our scientific endeavors reproducible and easier to reuse?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The problem was obvious. Hydrological modeling studies had grown complex. So complex, in fact, that it was virtually impossible to reproduce them from scratch. The only way to keep up was to maintain your own virtual research environment, with your own model, your own copy of input data, and your own computational facilities.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_VVhO3G5VtX4HqlFP6LaJvQ-1f1f952a.eX_J8oUt_Z1p0soh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;An unFAIR landscape: silo structure prohibits the exchange of models and their input/output data&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Side note: a characteristic figure in hydrological modeling studies is a hydrograph. This chart displays river discharge over time. To produce it, you simulate how the precipitation over a certain region propagates through the landscape: seeping into the soils, collecting into rivers, and flowing towards the sea. Hydrographs provide insight in the hydrology of a certain area and can serve to evaluate (and compare) the quality of your simulations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Despite the recent push towards more openly sharing datasets and model source code, this had minimal effect. Even with access to the source code, it remained difficult to compile each others’ models. And because modeling choices had diverged, it was not straightforward to swap out components or input datasets, or simply compare outputs of different models. Something had to change.&lt;/p&gt;
&lt;p&gt;A few years earlier, a set of &lt;a href=&quot;https://www.go-fair.org/fair-principles/&quot;&gt;“FAIR” principles&lt;/a&gt; had been formulated with the ultimate goal of making scientific datasets &lt;em&gt;Findable, Accessible, Interoperable, and Reusable&lt;/em&gt;. Intuitively, these concepts could be applied to other aspects of the research process as well. It was the right idea at the right time. Thus &lt;a href=&quot;https://www.lorentzcenter.nl/fair-hydrological-models-automated-comparisons-using-escience-tools.html&quot;&gt;the workshop in Leiden&lt;/a&gt; marked the start of our FAIR expedition.&lt;/p&gt;
&lt;h2 id=&quot;fair-models&quot;&gt;FAIR models&lt;/h2&gt;
&lt;p&gt;The first uncharted territory was that of models, the core substance of every modeling study. Hydrological models come in many flavours. They differ in the physical processes they include or in the way in which they describe these processes mathematically. They use different methods to discretize the equations, and different programming languages to implement them. How could such diversity ever be more FAIR?&lt;/p&gt;
&lt;p&gt;We found there was an interesting initiative from Boulder, Colorado: the &lt;a href=&quot;https://csdms.colorado.edu/wiki/BMI&quot;&gt;&lt;em&gt;Basic Model Interface&lt;/em&gt;&lt;/a&gt; (BMI). Even if models work differently under the hood, we could standardize the way users interact with them. Such a familiar interface would make it easier to reuse and exchange each others’ models.&lt;/p&gt;
&lt;p&gt;At that time, this standard had not been broadly embraced. But we were ambitious and we wanted to set an example of FAIR scientific conduct. So we decided to complement the participating models with a BMI. To top it off, we packaged them in Docker containers and made software to use them in a Python scripting environment.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CO5kblmYtR5qGYAcvuIbHg-3a474f0c.CybOecgc_ZX6AYk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Different models, but to the user they look the same. We decided to embrace Basic Model Interface (BMI).&lt;/p&gt;
&lt;h2 id=&quot;fair-forcing-data&quot;&gt;FAIR forcing data&lt;/h2&gt;
&lt;p&gt;Next, we entered the realm of forcing data: the weather that’s fed into the models. Here we discovered a very good standard with the only downside that it didn’t quite fit. Generations of coordinated climate research programmes had established conventions known as &lt;a href=&quot;https://cfconventions.org/&quot;&gt;CF&lt;/a&gt; and &lt;a href=&quot;https://pcmdi.llnl.gov/software/cmorTable/index.html&quot;&gt;CMOR&lt;/a&gt;. They describe how climate model output should be stored, including variable names, filename patterns, file formats, units, et cetera.&lt;/p&gt;
&lt;p&gt;There was also this software called &lt;a href=&quot;https://docs.esmvaltool.org/en/latest/&quot;&gt;ESMValTool&lt;/a&gt; that made working with these datasets more FAIR. You describe your workflow in relatively plain language, and the software takes care of finding the data and executing the specified tasks, such as cropping out a specific area. What’s great is that you can easily share your “recipes” so others can repeat and build upon your work.&lt;/p&gt;
&lt;p&gt;Another great aspect of ESMValTool is its extensibility. By writing so-called &lt;em&gt;CMORizers&lt;/em&gt;, we could “teach” the software to also understand the other datasets we wanted to support. At the other end of the workflow, we could write custom code snippets to incorporate model-specific quirks, such as deviating file formats. This allowed us to adopt the existing standards and software for our FAIR hydrological forcing module.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pCv3lwGmPzeENax9hIhuww-3a4f874f.GGg5g29G_hkEqR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;ESMValTool’s extensibility allowed us to adopt it for our FAIR hydrological forcing data module.&lt;/p&gt;
&lt;h2 id=&quot;fair-parameter-sets&quot;&gt;FAIR parameter sets?!&lt;/h2&gt;
&lt;p&gt;So far, our journey had been quite a feat. We’d seen adopting a standard even if it wasn’t widespread, and being pragmatic if it didn’t quite fit. But what if there is no suitable standard?&lt;/p&gt;
&lt;p&gt;We would soon discover it as we set foot in the land of parameter sets: home to all kinds of maps, from land use, soil types, elevation, you name it. We had envisioned and half-expected something similar to ESMValTool. But our disappointment grew quickly. Apparently, there was no clear authoritative source of parameter sets. No controlled vocabulary, a wild growth of file formats and software to manipulate them, and no consensus on what to use in hydrological models. We felt disoriented and washed out.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PKcxGe1AcIoAu1_Wf44XAw-561d6116.29N-g9by_Z1g83p1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;By imagining how we would use a standard if there had been one, we were able to “pretend” it exists.&lt;/p&gt;
&lt;p&gt;So we entered upon a game trail. Out of the control and out of time, we headed straight toward our goal: being able to load parameter sets from within our unified modeling environment. We quickly collected example parameter sets for our set of models and dreamed up a minimal set of metadata to describe them: a name, a directory path, the name of a configuration file, and the name of the model for which it was to be used. That was all we needed to load an existing parameter set that we had magically obtained. We added a DOI field, empty for now, so we could eventually publish the datasets and retrieve them again. FAIR enough.&lt;/p&gt;
&lt;h2 id=&quot;a-fair-platform&quot;&gt;A FAIR platform&lt;/h2&gt;
&lt;p&gt;Anecdotes are nice, but experience is nicer. To help you get started, we collected our models, forcing data, parameter sets, and software stack on a dedicated platform. Even if all these components are more FAIR than they’ve ever been, it’s still a bit of work to collect and configure all that. Clearly, we haven’t yet reached transcendence.&lt;/p&gt;
&lt;p&gt;The eWaterCycle demo platform gives a taste of what FAIR can bring in terms of user experience. Simply visit the URL, log in with your credentials, and enter a JupyterLab environment that is ready to go. On top of it, we build a graphical explorer where you can set up a basic experiment with a few clicks — a corresponding notebook will be generated and you can start modeling right away. Notebooks are great for exploratory research and disseminating experiments. Also, there are nice tools to help with things like auto-formatting and version control.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-2EFy2k5Gwj7OXMkZgwQGg-957d5fa9.DjOcac-q_ZM41jT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A dedicated platform makes all of its components more FAIR and helps to show the merits of FAIR&lt;/p&gt;
&lt;p&gt;While the platform is not necessarily FAIR in itself, we find that it greatly enhances the FAIRness of its components. Technical aspects are hidden from the users, so they can focus on conducting experiments. Models and parameter sets can easily be discovered and used. Our guidelines for adding new models or parameter sets are like a step-by-step guide to making them (more) FAIR.&lt;/p&gt;
&lt;p&gt;With eWaterCycle we hope to inspire a new paradigm for conducting hydrological modeling studies. The flowchart draws our FAIR journey in retrospect. It contains valuable insights, but it is by no means an all-encompassing wisdom chart. Now it is time for your expedition.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_6MXyXLQhvkjN7PL6Jp4gcw-79a28e46.DabdNPLv_Z2hClb9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our FAIR journey in retrospect (not an all-encompassing wisdom chart)&lt;/p&gt;
&lt;p&gt;For more information on eWaterCycle, see the &lt;a href=&quot;https://doi.org/10.5194/gmd-15-5371-2022&quot;&gt;publication in Geoscientific Model Development&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 09 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The journey of a group of hydrologists and research software engineers after FAIRer research software.&lt;/p&gt;
&lt;h2 id=&quot;a-grand-challenge&quot;&gt;A grand challenge&lt;/h2&gt;
&lt;p&gt;This story begins in April, 2019. A group of hydrologists and research software engineers had &lt;a href=&quot;https://www.lorentzcenter.nl/fair-hydrological-models-automated-comparisons-using-escience-tools.html&quot;&gt;gathered in Leiden&lt;/a&gt; to discuss one of the grand challenges in contemporary research: &lt;em&gt;how to make our scientific endeavors reproducible and easier to reuse?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The problem was obvious. Hydrological modeling studies had grown complex. So complex, in fact, that it was virtually impossible to reproduce them from scratch. The only way to keep up was to maintain your own virtual research environment, with your own model, your own copy of input data, and your own computational facilities.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_VVhO3G5VtX4HqlFP6LaJvQ-1f1f952a.eX_J8oUt_Z1p0soh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;An unFAIR landscape: silo structure prohibits the exchange of models and their input/output data&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Side note: a characteristic figure in hydrological modeling studies is a hydrograph. This chart displays river discharge over time. To produce it, you simulate how the precipitation over a certain region propagates through the landscape: seeping into the soils, collecting into rivers, and flowing towards the sea. Hydrographs provide insight in the hydrology of a certain area and can serve to evaluate (and compare) the quality of your simulations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Despite the recent push towards more openly sharing datasets and model source code, this had minimal effect. Even with access to the source code, it remained difficult to compile each others’ models. And because modeling choices had diverged, it was not straightforward to swap out components or input datasets, or simply compare outputs of different models. Something had to change.&lt;/p&gt;
&lt;p&gt;A few years earlier, a set of &lt;a href=&quot;https://www.go-fair.org/fair-principles/&quot;&gt;“FAIR” principles&lt;/a&gt; had been formulated with the ultimate goal of making scientific datasets &lt;em&gt;Findable, Accessible, Interoperable, and Reusable&lt;/em&gt;. Intuitively, these concepts could be applied to other aspects of the research process as well. It was the right idea at the right time. Thus &lt;a href=&quot;https://www.lorentzcenter.nl/fair-hydrological-models-automated-comparisons-using-escience-tools.html&quot;&gt;the workshop in Leiden&lt;/a&gt; marked the start of our FAIR expedition.&lt;/p&gt;
&lt;h2 id=&quot;fair-models&quot;&gt;FAIR models&lt;/h2&gt;
&lt;p&gt;The first uncharted territory was that of models, the core substance of every modeling study. Hydrological models come in many flavours. They differ in the physical processes they include or in the way in which they describe these processes mathematically. They use different methods to discretize the equations, and different programming languages to implement them. How could such diversity ever be more FAIR?&lt;/p&gt;
&lt;p&gt;We found there was an interesting initiative from Boulder, Colorado: the &lt;a href=&quot;https://csdms.colorado.edu/wiki/BMI&quot;&gt;&lt;em&gt;Basic Model Interface&lt;/em&gt;&lt;/a&gt; (BMI). Even if models work differently under the hood, we could standardize the way users interact with them. Such a familiar interface would make it easier to reuse and exchange each others’ models.&lt;/p&gt;
&lt;p&gt;At that time, this standard had not been broadly embraced. But we were ambitious and we wanted to set an example of FAIR scientific conduct. So we decided to complement the participating models with a BMI. To top it off, we packaged them in Docker containers and made software to use them in a Python scripting environment.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CO5kblmYtR5qGYAcvuIbHg-3a474f0c.CybOecgc_ZX6AYk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Different models, but to the user they look the same. We decided to embrace Basic Model Interface (BMI).&lt;/p&gt;
&lt;h2 id=&quot;fair-forcing-data&quot;&gt;FAIR forcing data&lt;/h2&gt;
&lt;p&gt;Next, we entered the realm of forcing data: the weather that’s fed into the models. Here we discovered a very good standard with the only downside that it didn’t quite fit. Generations of coordinated climate research programmes had established conventions known as &lt;a href=&quot;https://cfconventions.org/&quot;&gt;CF&lt;/a&gt; and &lt;a href=&quot;https://pcmdi.llnl.gov/software/cmorTable/index.html&quot;&gt;CMOR&lt;/a&gt;. They describe how climate model output should be stored, including variable names, filename patterns, file formats, units, et cetera.&lt;/p&gt;
&lt;p&gt;There was also this software called &lt;a href=&quot;https://docs.esmvaltool.org/en/latest/&quot;&gt;ESMValTool&lt;/a&gt; that made working with these datasets more FAIR. You describe your workflow in relatively plain language, and the software takes care of finding the data and executing the specified tasks, such as cropping out a specific area. What’s great is that you can easily share your “recipes” so others can repeat and build upon your work.&lt;/p&gt;
&lt;p&gt;Another great aspect of ESMValTool is its extensibility. By writing so-called &lt;em&gt;CMORizers&lt;/em&gt;, we could “teach” the software to also understand the other datasets we wanted to support. At the other end of the workflow, we could write custom code snippets to incorporate model-specific quirks, such as deviating file formats. This allowed us to adopt the existing standards and software for our FAIR hydrological forcing module.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pCv3lwGmPzeENax9hIhuww-3a4f874f.GGg5g29G_hkEqR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;ESMValTool’s extensibility allowed us to adopt it for our FAIR hydrological forcing data module.&lt;/p&gt;
&lt;h2 id=&quot;fair-parameter-sets&quot;&gt;FAIR parameter sets?!&lt;/h2&gt;
&lt;p&gt;So far, our journey had been quite a feat. We’d seen adopting a standard even if it wasn’t widespread, and being pragmatic if it didn’t quite fit. But what if there is no suitable standard?&lt;/p&gt;
&lt;p&gt;We would soon discover it as we set foot in the land of parameter sets: home to all kinds of maps, from land use, soil types, elevation, you name it. We had envisioned and half-expected something similar to ESMValTool. But our disappointment grew quickly. Apparently, there was no clear authoritative source of parameter sets. No controlled vocabulary, a wild growth of file formats and software to manipulate them, and no consensus on what to use in hydrological models. We felt disoriented and washed out.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PKcxGe1AcIoAu1_Wf44XAw-561d6116.29N-g9by_Z1g83p1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;By imagining how we would use a standard if there had been one, we were able to “pretend” it exists.&lt;/p&gt;
&lt;p&gt;So we entered upon a game trail. Out of the control and out of time, we headed straight toward our goal: being able to load parameter sets from within our unified modeling environment. We quickly collected example parameter sets for our set of models and dreamed up a minimal set of metadata to describe them: a name, a directory path, the name of a configuration file, and the name of the model for which it was to be used. That was all we needed to load an existing parameter set that we had magically obtained. We added a DOI field, empty for now, so we could eventually publish the datasets and retrieve them again. FAIR enough.&lt;/p&gt;
&lt;h2 id=&quot;a-fair-platform&quot;&gt;A FAIR platform&lt;/h2&gt;
&lt;p&gt;Anecdotes are nice, but experience is nicer. To help you get started, we collected our models, forcing data, parameter sets, and software stack on a dedicated platform. Even if all these components are more FAIR than they’ve ever been, it’s still a bit of work to collect and configure all that. Clearly, we haven’t yet reached transcendence.&lt;/p&gt;
&lt;p&gt;The eWaterCycle demo platform gives a taste of what FAIR can bring in terms of user experience. Simply visit the URL, log in with your credentials, and enter a JupyterLab environment that is ready to go. On top of it, we build a graphical explorer where you can set up a basic experiment with a few clicks — a corresponding notebook will be generated and you can start modeling right away. Notebooks are great for exploratory research and disseminating experiments. Also, there are nice tools to help with things like auto-formatting and version control.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-2EFy2k5Gwj7OXMkZgwQGg-957d5fa9.DjOcac-q_ZM41jT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A dedicated platform makes all of its components more FAIR and helps to show the merits of FAIR&lt;/p&gt;
&lt;p&gt;While the platform is not necessarily FAIR in itself, we find that it greatly enhances the FAIRness of its components. Technical aspects are hidden from the users, so they can focus on conducting experiments. Models and parameter sets can easily be discovered and used. Our guidelines for adding new models or parameter sets are like a step-by-step guide to making them (more) FAIR.&lt;/p&gt;
&lt;p&gt;With eWaterCycle we hope to inspire a new paradigm for conducting hydrological modeling studies. The flowchart draws our FAIR journey in retrospect. It contains valuable insights, but it is by no means an all-encompassing wisdom chart. Now it is time for your expedition.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_6MXyXLQhvkjN7PL6Jp4gcw-79a28e46.DabdNPLv_Z2hClb9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our FAIR journey in retrospect (not an all-encompassing wisdom chart)&lt;/p&gt;
&lt;p&gt;For more information on eWaterCycle, see the &lt;a href=&quot;https://doi.org/10.5194/gmd-15-5371-2022&quot;&gt;publication in Geoscientific Model Development&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_VVhO3G5VtX4HqlFP6LaJvQ-1f1f952a.eX_J8oUt.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Minds for Mobile Agents: speeding up social distancing simulations</title><link>https://blog.esciencecenter.nl/posts/2023-03-02---minds-for-mobile-agents-speeding-up-social-distancing-simula</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-03-02---minds-for-mobile-agents-speeding-up-social-distancing-simula</guid><description>&lt;p&gt;&lt;em&gt;This blog post is written by University of Amsterdam researchers Charlotte Tanis and Andrew Heathcote, who participated in the Small-Scale Initiative for Software Performance Optimization. Their team’s project: predicting the movement patterns of pedestrians, which can help governments and policy-makers in pandemics and crisis situations.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;928&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_b6gDKVX25ZdxuAHl-4d41c263.CMh6ba9d_SyxMU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Forest Simon on Unsplash&lt;/p&gt;
&lt;p&gt;During the COVID-19 pandemic, a group of researchers from the University of Amsterdam started the &lt;a href=&quot;https://dataversuscorona.com/&quot;&gt;Data vs. Corona&lt;/a&gt; initiative. Their mission: to create a community of data scientists who make their skills available in society’s battle against the coronavirus. One of the projects that emerged out of the initiative was our &lt;a href=&quot;https://www.ampl-psych.com/projects/minds-for-mobile-agents/&quot;&gt;Minds for Mobile Agents&lt;/a&gt; project. Minds for Mobile Agents uses real-life data to help governments implement effective physical distancing guidelines. In order to do so, it is key to accurately simulate, explain and predict how individuals move when going grocery shopping or visiting restaurants.&lt;/p&gt;
&lt;p&gt;Understanding how individuals move in such so-called &lt;em&gt;low to medium density settings&lt;/em&gt; has much wider applications than social distancing measures alone. Security authorities benefit from research like this too, because it helps them make realistic vulnerability assessments in crisis situations. This improves the safety and preparedness in the case of, for example, attacks on public spaces. &lt;a href=&quot;https://www.telegraaf.nl/nieuws/1822382862/supermarktproef-stoplicht-bij-ingang-paaseitjesbij-%20%20uitgang%20and%20https:/nos.nl/video/2374282-hoe-houd-je-het-beste-afstand-in-de-supermarktdat-%20%20onderzoeken-ze-in-veldhoven&quot;&gt;The elaborate media coverage&lt;/a&gt; we received in national media during our initial experiments showed that understanding and predicting pedestrian behavior in small but complex environments is a topic of great current interest.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_fAhjsTdZBGzQPQvc-92fcaac7.K954mqDK_Z2wFrtw.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Franki Chamaki on Unsplash&lt;/p&gt;
&lt;p&gt;Our research objective is to make accurate predictions about the movement patterns of a group of individuals, which means that we need to be able to simulate the fact that individuals move around in their environment for different reasons. That is exactly what the mathematical “Predictive Pedestrian” model does. The model simulates a set of pedestrians in a supermarket or restaurant and predicts each simulated pedestrian’s step choices. The choices a simulated pedestrian makes are based on predictions that simulated pedestrian would make about the behaviour of other pedestrians in the space. Each agent’s “mind” can be flexibly specified using parameters that have clear psychological interpretations, making the behaviour of the model explainable.&lt;/p&gt;
&lt;p&gt;Our team incorporated complex series of goals and individual differences in the way in which pedestrians move around and interact with each other according to the model (see &lt;a href=&quot;https://www.ampl-psych.com/projects/minds-for-mobile-agents/&quot;&gt;here&lt;/a&gt; for background and illustrations). As you may be able to imagine, the computational cost associated with these simulations is high. Our approach requires us to develop methods that can estimate the distributions of many model parameters that can characterize realistic scenarios.&lt;/p&gt;
&lt;h3 id=&quot;escience-center-support&quot;&gt;eScience Center support&lt;/h3&gt;
&lt;p&gt;We participated in the eScience Center Small-Scale Initiative (SSI) in Software Performance Optimization. The goal of our SSI project was to optimize the computational efficiency of the Predictive Pedestrian model. Our team worked together with eScience Center Research Software Engineers Eva Viviani and Malte Luken. We started off profiling the Predictive Pedestrian model code to identify computational bottlenecks. We then ported a selection of functions to &lt;a href=&quot;https://github.com/m4ma&quot;&gt;an R package we dubbed M4MA&lt;/a&gt;, and added the option to perform the associated computations in C++ through the &lt;a href=&quot;https://www.rcpp.org/&quot;&gt;Rcpp&lt;/a&gt; framework. This resulted in the code running approximately ten times faster. The M4MA package puts us one step closer to realizing the promise of the Predictive Pedestrian model: to quantitatively characterize and simulate pedestrian behaviour in a wide range of scenarios in real time.&lt;/p&gt;
&lt;p&gt;In the next step of the project, the M4MA package will be used to analyse the results of experiments in various settings using ultra-wide band technology to precisely measure the locations of real pedestrians, and to guide the design of new experiments. The experimental results will be used to estimate the model parameters, enabling the first thorough investigation of when individual differences in pedestrian behavior matter and how they change across different scenarios. Models that are calibrated for these environments offer exciting possibilities: they may result in more accurate simulations of how people move around, and can provide meaningful data that can be used to make changes without needing expensive calibration studies in every case. This in turn facilitates policy advice and the better design of environments that achieve a wide variety of goals related to, for example, safety (e.g., maintaining physical distance) and commerce (e.g., encouraging smooth flows through targeted areas).&lt;/p&gt;
&lt;p&gt;Edited by &lt;em&gt;Lieke de Boer.&lt;/em&gt; Thanks to &lt;em&gt;Eva Viviani&lt;/em&gt; for fact checking.&lt;/p&gt;</description><pubDate>Thu, 02 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog post is written by University of Amsterdam researchers Charlotte Tanis and Andrew Heathcote, who participated in the Small-Scale Initiative for Software Performance Optimization. Their team’s project: predicting the movement patterns of pedestrians, which can help governments and policy-makers in pandemics and crisis situations.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;928&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_b6gDKVX25ZdxuAHl-4d41c263.CMh6ba9d_SyxMU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Forest Simon on Unsplash&lt;/p&gt;
&lt;p&gt;During the COVID-19 pandemic, a group of researchers from the University of Amsterdam started the &lt;a href=&quot;https://dataversuscorona.com/&quot;&gt;Data vs. Corona&lt;/a&gt; initiative. Their mission: to create a community of data scientists who make their skills available in society’s battle against the coronavirus. One of the projects that emerged out of the initiative was our &lt;a href=&quot;https://www.ampl-psych.com/projects/minds-for-mobile-agents/&quot;&gt;Minds for Mobile Agents&lt;/a&gt; project. Minds for Mobile Agents uses real-life data to help governments implement effective physical distancing guidelines. In order to do so, it is key to accurately simulate, explain and predict how individuals move when going grocery shopping or visiting restaurants.&lt;/p&gt;
&lt;p&gt;Understanding how individuals move in such so-called &lt;em&gt;low to medium density settings&lt;/em&gt; has much wider applications than social distancing measures alone. Security authorities benefit from research like this too, because it helps them make realistic vulnerability assessments in crisis situations. This improves the safety and preparedness in the case of, for example, attacks on public spaces. &lt;a href=&quot;https://www.telegraaf.nl/nieuws/1822382862/supermarktproef-stoplicht-bij-ingang-paaseitjesbij-%20%20uitgang%20and%20https:/nos.nl/video/2374282-hoe-houd-je-het-beste-afstand-in-de-supermarktdat-%20%20onderzoeken-ze-in-veldhoven&quot;&gt;The elaborate media coverage&lt;/a&gt; we received in national media during our initial experiments showed that understanding and predicting pedestrian behavior in small but complex environments is a topic of great current interest.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_fAhjsTdZBGzQPQvc-92fcaac7.K954mqDK_Z2wFrtw.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Franki Chamaki on Unsplash&lt;/p&gt;
&lt;p&gt;Our research objective is to make accurate predictions about the movement patterns of a group of individuals, which means that we need to be able to simulate the fact that individuals move around in their environment for different reasons. That is exactly what the mathematical “Predictive Pedestrian” model does. The model simulates a set of pedestrians in a supermarket or restaurant and predicts each simulated pedestrian’s step choices. The choices a simulated pedestrian makes are based on predictions that simulated pedestrian would make about the behaviour of other pedestrians in the space. Each agent’s “mind” can be flexibly specified using parameters that have clear psychological interpretations, making the behaviour of the model explainable.&lt;/p&gt;
&lt;p&gt;Our team incorporated complex series of goals and individual differences in the way in which pedestrians move around and interact with each other according to the model (see &lt;a href=&quot;https://www.ampl-psych.com/projects/minds-for-mobile-agents/&quot;&gt;here&lt;/a&gt; for background and illustrations). As you may be able to imagine, the computational cost associated with these simulations is high. Our approach requires us to develop methods that can estimate the distributions of many model parameters that can characterize realistic scenarios.&lt;/p&gt;
&lt;h3 id=&quot;escience-center-support&quot;&gt;eScience Center support&lt;/h3&gt;
&lt;p&gt;We participated in the eScience Center Small-Scale Initiative (SSI) in Software Performance Optimization. The goal of our SSI project was to optimize the computational efficiency of the Predictive Pedestrian model. Our team worked together with eScience Center Research Software Engineers Eva Viviani and Malte Luken. We started off profiling the Predictive Pedestrian model code to identify computational bottlenecks. We then ported a selection of functions to &lt;a href=&quot;https://github.com/m4ma&quot;&gt;an R package we dubbed M4MA&lt;/a&gt;, and added the option to perform the associated computations in C++ through the &lt;a href=&quot;https://www.rcpp.org/&quot;&gt;Rcpp&lt;/a&gt; framework. This resulted in the code running approximately ten times faster. The M4MA package puts us one step closer to realizing the promise of the Predictive Pedestrian model: to quantitatively characterize and simulate pedestrian behaviour in a wide range of scenarios in real time.&lt;/p&gt;
&lt;p&gt;In the next step of the project, the M4MA package will be used to analyse the results of experiments in various settings using ultra-wide band technology to precisely measure the locations of real pedestrians, and to guide the design of new experiments. The experimental results will be used to estimate the model parameters, enabling the first thorough investigation of when individual differences in pedestrian behavior matter and how they change across different scenarios. Models that are calibrated for these environments offer exciting possibilities: they may result in more accurate simulations of how people move around, and can provide meaningful data that can be used to make changes without needing expensive calibration studies in every case. This in turn facilitates policy advice and the better design of environments that achieve a wide variety of goals related to, for example, safety (e.g., maintaining physical distance) and commerce (e.g., encouraging smooth flows through targeted areas).&lt;/p&gt;
&lt;p&gt;Edited by &lt;em&gt;Lieke de Boer.&lt;/em&gt; Thanks to &lt;em&gt;Eva Viviani&lt;/em&gt; for fact checking.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_b6gDKVX25ZdxuAHl-4d41c263.CMh6ba9d.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>The hidden dangers of using XAI carelessly</title><link>https://blog.esciencecenter.nl/posts/2023-02-23---the-hidden-dangers-of-using-xai-carelessly</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-02-23---the-hidden-dangers-of-using-xai-carelessly</guid><description>&lt;p&gt;&lt;em&gt;Congrats! Your ML model is finally XAI-ready. But before you start patting yourself on the back, have you pre-processed your features? If so, watch out for those SHAP values, they might have been “processed”, too&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2097&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_s3LlcenurDp-MxDA-e6102adf.BIelJepI_Z2p3GPn.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mind the gap. Photo by Sammie Chaffin on Unsplash&lt;/p&gt;
&lt;p&gt;A very desirable property of machine learning models is explainability. This means being able to attribute the predictions to each input feature. SHAP (SHapley Additive exPlanations) is one of the most popular methods for getting feature importance, and it’s pretty much the state-of-the-art in explainable AI. It’s so popular because (1) it doesn’t matter what kind of model you use (random forest, SVM, neural network), (2) in certain aspects unifies other explainability methods, and (3) it has some great properties, including &lt;em&gt;additivity:&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sum of the SHAP values of each feature for a given observation gives the difference between the full model prediction and the prediction of the null model (a model without features).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a crucial property that makes SHAP believable. If the numbers from an explainability method have no physical meaning, no one is going to believe the method explains the model.&lt;/p&gt;
&lt;p&gt;Now, here’s the catch. A popular way to train high-performing neural nets is to pre-process the data (features), for example, using Principal Compenent Analysis (PCA) or whitening or log transforming or… If you’ve trained a neurals network before, you’ve probably used some kind of feature pre-processing to improve the model’s predictions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_u1Wxxn-nmbcVKzVO-a0eaa844.hMILayCi_Z109Vwk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Standardization. Photo by Philippe Krief on Unsplash&lt;/p&gt;
&lt;p&gt;But here’s the problem. When it’s time to uncover the importance of individual features with SHAP, all is good as long as you’re playing with the pre-processed features. But for SHAP to serve its purpose, it needs to show the relevance of the &lt;em&gt;original&lt;/em&gt; features. Imagine that you have pre-processed the features in a different way. That &lt;em&gt;other&lt;/em&gt; pre-processing would have led to an entirely different model, with different predictions. Different predictions mostly lead to different SHAP values.&lt;/p&gt;
&lt;p&gt;This means that in general, we can’t use the SHAP values of pre-processed features to represent the importance of the original features. (&lt;em&gt;In general&lt;/em&gt;: to be precise, specific variants of SHAP, like &lt;a href=&quot;https://arxiv.org/pdf/1908.08474.pdf&quot;&gt;BShap&lt;/a&gt;, do allow for specific &lt;em&gt;affine&lt;/em&gt; transformations of the features — like transforming Celsius to Fahrenheit — a property called &lt;em&gt;affine scale invariance.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With multi-variate transformations like PCA, the original features are even gone.&lt;/p&gt;
&lt;p&gt;You might be tempted to play with the SHAP values of the pre-processed features to get “SHAPpy” values for the original features.&lt;/p&gt;
&lt;p&gt;But what about the additivity property? Will the sum of the post-processed “SHAPpy” values of each feature for a given observation give the difference between the full model prediction and the null model prediction? Probably not.&lt;/p&gt;
&lt;p&gt;This means that the “SHAPpy” values lose their original meaning. So,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;using SHAP or XAI while pre-processing features is risky business!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Does this mean there’s something wrong with SHAP? No, not at all. The point of this post is to give you a heads up that when you pre-process features in a non-affine way, you can’t count on explainability in advance. And in reality, most of the time, features are pre-processed to get good results with training, unless you use tree-based models that don’t require pre-processing.&lt;/p&gt;
&lt;p&gt;Does this mean SHAP is at a disadvantage compared to other feature importance methods? Nope, not at all. This post didn’t even scratch the surface of the specifics of SHAP. So stay tuned, we might do a follow-up post on another method!&lt;/p&gt;
&lt;p&gt;p.s. This post was inspired by a productive discussion with the &lt;a href=&quot;http://tps.phys.tue.nl/janssen&quot;&gt;&lt;em&gt;Non-equilibrium soft matter&lt;/em&gt;&lt;/a&gt; group in Eindhoven, within a &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;collaboration&lt;/a&gt; with the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to Meiert Willem Grootes, Christiaan Meijer, Candace Moore and Patrick Bos for improving the blog post!&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 23 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Congrats! Your ML model is finally XAI-ready. But before you start patting yourself on the back, have you pre-processed your features? If so, watch out for those SHAP values, they might have been “processed”, too&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2097&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_s3LlcenurDp-MxDA-e6102adf.BIelJepI_Z2p3GPn.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mind the gap. Photo by Sammie Chaffin on Unsplash&lt;/p&gt;
&lt;p&gt;A very desirable property of machine learning models is explainability. This means being able to attribute the predictions to each input feature. SHAP (SHapley Additive exPlanations) is one of the most popular methods for getting feature importance, and it’s pretty much the state-of-the-art in explainable AI. It’s so popular because (1) it doesn’t matter what kind of model you use (random forest, SVM, neural network), (2) in certain aspects unifies other explainability methods, and (3) it has some great properties, including &lt;em&gt;additivity:&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sum of the SHAP values of each feature for a given observation gives the difference between the full model prediction and the prediction of the null model (a model without features).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a crucial property that makes SHAP believable. If the numbers from an explainability method have no physical meaning, no one is going to believe the method explains the model.&lt;/p&gt;
&lt;p&gt;Now, here’s the catch. A popular way to train high-performing neural nets is to pre-process the data (features), for example, using Principal Compenent Analysis (PCA) or whitening or log transforming or… If you’ve trained a neurals network before, you’ve probably used some kind of feature pre-processing to improve the model’s predictions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;559&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_u1Wxxn-nmbcVKzVO-a0eaa844.hMILayCi_Z109Vwk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Standardization. Photo by Philippe Krief on Unsplash&lt;/p&gt;
&lt;p&gt;But here’s the problem. When it’s time to uncover the importance of individual features with SHAP, all is good as long as you’re playing with the pre-processed features. But for SHAP to serve its purpose, it needs to show the relevance of the &lt;em&gt;original&lt;/em&gt; features. Imagine that you have pre-processed the features in a different way. That &lt;em&gt;other&lt;/em&gt; pre-processing would have led to an entirely different model, with different predictions. Different predictions mostly lead to different SHAP values.&lt;/p&gt;
&lt;p&gt;This means that in general, we can’t use the SHAP values of pre-processed features to represent the importance of the original features. (&lt;em&gt;In general&lt;/em&gt;: to be precise, specific variants of SHAP, like &lt;a href=&quot;https://arxiv.org/pdf/1908.08474.pdf&quot;&gt;BShap&lt;/a&gt;, do allow for specific &lt;em&gt;affine&lt;/em&gt; transformations of the features — like transforming Celsius to Fahrenheit — a property called &lt;em&gt;affine scale invariance.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With multi-variate transformations like PCA, the original features are even gone.&lt;/p&gt;
&lt;p&gt;You might be tempted to play with the SHAP values of the pre-processed features to get “SHAPpy” values for the original features.&lt;/p&gt;
&lt;p&gt;But what about the additivity property? Will the sum of the post-processed “SHAPpy” values of each feature for a given observation give the difference between the full model prediction and the null model prediction? Probably not.&lt;/p&gt;
&lt;p&gt;This means that the “SHAPpy” values lose their original meaning. So,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;using SHAP or XAI while pre-processing features is risky business!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Does this mean there’s something wrong with SHAP? No, not at all. The point of this post is to give you a heads up that when you pre-process features in a non-affine way, you can’t count on explainability in advance. And in reality, most of the time, features are pre-processed to get good results with training, unless you use tree-based models that don’t require pre-processing.&lt;/p&gt;
&lt;p&gt;Does this mean SHAP is at a disadvantage compared to other feature importance methods? Nope, not at all. This post didn’t even scratch the surface of the specifics of SHAP. So stay tuned, we might do a follow-up post on another method!&lt;/p&gt;
&lt;p&gt;p.s. This post was inspired by a productive discussion with the &lt;a href=&quot;http://tps.phys.tue.nl/janssen&quot;&gt;&lt;em&gt;Non-equilibrium soft matter&lt;/em&gt;&lt;/a&gt; group in Eindhoven, within a &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;collaboration&lt;/a&gt; with the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to Meiert Willem Grootes, Christiaan Meijer, Candace Moore and Patrick Bos for improving the blog post!&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_u1Wxxn-nmbcVKzVO-a0eaa844.hMILayCi.webp" medium="image"/><author>Sonja Georgievska</author></item><item><title>The medical chatbot will not see you now</title><link>https://blog.esciencecenter.nl/posts/2023-02-16---the-medical-chatbot-will-not-see-you-now</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-02-16---the-medical-chatbot-will-not-see-you-now</guid><description>&lt;h2 id=&quot;dr-candace-makeda-moore-rse-and-medical-doctor-lays-out-what-she-believes-the-potential-pitfalls-and-problems-of-ai-chatbots-in-medicine-are-closed-source-discrimination-irreproducibility-and-hype&quot;&gt;Dr. Candace Makeda Moore, RSE and medical doctor, lays out what she believes the potential pitfalls and problems of AI chatbots in medicine are: closed source, discrimination, (ir)reproducibility and hype&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_iu5EgTq1-GfUgnHK-a5b4977d.CxSbe3Dz_1vKyRD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by National Cancer Institute on Unsplash&lt;/p&gt;
&lt;p&gt;In a recent conversation with other physicians on AI in healthcare, I noticed they seemed hyped up about &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt;. In their happy enthusiasm, they sounded as if they had not thought through some of the implications of things they themselves were saying. Several of them asked many questions about how it worked. While we know ChatGPT is a large language model, it is closed-source. That means that even people like myself, who have worked with the code on healthcare-related chatbots, cannot tell you the exact mechanisms of how each part works unless they happen to work on the product itself.&lt;/p&gt;
&lt;p&gt;Many physicians today use their computers as operators, close to the way they use cars. They never open up the hood and figure out what is going on underneath. Closed source code is essentially a car where the hood has been nailed and glued shut with a legal mechanism. It doesn’t matter that most particular physicians can’t read the code behind ChatGPT. After all, no one needs programming knowledge to become a medical doctor. What really matters is that no engineer or statistician in their hospital can read closed source code either, because it’s not public.&lt;/p&gt;
&lt;p&gt;The last decades have seen a real revolution in terms of moving away from closed-source code. In our work at the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center,&lt;/a&gt; we help scientific researchers create and use open code to create reproducible results. We push scientists to make both data and code available. Open-source chatbots for healthcare issues are under development in our center (like &lt;a href=&quot;https://github.com/PerfectFit-project/&quot;&gt;PerfectFit&lt;/a&gt;) and beyond. In healthcare, patient data protection is critical and in some cases the data powering algorithms needs anonymization. But in the case of a machine learning algorithm, until you can examine the code behind it, you can’t really know whether the data used to train the algorithm has been subjected to the same standards. If you deploy a closed-source product, you have to take on blind faith that it works in a way that won’t harm people.&lt;/p&gt;
&lt;p&gt;Here I must point out that it is likely that ChatGPT can harm people. The real hero to warn the public about this was Steven T. Piantadosi, a Berkeley neuroscience professor, who tweeted some fascinating results that I wish more people had seen. We may not know what is under the hood of ChatGPT, but thanks in part to Piantadosi’s prompts, we know it is capable of producing results that are racist and sexist. Less than three months ago, in December 2022, Piantadosi Tweeted ChatGPT’s response when he prompted the program to write programs about issues such as which child’s life should be saved based on their race and gender.&lt;/p&gt;
&lt;h3 id=&quot;automated-racism&quot;&gt;Automated racism&lt;/h3&gt;
&lt;p&gt;The program, if cued in a certain way, &lt;a href=&quot;https://twitter.com/spiantado/status/1599462375887114240&quot;&gt;would not suggest saving the life of a black male child, and but would suggest saving a white one&lt;/a&gt;. This &lt;a href=&quot;https://twitter.com/spiantado/status/1599462375887114240&quot;&gt;program algorithm&lt;/a&gt; was not an ironic joke or even a fluke. On prompts about race, the results were sadly expectable for someone like me who researches these issues. Sharing the results with the broader public allows everyone to see the dangers for themselves. ChatGPT is trained on a large corpus of text, gigabytes large, which clearly had some biases in it.&lt;/p&gt;
&lt;p&gt;The full conversation with ChatGPT contains more examples of ChatGPT’s biases at the time.&lt;/p&gt;
&lt;p&gt;What Piantadosi did in technical terms was a type of adversarial testing, and it is worth pointing out that it did not require him to be a computer scientist or even to write code. What I’m getting at, by pointing to Piantadosi’s academic provenance, is that even a scientist, nurse, or medical doctor with zero computer science knowledge, but perhaps some awareness of the dangers of such algorithms, could have done the same out of concern for patients. And at this point, we should all know to expect these outcomes, as countless researchers (even &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2666521222000205&quot;&gt;including myself&lt;/a&gt;) have been working and publishing on issues like these for years.&lt;/p&gt;
&lt;p&gt;In the conversation with fellow doctors, the author of a forthcoming book on ChatGPT in healthcare declared it would get better and better. The man was an accomplished physician, but unfortunately, that does not imply someone who actually builds such systems line by line of code (specifically including the test code) and sees the results at scale. Only someone who doesn’t write the code on such systems could be so optimistic. The algorithm will get better or worse depending upon the data that it is fed, and the code that is added or removed from it. If you are counting on engineers to only do better and more careful work, you may want to consider how many software failures in healthcare come not from original products but from upgrades.&lt;/p&gt;
&lt;p&gt;To their credit, the staff over at &lt;a href=&quot;https://openai.com/&quot;&gt;OpenAI&lt;/a&gt; must be watching the internet, because they seem to have put guardrails on in terms of the exact kind of cues Piantadosi fed the algorithm. When I tested it on a recent morning, I got different results (screenshot shared below).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-f1dub97Cihvht4NPrwU7w-d0fbf5f0.u5IsbUkK_Z25Pm02.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Did I get different results based on a new algorithm, or just by chance? We can’t know. I do know it is very easy to hard-code over answers to certain questions while leaving bias in a general algorithm. I can imagine, that for legal reasons alone, anyone using ChatGPT might apply some kind of adversarial training layer on top of the closed algorithm results to eliminate racist statements.&lt;/p&gt;
&lt;p&gt;Even if this were the case, there are at least a couple more fundamental issues with the algorithm than its potential for producing racially biased answers. One issue is that the algorithm can return incorrect text about fairly obvious facts in medicine. Below is a screenshot from its response when I asked it a question about fabellae (a fabella is an accessory ossicle in the knee present in a minority of the population) in the way I thought a patient might ask it i.e. without fancy Latin orthography.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PuAvhRAwOe91akA3VkefJA-b1150312.BO04i_pB_1eg7Fl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The program returns something I consider symbolic of many of its problems. The program actually produced the correct spelling of fabellae, but got the facts wrong. Text produced can look right, and if you incorrectly attribute human qualities to the program, the program and text can seem ‘smarter’ than your average patient, but it can simultaneously not actually &lt;strong&gt;be&lt;/strong&gt; right. I guess ChatGPT won’t be replacing anatomists or radiologists (who know &lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6075638/&quot;&gt;most of the population have zero fabellae&lt;/a&gt;) anytime soon. Some enthusiasts might argue that these little bugs could be fixed with hardcoded information about obvious facts. Even if that were possible, there are simple facts, and then there are assumptions based on the interpretation of data. For example, if I were to ask ChatGPT about the ideal diet for me to optimize my health, the answer is not truly an undebated ‘fact’ in the medical community. And here again, the machine can go in unwanted directions.&lt;/p&gt;
&lt;h3 id=&quot;reproducibility-the-scientific-dilemma-of-our-decade&quot;&gt;Reproducibility: the scientific dilemma of our decade&lt;/h3&gt;
&lt;p&gt;In my recent conversation with physicians, one marveled at how the chatbot had given two logical yet different answers to questions posed to it about a complex text. The doctor was wowed by the human and intellectual sound of the answers. In my head alarm bells were going off. If the same algorithm produces different answers at different times of the day, you have a problem with medical and scientific research, let alone medical applications. Algorithms can be programmed to look spontaneous and not reproducible, but fundamentally, many algorithms create exactly reproducible results even if they appear not to.&lt;/p&gt;
&lt;p&gt;Computers are not random, in fact, they can’t even make truly random outputs. If you actually program, you know this, as the functions used to make ‘random’ numbers rely on things like the machine time as input to pseudorandomized output. It takes a lot of work and code to make a simple algorithm, like a decision tree, not reproducible. But the more complex an algorithm is, the easier it is to get results that appear random, and not be truly reproducible in important ways. An algorithm that was trained on gigabytes of input can become pseudo-random in ways humans simply can’t comprehend, as we cannot read a corpus of gigabytes of text. Such an algorithm’s outputs can become, for our purposes, not reproducible from one patient to the next, and that is simply unacceptable in modern medicine.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;I am always surprised at how many of my fellow physicians seem to think algorithms fall from the sky perfect (the technical term here is automation bias). As someone who actually writes code on algorithms, I can tell you that to get a very complex large computer program that is perfect, you need a perfect group of perfect programmers (and no such thing exists). Code reflects the people who wrote it in general, and when it comes to machine learning it reflects the thought process of those people, and the people who curated the data the particular algorithm was based on.&lt;/p&gt;
&lt;p&gt;One argument for using chatbots in medicine is that they could help people who can’t access doctors. As someone who has spent time in places like Haiti and Lesvos, Greece, voluntarily practicing medicine towards humanitarian aims, this sounds appealing. But as someone whose work is to write code, I know better. There is a highly paid workforce behind complex algorithms and any medical AI system needs constant surveillance, monitoring, and upgrades. The work of ten dedicated high-level biomedical engineers and programmers isn’t necessarily any cheaper or better than that of ten physicians. Perhaps the true path forward is more physician education on such matters because in each specific situation, some combination of physicians and engineers is optimal to get the best healthcare to the most people at the lowest price.&lt;/p&gt;
&lt;p&gt;Chatbots are a tool we should embrace towards these great aims, but the hype around a closed-source product shows how far we have to go before we in medicine are truly ready to use such powerful tools.&lt;/p&gt;</description><pubDate>Thu, 16 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;dr-candace-makeda-moore-rse-and-medical-doctor-lays-out-what-she-believes-the-potential-pitfalls-and-problems-of-ai-chatbots-in-medicine-are-closed-source-discrimination-irreproducibility-and-hype&quot;&gt;Dr. Candace Makeda Moore, RSE and medical doctor, lays out what she believes the potential pitfalls and problems of AI chatbots in medicine are: closed source, discrimination, (ir)reproducibility and hype&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_iu5EgTq1-GfUgnHK-a5b4977d.CxSbe3Dz_1vKyRD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by National Cancer Institute on Unsplash&lt;/p&gt;
&lt;p&gt;In a recent conversation with other physicians on AI in healthcare, I noticed they seemed hyped up about &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt;. In their happy enthusiasm, they sounded as if they had not thought through some of the implications of things they themselves were saying. Several of them asked many questions about how it worked. While we know ChatGPT is a large language model, it is closed-source. That means that even people like myself, who have worked with the code on healthcare-related chatbots, cannot tell you the exact mechanisms of how each part works unless they happen to work on the product itself.&lt;/p&gt;
&lt;p&gt;Many physicians today use their computers as operators, close to the way they use cars. They never open up the hood and figure out what is going on underneath. Closed source code is essentially a car where the hood has been nailed and glued shut with a legal mechanism. It doesn’t matter that most particular physicians can’t read the code behind ChatGPT. After all, no one needs programming knowledge to become a medical doctor. What really matters is that no engineer or statistician in their hospital can read closed source code either, because it’s not public.&lt;/p&gt;
&lt;p&gt;The last decades have seen a real revolution in terms of moving away from closed-source code. In our work at the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center,&lt;/a&gt; we help scientific researchers create and use open code to create reproducible results. We push scientists to make both data and code available. Open-source chatbots for healthcare issues are under development in our center (like &lt;a href=&quot;https://github.com/PerfectFit-project/&quot;&gt;PerfectFit&lt;/a&gt;) and beyond. In healthcare, patient data protection is critical and in some cases the data powering algorithms needs anonymization. But in the case of a machine learning algorithm, until you can examine the code behind it, you can’t really know whether the data used to train the algorithm has been subjected to the same standards. If you deploy a closed-source product, you have to take on blind faith that it works in a way that won’t harm people.&lt;/p&gt;
&lt;p&gt;Here I must point out that it is likely that ChatGPT can harm people. The real hero to warn the public about this was Steven T. Piantadosi, a Berkeley neuroscience professor, who tweeted some fascinating results that I wish more people had seen. We may not know what is under the hood of ChatGPT, but thanks in part to Piantadosi’s prompts, we know it is capable of producing results that are racist and sexist. Less than three months ago, in December 2022, Piantadosi Tweeted ChatGPT’s response when he prompted the program to write programs about issues such as which child’s life should be saved based on their race and gender.&lt;/p&gt;
&lt;h3 id=&quot;automated-racism&quot;&gt;Automated racism&lt;/h3&gt;
&lt;p&gt;The program, if cued in a certain way, &lt;a href=&quot;https://twitter.com/spiantado/status/1599462375887114240&quot;&gt;would not suggest saving the life of a black male child, and but would suggest saving a white one&lt;/a&gt;. This &lt;a href=&quot;https://twitter.com/spiantado/status/1599462375887114240&quot;&gt;program algorithm&lt;/a&gt; was not an ironic joke or even a fluke. On prompts about race, the results were sadly expectable for someone like me who researches these issues. Sharing the results with the broader public allows everyone to see the dangers for themselves. ChatGPT is trained on a large corpus of text, gigabytes large, which clearly had some biases in it.&lt;/p&gt;
&lt;p&gt;The full conversation with ChatGPT contains more examples of ChatGPT’s biases at the time.&lt;/p&gt;
&lt;p&gt;What Piantadosi did in technical terms was a type of adversarial testing, and it is worth pointing out that it did not require him to be a computer scientist or even to write code. What I’m getting at, by pointing to Piantadosi’s academic provenance, is that even a scientist, nurse, or medical doctor with zero computer science knowledge, but perhaps some awareness of the dangers of such algorithms, could have done the same out of concern for patients. And at this point, we should all know to expect these outcomes, as countless researchers (even &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2666521222000205&quot;&gt;including myself&lt;/a&gt;) have been working and publishing on issues like these for years.&lt;/p&gt;
&lt;p&gt;In the conversation with fellow doctors, the author of a forthcoming book on ChatGPT in healthcare declared it would get better and better. The man was an accomplished physician, but unfortunately, that does not imply someone who actually builds such systems line by line of code (specifically including the test code) and sees the results at scale. Only someone who doesn’t write the code on such systems could be so optimistic. The algorithm will get better or worse depending upon the data that it is fed, and the code that is added or removed from it. If you are counting on engineers to only do better and more careful work, you may want to consider how many software failures in healthcare come not from original products but from upgrades.&lt;/p&gt;
&lt;p&gt;To their credit, the staff over at &lt;a href=&quot;https://openai.com/&quot;&gt;OpenAI&lt;/a&gt; must be watching the internet, because they seem to have put guardrails on in terms of the exact kind of cues Piantadosi fed the algorithm. When I tested it on a recent morning, I got different results (screenshot shared below).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-f1dub97Cihvht4NPrwU7w-d0fbf5f0.u5IsbUkK_Z25Pm02.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Did I get different results based on a new algorithm, or just by chance? We can’t know. I do know it is very easy to hard-code over answers to certain questions while leaving bias in a general algorithm. I can imagine, that for legal reasons alone, anyone using ChatGPT might apply some kind of adversarial training layer on top of the closed algorithm results to eliminate racist statements.&lt;/p&gt;
&lt;p&gt;Even if this were the case, there are at least a couple more fundamental issues with the algorithm than its potential for producing racially biased answers. One issue is that the algorithm can return incorrect text about fairly obvious facts in medicine. Below is a screenshot from its response when I asked it a question about fabellae (a fabella is an accessory ossicle in the knee present in a minority of the population) in the way I thought a patient might ask it i.e. without fancy Latin orthography.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;788&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PuAvhRAwOe91akA3VkefJA-b1150312.BO04i_pB_1eg7Fl.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The program returns something I consider symbolic of many of its problems. The program actually produced the correct spelling of fabellae, but got the facts wrong. Text produced can look right, and if you incorrectly attribute human qualities to the program, the program and text can seem ‘smarter’ than your average patient, but it can simultaneously not actually &lt;strong&gt;be&lt;/strong&gt; right. I guess ChatGPT won’t be replacing anatomists or radiologists (who know &lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6075638/&quot;&gt;most of the population have zero fabellae&lt;/a&gt;) anytime soon. Some enthusiasts might argue that these little bugs could be fixed with hardcoded information about obvious facts. Even if that were possible, there are simple facts, and then there are assumptions based on the interpretation of data. For example, if I were to ask ChatGPT about the ideal diet for me to optimize my health, the answer is not truly an undebated ‘fact’ in the medical community. And here again, the machine can go in unwanted directions.&lt;/p&gt;
&lt;h3 id=&quot;reproducibility-the-scientific-dilemma-of-our-decade&quot;&gt;Reproducibility: the scientific dilemma of our decade&lt;/h3&gt;
&lt;p&gt;In my recent conversation with physicians, one marveled at how the chatbot had given two logical yet different answers to questions posed to it about a complex text. The doctor was wowed by the human and intellectual sound of the answers. In my head alarm bells were going off. If the same algorithm produces different answers at different times of the day, you have a problem with medical and scientific research, let alone medical applications. Algorithms can be programmed to look spontaneous and not reproducible, but fundamentally, many algorithms create exactly reproducible results even if they appear not to.&lt;/p&gt;
&lt;p&gt;Computers are not random, in fact, they can’t even make truly random outputs. If you actually program, you know this, as the functions used to make ‘random’ numbers rely on things like the machine time as input to pseudorandomized output. It takes a lot of work and code to make a simple algorithm, like a decision tree, not reproducible. But the more complex an algorithm is, the easier it is to get results that appear random, and not be truly reproducible in important ways. An algorithm that was trained on gigabytes of input can become pseudo-random in ways humans simply can’t comprehend, as we cannot read a corpus of gigabytes of text. Such an algorithm’s outputs can become, for our purposes, not reproducible from one patient to the next, and that is simply unacceptable in modern medicine.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;I am always surprised at how many of my fellow physicians seem to think algorithms fall from the sky perfect (the technical term here is automation bias). As someone who actually writes code on algorithms, I can tell you that to get a very complex large computer program that is perfect, you need a perfect group of perfect programmers (and no such thing exists). Code reflects the people who wrote it in general, and when it comes to machine learning it reflects the thought process of those people, and the people who curated the data the particular algorithm was based on.&lt;/p&gt;
&lt;p&gt;One argument for using chatbots in medicine is that they could help people who can’t access doctors. As someone who has spent time in places like Haiti and Lesvos, Greece, voluntarily practicing medicine towards humanitarian aims, this sounds appealing. But as someone whose work is to write code, I know better. There is a highly paid workforce behind complex algorithms and any medical AI system needs constant surveillance, monitoring, and upgrades. The work of ten dedicated high-level biomedical engineers and programmers isn’t necessarily any cheaper or better than that of ten physicians. Perhaps the true path forward is more physician education on such matters because in each specific situation, some combination of physicians and engineers is optimal to get the best healthcare to the most people at the lowest price.&lt;/p&gt;
&lt;p&gt;Chatbots are a tool we should embrace towards these great aims, but the hype around a closed-source product shows how far we have to go before we in medicine are truly ready to use such powerful tools.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_-f1dub97Cihvht4NPrwU7w-d0fbf5f0.u5IsbUkK.png" medium="image"/><author>Candace Moore</author></item><item><title>Diversity in Software: four ways to think different</title><link>https://blog.esciencecenter.nl/posts/2023-02-02---diversity-in-software-four-ways-to-think-different</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-02-02---diversity-in-software-four-ways-to-think-different</guid><description>&lt;p&gt;&lt;img alt=&quot;Diversity in Software: four ways to think different&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;511&quot; src=&quot;https://blog.esciencecenter.nl/_astro/diversity-in-software-four-ways-to-think-4a16eeee.CsqEyq-x_W46iH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steve_j?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Johnson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;diversity-in-software-four-ways-to-think-different&quot;&gt;Diversity in Software: four ways to think different&lt;/h1&gt;
&lt;p&gt;Diversity is a hot topic. Let’s talk about diversity in Software. Hackers need to wake up and face the truth: a lot of programming paradigms are underrepresented in the mainstream media. All the talk is about Python, Rust, Kotlin, and Julia. All of them are imperative languages. This just leaves no room for us wayward farers to express ourselves and be ourselves!&lt;/p&gt;
&lt;p&gt;People who know me now think the rest of this piece is going to cover the other side of the isle: functional programming, but they’re wrong. Just two approaches to programming are not enough. The funny thing is, you will have heard of most of the languages that I will talk about. I’ll just teach you to treat them with a little more respect.&lt;/p&gt;
&lt;h3 id=&quot;make&quot;&gt;Make&lt;/h3&gt;
&lt;p&gt;Make is a dependency-based programming language. You state a set of requirements, then other requirements for those, and so on. Then Make figures out a way to meet this cascade of requirements until your original goal is reached. This is a radical departure from imperative-style programming, where you have to be more explicit in what order you would like things to happen.&lt;/p&gt;
&lt;h3 id=&quot;awk&quot;&gt;Awk&lt;/h3&gt;
&lt;p&gt;Awk is a data streaming language. Given that you have some input file, Awk triggers actions on some regular expressions that you provide. This is ideal for processing text files. Because Regexes play a central role in the execution model of Awk, programs tend to suffer in readability. What you need to realize is how awesome the concept of Awk is. The rule-based control flow makes your program context-aware.&lt;/p&gt;
&lt;h3 id=&quot;sql&quot;&gt;SQL&lt;/h3&gt;
&lt;p&gt;In a landscape where the increasingly popular databases are graph-based or NoSQL, we need to champion our old hero: SQL. There’s nothing quite like juggling tables and inner joining them in holy matrimony. There’s a good reason why most databases work with tables and relations: for most cases, it is very efficient. The little extra effort of designing a table layout and indexing your data at strategic points is always well spent, as you gain insight into your problem.&lt;/p&gt;
&lt;h3 id=&quot;excel&quot;&gt;Excel&lt;/h3&gt;
&lt;p&gt;Say what!?! Excel is at its core a functional reactive programming language. Your data is a signal. Every time the signal changes all the depending cells are notified and updated live. Frameworks that generalize on this concept are known as functional reactive. I know Excel has its share of problems: cells that are not included in the computation, bad type heuristics, poor scaling… However, at its core Excel is a beautiful diamond that needs to be celebrated.&lt;/p&gt;
&lt;p&gt;Ok, those were some very famous languages. What you need to understand is how they are different. Their diversity can teach you not to take the mainstream general-purpose programming sludge for granted.&lt;/p&gt;
&lt;p&gt;In fact, the particular way that these languages or systems are different may teach you how to think about some problems on a higher level. The primitives of SQL are available in Python (and many other languages): for small things, you can use iterator comprehensions or the &lt;code&gt;itertools&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;If your problem has a complex set of interlocking dependent tasks (like you’d have in Make), consider writing the dependencies down in a data structure and evaluate them using Asyncio or Dask. This helps separate the core logic from implementation details, giving you cleaner, i.e. more readable and better maintainable code.&lt;/p&gt;
&lt;p&gt;The same goes for Awky problems: if you need to filter through a lot of text, write down some rules for a little state machine. Your life will improve!&lt;/p&gt;
&lt;p&gt;As for Excel: (functional) reactive programming is a topic I can’t possibly do justice to here. For those interested: &lt;a href=&quot;https://blog.oakbits.com/introduction-to-rxpy.html&quot;&gt;Introduction to RxPy&lt;/a&gt;, or more generally &lt;a href=&quot;https://www.manning.com/books/functional-reactive-programming&quot;&gt;Introduction to Functional Reactive Programming&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What these languages have in common, is that they have a different control flow* from what you’re used to. Knowing how to work with these tools can be an invaluable addition to your skill set. Did I miss out on any? Please comment below!&lt;/p&gt;
&lt;p&gt;If you’re interested in programming language history, check out this video.&lt;/p&gt;</description><pubDate>Thu, 02 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;Diversity in Software: four ways to think different&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;511&quot; src=&quot;https://blog.esciencecenter.nl/_astro/diversity-in-software-four-ways-to-think-4a16eeee.CsqEyq-x_W46iH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@steve_j?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Steve Johnson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;diversity-in-software-four-ways-to-think-different&quot;&gt;Diversity in Software: four ways to think different&lt;/h1&gt;
&lt;p&gt;Diversity is a hot topic. Let’s talk about diversity in Software. Hackers need to wake up and face the truth: a lot of programming paradigms are underrepresented in the mainstream media. All the talk is about Python, Rust, Kotlin, and Julia. All of them are imperative languages. This just leaves no room for us wayward farers to express ourselves and be ourselves!&lt;/p&gt;
&lt;p&gt;People who know me now think the rest of this piece is going to cover the other side of the isle: functional programming, but they’re wrong. Just two approaches to programming are not enough. The funny thing is, you will have heard of most of the languages that I will talk about. I’ll just teach you to treat them with a little more respect.&lt;/p&gt;
&lt;h3 id=&quot;make&quot;&gt;Make&lt;/h3&gt;
&lt;p&gt;Make is a dependency-based programming language. You state a set of requirements, then other requirements for those, and so on. Then Make figures out a way to meet this cascade of requirements until your original goal is reached. This is a radical departure from imperative-style programming, where you have to be more explicit in what order you would like things to happen.&lt;/p&gt;
&lt;h3 id=&quot;awk&quot;&gt;Awk&lt;/h3&gt;
&lt;p&gt;Awk is a data streaming language. Given that you have some input file, Awk triggers actions on some regular expressions that you provide. This is ideal for processing text files. Because Regexes play a central role in the execution model of Awk, programs tend to suffer in readability. What you need to realize is how awesome the concept of Awk is. The rule-based control flow makes your program context-aware.&lt;/p&gt;
&lt;h3 id=&quot;sql&quot;&gt;SQL&lt;/h3&gt;
&lt;p&gt;In a landscape where the increasingly popular databases are graph-based or NoSQL, we need to champion our old hero: SQL. There’s nothing quite like juggling tables and inner joining them in holy matrimony. There’s a good reason why most databases work with tables and relations: for most cases, it is very efficient. The little extra effort of designing a table layout and indexing your data at strategic points is always well spent, as you gain insight into your problem.&lt;/p&gt;
&lt;h3 id=&quot;excel&quot;&gt;Excel&lt;/h3&gt;
&lt;p&gt;Say what!?! Excel is at its core a functional reactive programming language. Your data is a signal. Every time the signal changes all the depending cells are notified and updated live. Frameworks that generalize on this concept are known as functional reactive. I know Excel has its share of problems: cells that are not included in the computation, bad type heuristics, poor scaling… However, at its core Excel is a beautiful diamond that needs to be celebrated.&lt;/p&gt;
&lt;p&gt;Ok, those were some very famous languages. What you need to understand is how they are different. Their diversity can teach you not to take the mainstream general-purpose programming sludge for granted.&lt;/p&gt;
&lt;p&gt;In fact, the particular way that these languages or systems are different may teach you how to think about some problems on a higher level. The primitives of SQL are available in Python (and many other languages): for small things, you can use iterator comprehensions or the &lt;code&gt;itertools&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;If your problem has a complex set of interlocking dependent tasks (like you’d have in Make), consider writing the dependencies down in a data structure and evaluate them using Asyncio or Dask. This helps separate the core logic from implementation details, giving you cleaner, i.e. more readable and better maintainable code.&lt;/p&gt;
&lt;p&gt;The same goes for Awky problems: if you need to filter through a lot of text, write down some rules for a little state machine. Your life will improve!&lt;/p&gt;
&lt;p&gt;As for Excel: (functional) reactive programming is a topic I can’t possibly do justice to here. For those interested: &lt;a href=&quot;https://blog.oakbits.com/introduction-to-rxpy.html&quot;&gt;Introduction to RxPy&lt;/a&gt;, or more generally &lt;a href=&quot;https://www.manning.com/books/functional-reactive-programming&quot;&gt;Introduction to Functional Reactive Programming&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What these languages have in common, is that they have a different control flow* from what you’re used to. Knowing how to work with these tools can be an invaluable addition to your skill set. Did I miss out on any? Please comment below!&lt;/p&gt;
&lt;p&gt;If you’re interested in programming language history, check out this video.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/diversity-in-software-four-ways-to-think-4a16eeee.CsqEyq-x.jpg" medium="image"/><author>Johan Hidding</author></item><item><title>Build a mass spectrometry analysis pipeline in Python using matchms — part II: Spec2Vec</title><link>https://blog.esciencecenter.nl/posts/2023-01-31---build-a-mass-spectrometry-analysis-pipeline-in-python-using-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-01-31---build-a-mass-spectrometry-analysis-pipeline-in-python-using-</guid><description>&lt;h2 id=&quot;after-part-i-which-gave-an-introduction-on-how-to-import-process-and-analyze-a-tandem-mass-spectra-dataset-using-python-and-matchms-part-ii-will-add-spec2vec-to-the-game-a-machine-learning-tool-to-assess-spectrum-similarities&quot;&gt;After “part I” which gave an introduction on how to import, process, and analyze a tandem mass spectra dataset using Python and matchms, “part II” will add Spec2Vec to the game, a machine learning tool to assess spectrum similarities.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Feb 17, 2021&lt;/p&gt;
&lt;p&gt;Instead of looking at a few individual query spectra, lets have a look at the “bigger picture” by plotting part of the similarity score matrix we just computed to generate Figure 2**.&lt;/p&gt;
&lt;p&gt;from matplotlib import pyplot as pltscores_array = scores.scores.to_array()  # for matchms &gt;= 0.18.0plt.figure(figsize=(6,6), dpi=150)&lt;strong&gt;plt.imshow(scores_array[:50, :50], cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Spec2Vec spectra similarities”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
plt.clim(0, 1)  # Spec2Vec scores can be between -1 and 1
#plt.savefig(“spec2vec_scores.png”)
Figure 2&lt;/strong&gt;. Show the first 50 x 50 Spec2Vec similarity scores. The diagonal are scores between spectra and themselves, hence always = 1.0 (boring). But the few brighter (green/yellowish) dots here and there point out some apparently related spectra, according to Spec2Vec. Those might be worth a closer look.&lt;/p&gt;
&lt;h2 id=&quot;2-train-a-new-spec2vec-model-from-scratch&quot;&gt;2. Train a new Spec2Vec model from scratch&lt;/h2&gt;
&lt;p&gt;Training a Spec2Vec model is fairly straightforward and relatively fast (usually minutes to one hour max). In general, training a new model from scratch makes sense when a lot a data is present to train on as it gives more options to optimize the results when compared to simply using a pretrained model as done above.&lt;/p&gt;
&lt;p&gt;First, the spectrum data has to be converted into “documents” where peaks and neutral losses have become “words” (e.g. &lt;code&gt;peak@289.29&lt;/code&gt;). This can be done by running:&lt;/p&gt;
&lt;p&gt;from spec2vec import SpectrumDocumentspectrum_documents = [SpectrumDocument(s, n_decimals=2) for s in spectrums]Then, a new model can simply be trained by using &lt;code&gt;train_new_word2vec_model&lt;/code&gt;. The following code will create a new model which is trained for 25 iterations (for machine learning people: that is ”epochs”) on 2 workers (you can change this, e.g. to 4 if you have 4 cores, the difference is not drastic though). Depending on your hardware, the training of this model should not take longer than a couple of minutes.&lt;/p&gt;
&lt;p&gt;from spec2vec.model_building import train_new_word2vec_modelmodel_file = “tutorial_model.model”**model = train_new_word2vec_model(spectrum_documents, iterations=[25], filename=model_file,
workers=2, progress_logger=True)The above code snippet will automatically save the model under the name &lt;code&gt;tutorial_model.model&lt;/code&gt;, which could later load again by running &lt;code&gt;model = gensim.models.Word2Vec.load(&quot;tutorial_model.model&quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;calculate-spectrum-similarities&quot;&gt;Calculate spectrum similarities&lt;/h3&gt;
&lt;p&gt;Once we have our trained model we can again (as above with the pretrained model) compute spectrum similarities.&lt;/p&gt;
&lt;p&gt;from matchms import calculate_scores
from spec2vec import Spec2Vecspec2vec_similarity = Spec2Vec(model=model, intensity_weighting_power=0.5,
allowed_missing_percentage=5.0)scores = calculate_scores(spectrum_documents, spectrum_documents, spec2vec_similarity, is_symmetric=True)Here again we can search for the best matching compounds according to Spec2Vec.&lt;/p&gt;
&lt;p&gt;best_matches = scores.scores_by_query(spectrum_documents[11], sort=True)[:10]
[x[0].get(“smiles”) for x in best_matches]And we can plot the resulting smiles to .png files by running:&lt;/p&gt;
&lt;p&gt;from rdkit import Chem
from rdkit.Chem import Drawfor i, smiles in enumerate([x[0].get(“smiles”) for x in best_matches]):
m = Chem.MolFromSmiles(smiles)
Draw.MolToFile(m, f”compound_{i}.png”)The best 8 matches are plotted in Figure 3**.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 3.&lt;/strong&gt; Compounds of the highest 9 Spec2Vec similarity scores within the dataset with respect to spectrums[11], the first being the spectrum of interest itself (hence “query compound”).This example in figure 3 looks already quiet promising and all selected candidates clearly show chemical similarities! But this is of course just one mostly random pick out of many spectra. In our &lt;a href=&quot;https://www.biorxiv.org/content/10.1101/2020.08.11.245928v2&quot;&gt;Spec2Vec paper&lt;/a&gt; we compared the different similarity scores (Cosine, modified Cosine, Spec2Vec) in much more detail and found that Spec2Vec often — but not always — outperformed the classical scores. We also found a general trend that such scores are generally more reliable for larger compounds, supposedly because those will come with a higher number of chemically meaningful fragments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 4.&lt;/strong&gt; Working with different datasets from GNPS we evaluated the quality of Spec2Vec based spectrum suggestions and found that they get better with increasing compound mass. Taken from &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;Spec2Vec article&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OK. Done for now. Really curious to see what you can get out of Spec2Vec!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;other-parts-of-this-tutorial&quot;&gt;Other parts of this tutorial&lt;/h2&gt;
&lt;h3 id=&quot;part-i--build-you-own-mass-spectrometry-pipeline&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-your-own-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-i-d96c718c68ee&quot;&gt;part I — Build you own mass spectrometry pipeline&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-ii--compute-spectra-similarities-using-spec2vec&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-ii-spec2vec-8aa639571018&quot;&gt;part II — Compute spectra similarities using Spec2Vec&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-iii--network-analysis-based-on-spectra-similarities&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-iii-molecular-91891248ee34&quot;&gt;part III — Network analysis based on spectra similarities&lt;/a&gt;&lt;/h3&gt;
&lt;h2 id=&quot;matchms-library&quot;&gt;matchms library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;matchms&lt;/strong&gt;* is freely available and open-source. You can find the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/matchms&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/matchms/&quot;&gt;from pypi&lt;/a&gt;. It was developed by a bunch of very nice people (see &lt;a href=&quot;https://github.com/matchms/matchms/blob/master/CITATION.cff&quot;&gt;here&lt;/a&gt;) and is &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;published in Joss&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;spec2vec-library&quot;&gt;spec2vec library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Spec2Vec&lt;/strong&gt; is of course also freely available and open-source. You can find the &lt;a href=&quot;https://github.com/iomega/spec2vec&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/spec2vec&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/spec2vec/&quot;&gt;from pypi&lt;/a&gt;. The &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;article published in PLOS Computational Biology can be found here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find more information in the &lt;a href=&quot;https://matchms.readthedocs.io/en/latest/&quot;&gt;matchms documentation&lt;/a&gt; and the &lt;a href=&quot;https://spec2vec.readthedocs.io/en/latest/?badge=latest&quot;&gt;spec2vec documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;
&lt;p&gt;The code shown in this blog post can also be found &lt;a href=&quot;https://github.com/matchms/matchms/blob/tutorial/tutorial/matchms_tutorial_02_compute_similarities_with_Spec2Vec.ipynb&quot;&gt;as Jupyter notebook on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;help-us-develop-matchms-and-spec2vec-further&quot;&gt;Help us develop matchms and spec2vec further!&lt;/h2&gt;
&lt;p&gt;We really hope that matchms will help people to build new, better analysis pipelines and that spec2vec can improve your analysis results. So, please help us to further improve matchms and spec2vec. You can help us by &lt;strong&gt;(1)&lt;/strong&gt; Cite our work if you use our package for your research: &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;matchms article in JOSS,&lt;/a&gt; &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;spec2vec article in PLOS Computational Biology&lt;/a&gt;.&lt;strong&gt;(2)&lt;/strong&gt; Let us know if you run into any issues using matchms and/or spec2vec, or if you are missing any key functionalities! You can simply do so by starting a new issue on the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;matchms GitHub repository,&lt;/a&gt; or contact me on twitter &lt;a href=&quot;https://twitter.com/me_datapoint?lang=en&quot;&gt;@me_datapoint&lt;/a&gt;.&lt;strong&gt;You are of course more than welcome to also become an active contributor to the package and help extend its functionality!
(3)&lt;/strong&gt; Please let us know if you successfully applied matchms and/or spec2vec in your research project (makes us happy + we can maybe share the good news!).&lt;/p&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
&lt;p&gt;I would like to thank [Carlos Martinez-Ortiz], [Justin van der Hooft] and [Kontoueftychia] for helpful comments and suggestions on this blog post.&lt;/p&gt;</description><pubDate>Tue, 31 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;after-part-i-which-gave-an-introduction-on-how-to-import-process-and-analyze-a-tandem-mass-spectra-dataset-using-python-and-matchms-part-ii-will-add-spec2vec-to-the-game-a-machine-learning-tool-to-assess-spectrum-similarities&quot;&gt;After “part I” which gave an introduction on how to import, process, and analyze a tandem mass spectra dataset using Python and matchms, “part II” will add Spec2Vec to the game, a machine learning tool to assess spectrum similarities.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Feb 17, 2021&lt;/p&gt;
&lt;p&gt;Instead of looking at a few individual query spectra, lets have a look at the “bigger picture” by plotting part of the similarity score matrix we just computed to generate Figure 2**.&lt;/p&gt;
&lt;p&gt;from matplotlib import pyplot as pltscores_array = scores.scores.to_array()  # for matchms &gt;= 0.18.0plt.figure(figsize=(6,6), dpi=150)&lt;strong&gt;plt.imshow(scores_array[:50, :50], cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Spec2Vec spectra similarities”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
plt.clim(0, 1)  # Spec2Vec scores can be between -1 and 1
#plt.savefig(“spec2vec_scores.png”)
Figure 2&lt;/strong&gt;. Show the first 50 x 50 Spec2Vec similarity scores. The diagonal are scores between spectra and themselves, hence always = 1.0 (boring). But the few brighter (green/yellowish) dots here and there point out some apparently related spectra, according to Spec2Vec. Those might be worth a closer look.&lt;/p&gt;
&lt;h2 id=&quot;2-train-a-new-spec2vec-model-from-scratch&quot;&gt;2. Train a new Spec2Vec model from scratch&lt;/h2&gt;
&lt;p&gt;Training a Spec2Vec model is fairly straightforward and relatively fast (usually minutes to one hour max). In general, training a new model from scratch makes sense when a lot a data is present to train on as it gives more options to optimize the results when compared to simply using a pretrained model as done above.&lt;/p&gt;
&lt;p&gt;First, the spectrum data has to be converted into “documents” where peaks and neutral losses have become “words” (e.g. &lt;code&gt;peak@289.29&lt;/code&gt;). This can be done by running:&lt;/p&gt;
&lt;p&gt;from spec2vec import SpectrumDocumentspectrum_documents = [SpectrumDocument(s, n_decimals=2) for s in spectrums]Then, a new model can simply be trained by using &lt;code&gt;train_new_word2vec_model&lt;/code&gt;. The following code will create a new model which is trained for 25 iterations (for machine learning people: that is ”epochs”) on 2 workers (you can change this, e.g. to 4 if you have 4 cores, the difference is not drastic though). Depending on your hardware, the training of this model should not take longer than a couple of minutes.&lt;/p&gt;
&lt;p&gt;from spec2vec.model_building import train_new_word2vec_modelmodel_file = “tutorial_model.model”**model = train_new_word2vec_model(spectrum_documents, iterations=[25], filename=model_file,
workers=2, progress_logger=True)The above code snippet will automatically save the model under the name &lt;code&gt;tutorial_model.model&lt;/code&gt;, which could later load again by running &lt;code&gt;model = gensim.models.Word2Vec.load(&quot;tutorial_model.model&quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;calculate-spectrum-similarities&quot;&gt;Calculate spectrum similarities&lt;/h3&gt;
&lt;p&gt;Once we have our trained model we can again (as above with the pretrained model) compute spectrum similarities.&lt;/p&gt;
&lt;p&gt;from matchms import calculate_scores
from spec2vec import Spec2Vecspec2vec_similarity = Spec2Vec(model=model, intensity_weighting_power=0.5,
allowed_missing_percentage=5.0)scores = calculate_scores(spectrum_documents, spectrum_documents, spec2vec_similarity, is_symmetric=True)Here again we can search for the best matching compounds according to Spec2Vec.&lt;/p&gt;
&lt;p&gt;best_matches = scores.scores_by_query(spectrum_documents[11], sort=True)[:10]
[x[0].get(“smiles”) for x in best_matches]And we can plot the resulting smiles to .png files by running:&lt;/p&gt;
&lt;p&gt;from rdkit import Chem
from rdkit.Chem import Drawfor i, smiles in enumerate([x[0].get(“smiles”) for x in best_matches]):
m = Chem.MolFromSmiles(smiles)
Draw.MolToFile(m, f”compound_{i}.png”)The best 8 matches are plotted in Figure 3**.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 3.&lt;/strong&gt; Compounds of the highest 9 Spec2Vec similarity scores within the dataset with respect to spectrums[11], the first being the spectrum of interest itself (hence “query compound”).This example in figure 3 looks already quiet promising and all selected candidates clearly show chemical similarities! But this is of course just one mostly random pick out of many spectra. In our &lt;a href=&quot;https://www.biorxiv.org/content/10.1101/2020.08.11.245928v2&quot;&gt;Spec2Vec paper&lt;/a&gt; we compared the different similarity scores (Cosine, modified Cosine, Spec2Vec) in much more detail and found that Spec2Vec often — but not always — outperformed the classical scores. We also found a general trend that such scores are generally more reliable for larger compounds, supposedly because those will come with a higher number of chemically meaningful fragments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 4.&lt;/strong&gt; Working with different datasets from GNPS we evaluated the quality of Spec2Vec based spectrum suggestions and found that they get better with increasing compound mass. Taken from &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;Spec2Vec article&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OK. Done for now. Really curious to see what you can get out of Spec2Vec!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;other-parts-of-this-tutorial&quot;&gt;Other parts of this tutorial&lt;/h2&gt;
&lt;h3 id=&quot;part-i--build-you-own-mass-spectrometry-pipeline&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-your-own-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-i-d96c718c68ee&quot;&gt;part I — Build you own mass spectrometry pipeline&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-ii--compute-spectra-similarities-using-spec2vec&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-ii-spec2vec-8aa639571018&quot;&gt;part II — Compute spectra similarities using Spec2Vec&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-iii--network-analysis-based-on-spectra-similarities&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-iii-molecular-91891248ee34&quot;&gt;part III — Network analysis based on spectra similarities&lt;/a&gt;&lt;/h3&gt;
&lt;h2 id=&quot;matchms-library&quot;&gt;matchms library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;matchms&lt;/strong&gt;* is freely available and open-source. You can find the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/matchms&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/matchms/&quot;&gt;from pypi&lt;/a&gt;. It was developed by a bunch of very nice people (see &lt;a href=&quot;https://github.com/matchms/matchms/blob/master/CITATION.cff&quot;&gt;here&lt;/a&gt;) and is &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;published in Joss&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;spec2vec-library&quot;&gt;spec2vec library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Spec2Vec&lt;/strong&gt; is of course also freely available and open-source. You can find the &lt;a href=&quot;https://github.com/iomega/spec2vec&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/spec2vec&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/spec2vec/&quot;&gt;from pypi&lt;/a&gt;. The &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;article published in PLOS Computational Biology can be found here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find more information in the &lt;a href=&quot;https://matchms.readthedocs.io/en/latest/&quot;&gt;matchms documentation&lt;/a&gt; and the &lt;a href=&quot;https://spec2vec.readthedocs.io/en/latest/?badge=latest&quot;&gt;spec2vec documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;
&lt;p&gt;The code shown in this blog post can also be found &lt;a href=&quot;https://github.com/matchms/matchms/blob/tutorial/tutorial/matchms_tutorial_02_compute_similarities_with_Spec2Vec.ipynb&quot;&gt;as Jupyter notebook on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;help-us-develop-matchms-and-spec2vec-further&quot;&gt;Help us develop matchms and spec2vec further!&lt;/h2&gt;
&lt;p&gt;We really hope that matchms will help people to build new, better analysis pipelines and that spec2vec can improve your analysis results. So, please help us to further improve matchms and spec2vec. You can help us by &lt;strong&gt;(1)&lt;/strong&gt; Cite our work if you use our package for your research: &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;matchms article in JOSS,&lt;/a&gt; &lt;a href=&quot;https://journals.plos.org/ploscompbiol/article?id=10.1371%2Fjournal.pcbi.1008724&quot;&gt;spec2vec article in PLOS Computational Biology&lt;/a&gt;.&lt;strong&gt;(2)&lt;/strong&gt; Let us know if you run into any issues using matchms and/or spec2vec, or if you are missing any key functionalities! You can simply do so by starting a new issue on the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;matchms GitHub repository,&lt;/a&gt; or contact me on twitter &lt;a href=&quot;https://twitter.com/me_datapoint?lang=en&quot;&gt;@me_datapoint&lt;/a&gt;.&lt;strong&gt;You are of course more than welcome to also become an active contributor to the package and help extend its functionality!
(3)&lt;/strong&gt; Please let us know if you successfully applied matchms and/or spec2vec in your research project (makes us happy + we can maybe share the good news!).&lt;/p&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
&lt;p&gt;I would like to thank [Carlos Martinez-Ortiz], [Justin van der Hooft] and [Kontoueftychia] for helpful comments and suggestions on this blog post.&lt;/p&gt;</content:encoded><author>Florian Huber</author></item><item><title>Build your own mass spectrometry analysis pipeline in Python using matchms — part I</title><link>https://blog.esciencecenter.nl/posts/2023-01-31---build-your-own-mass-spectrometry-analysis-pipeline-in-python</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-01-31---build-your-own-mass-spectrometry-analysis-pipeline-in-python</guid><description>&lt;h2 id=&quot;python-is-a-very-powerful-language-and-brings-the-potential-for-designing-computational-mass-spectrometry-analysis-workflows-of-any-desired-type-and-complexity-here-you-can-find-a-quick-introduction-on-how-to-import-process-and-analyze-a-tandem-mass-spectra-dataset-using-python-and-matchms&quot;&gt;Python is a very powerful language and brings the potential for designing computational mass spectrometry analysis workflows of any desired type and complexity. Here, you can find a quick introduction on how to import, process, and analyze a tandem mass spectra dataset using Python and matchms.&lt;/h2&gt;
&lt;p&gt;Let’s first inspect what scores we have by running:&lt;/p&gt;
&lt;p&gt;scores.score_namesLet’s inspect some of the number of matching peaks by first converting our sparse score array into a regular Numpy array and then slicing the first 5x5 entries:&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()
scores_array[:5, :5][“CosineGreedy_score”]or access the corresponding number of matching peaks by running:&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()
scores_array[:5, :5][“CosineGreedy_matches”]&lt;/p&gt;
&lt;h3 id=&quot;get-most-similar-spectra-for-spectrum-of-interest&quot;&gt;Get most similar spectra for spectrum of interest&lt;/h3&gt;
&lt;p&gt;If we want to see which spectra are most similar to the i-th spectrum (according to the here used Cosine score), then we can call:&lt;/p&gt;
&lt;p&gt;best_matches = scores.scores_by_query(spectrums[5], name=“CosineGreedy_score”, sort=True)[:10]
print([x[1] for x in best_matches])which returns the scores for the top-10 candidates (Cosine score + number of matching peaks):&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 30),
(0.99711049, 2),
(0.99534901, 2),
(0.99214557, 2),
(0.98748381, 2),
(0.98461111, 3),
(0.98401833, 2),
(0.97598497, 2),
(0.9757458, 2),
(0.97547771, 2)]The first, highest ranked results is the spectrum itself, but what are those other candidates, all with pretty high Cosine scores? Let’s find out by looking at the respective smiles (&lt;a href=&quot;https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system&quot;&gt;smiles&lt;/a&gt; are notations for the chemical structure of the compounds):&lt;/p&gt;
&lt;p&gt;[x[0].get(“smiles”) for x in best_matches]which here returns:&lt;/p&gt;
&lt;p&gt;Out[]:[‘OC(COC(=O)c1ccccc1)C(O)C(O)COC(=O)c2ccccc2’,
‘Cc1cc(=O)oc2cc(OC(=O)c3ccccc3)ccc12’,
‘O=C(Nc1ccccc1OC(=O)c2ccccc2)c3ccccc3’,
‘COc1cc(CC=C)ccc1OC(=O)c2ccccc2’,
‘O=C(OCC1OC(C(OC(=O)c2ccccc2)C1OC(=O)c3ccccc3)n4ncc(=O)[nH]c4=O)c5ccccc5’,
‘O=C(Oc1cccc2ccccc12)c3ccccc3’,
‘O=C(N1&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C#N&quot;&gt;C@@H&lt;/a&gt;C2OC2c3ccccc13)c4ccccc4’,
‘COC(=O)CNC(=O)c1ccccc1’,
‘COc1c2OCOc2cc(CCN(C)C(=O)c3ccccc3)c1C=C4C(=O)NC(=O)NC4=O’,
‘COc1c2OCOc2cc(CCN(C)C(=O)c3ccccc3)c1/C=C\4/C(=O)NC(=O)N(C)C4=O’]For those who are not used to reading smiles all the time (like me), let’s display the structures. There are many online and offline tools for plotting structures from smiles. Here, I used the Python package &lt;a href=&quot;https://www.rdkit.org/&quot;&gt;rdkit&lt;/a&gt; for it by running:&lt;/p&gt;
&lt;p&gt;from rdkit import Chem
from rdkit.Chem import Drawfor i, smiles in enumerate([x[0].get(“smiles”) for x in    best_matches]):
m = Chem.MolFromSmiles(smiles)
Draw.MolToFile(m, f”compound_{i}.png”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-b73e3c5e.DXzNQPN6_2fRDxG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4.** Compounds of the highest 9 Cosine scores within the dataset with respect to spectrums[5], the first being the spectrum of interest itself (hence named “query compound”).&lt;/p&gt;
&lt;h3 id=&quot;alternative-get-best-matches-above-min_match-threshold&quot;&gt;Alternative: Get best matches above ‘min_match’ threshold&lt;/h3&gt;
&lt;p&gt;Maybe having two matching peaks is not good enough and you want to be more certain of your Cosine score based candidates. Let’s then only consider the best Cosine scores for which we have at least min_match* matches:&lt;/p&gt;
&lt;p&gt;min_match = 5**sorted_matches = scores.scores_by_query(spectrums[5], name=“CosineGreedy_score”, sort=True)
best_matches = [x for x in sorted_matches if x[1][“CosineGreedy_matches”] &gt;= min_match][:10][x[1] for x in best_matches]which will give a very different result than the previous run. Here we do not find any other spectrum in the dataset that shows a very high Cosine score (again, except the first entry which is the similarity of the spectrum with itself and hence obviously = 1):&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 30),
(0.44857215, 6),
(0.39605775, 5),
(0.33880658, 5),
(0.03942863, 6),
(0.03429136, 5),
(0.03028157, 5),
(0.02845932, 5),
(0.01924283, 7),
(0.01890612, 5)]&lt;/p&gt;
&lt;h2 id=&quot;4-compute-spectra-similarities-modified-cosine-score&quot;&gt;4. Compute spectra similarities: Modified Cosine score&lt;/h2&gt;
&lt;p&gt;The modified cosine score aims at quantifying the similarity between two mass spectra. Unlike the Cosine score it does not only look at nearly identical spectra, but also considers the mass shift between two compounds. The score is calculated by finding best possible matches between peaks of two spectra. Two peaks are considered a potential match if their m/z ratios lie within the given ‘tolerance’, or if their m/z ratios lie within the tolerance once a mass-shift is applied. The mass shift is simply the difference in precursor-m/z between the two spectra. See &lt;a href=&quot;https://www.pnas.org/content/109/26/E1743&quot;&gt;Watrous et al. (PNAS, 2012)&lt;/a&gt; for further details.&lt;/p&gt;
&lt;p&gt;As done above for the Cosine score, we can calculate the similarities for all possible spectrum pairs by running:&lt;/p&gt;
&lt;p&gt;from matchms.similarity import ModifiedCosinesimilarity_measure = ModifiedCosine(tolerance=0.005)
scores = calculate_scores(spectrums, spectrums, similarity_measure,
is_symmetric=True)Let’s then visualize the results for the first 50 x 50 spectrum pairs.&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()plt.figure(figsize=(6,6), dpi=150)
plt.imshow(scores_array[:50, :50][“score”], cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Modified Cosine spectra similarities”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;584&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-b0ee4396.TFNu_jSz_ZuxCvP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5.** Modified Cosine scores for all possible pairs between the first 50 imported spectrums. As to be expected, the diagonal is always =1 (score for spectrum with itself). But also several other very high Modified Cosine scores stick out suggesting highly related spectra.Now, let’s accept Modified Cosine scores for a minimum number of matching peaks (min_match).&lt;/p&gt;
&lt;p&gt;min_match = 5plt.figure(figsize=(6,6), dpi=150)**plt.imshow(scores_array[:50, :50][“ModifiedCosine_score”] &lt;br&gt;
* (scores_array[:50, :50][“ModifiedCosine_matches”] &gt;= min_match), cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Modified Cosine spectra similarities (min_match=5)”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;607&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-5d737491.DuPLDQy9_ZJDWiI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 6.** Modified Cosine scores for all possible pairs between the first 50 imported spectrums (with ≥ 5 matching peaks!).There’s for instance a bright spot far outside the diagonal for &lt;code&gt;spectrums[11]&lt;/code&gt; so let’s have a look at that one!&lt;/p&gt;
&lt;p&gt;min_match = 5sorted_matches = scores.scores_by_query(spectrums[11], name=“ModifiedCosine_score”, sort=True)**best_matches = [x for x in sorted_matches if x[1][“ModifiedCosine_matches”] &gt;= min_match][:10]
[x[1] for x in best_matches]Which gives&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 151),
(0.95295779, 15),
(0.94542762, 13),
(0.89735889, 17),
(0.7886489, 12),
(0.77433041, 9),
(0.74935776, 8),
(0.72854032, 8),
(0.55896333, 7),
(0.52331993, 9)]And, probably more interesting, the corresponding smiles:&lt;/p&gt;
&lt;p&gt;[x[0].get(“smiles”) for x in best_matches]Out[]:[‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/CC(=O)O&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CCCCCC(NC(=O)C1CCN(CC1)C(=O)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c2ccc(C)cc2&quot;&gt;C@@H&lt;/a&gt;C(C)C)C(=O)O’,
‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(=O)O&quot;&gt;C@H&lt;/a&gt;c3ccccc3’,
‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/CCC(=O)N&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘COC(=O)C1CCN(CC1)C(=O)C2CCN(CC2)C(=O)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c3ccc(C)cc3&quot;&gt;C@@H&lt;/a&gt;C(C)C’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(=O)O&quot;&gt;C@H&lt;/a&gt;c3ccccc3’,
‘CC(C)C&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(C)C&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CC(C)C&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/Cc3ccccc3&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N3CCC(CC3)C(=O)N’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N3CCC(CC3)C(=O)OC’]OK, smiles, nice. But let’s better move on and have a look at how those compounds actually look like (as above, plotted using rdkit):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;548&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-f6234fec.BUqASEbP_Z2ulvye.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 7.** Compounds of the highest 9 modified Cosine scores within the dataset with respect to spectrums[11], the first being the spectrum of interest itself (hence “query compound”).I wouldn’t dare calling myself a natural product expert. But those chemical structures clearly do look more consistent to what we saw in Figure 4…&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now it’s up to you to come up with things to do with this ;)&lt;/p&gt;
&lt;p&gt;I hope this helped you getting started with using &lt;em&gt;&lt;strong&gt;matchms&lt;/strong&gt;&lt;/em&gt; for working with your MS/MS data! Soon there will be additional tutorials to go a bit more depth:&lt;/p&gt;
&lt;h2 id=&quot;other-parts-of-this-tutorial&quot;&gt;Other parts of this tutorial&lt;/h2&gt;
&lt;h3 id=&quot;part-i--build-you-own-mass-spectrometry-pipeline&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-your-own-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-i-d96c718c68ee&quot;&gt;part I — Build you own mass spectrometry pipeline&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-ii--compute-spectra-similarities-using-spec2vec&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-ii-spec2vec-8aa639571018&quot;&gt;part II — Compute spectra similarities using Spec2Vec&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-iii--network-analysis-based-on-spectra-similarities&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-iii-molecular-91891248ee34&quot;&gt;part III — Network analysis based on spectra similarities&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;matchms-library&quot;&gt;matchms library&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;matchms&lt;/strong&gt;&lt;/em&gt; is freely available and open-source. You can find the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/matchms&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/matchms/&quot;&gt;from pypi&lt;/a&gt;. It was developed by a bunch of very nice people (see &lt;a href=&quot;https://github.com/matchms/matchms/blob/master/CITATION.cff&quot;&gt;here&lt;/a&gt;) and is &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;published in Joss&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find more information in the &lt;a href=&quot;https://matchms.readthedocs.io/en/latest/&quot;&gt;matchms documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;code&quot;&gt;Code&lt;/h3&gt;
&lt;p&gt;The code shown in this blog post can also be found as &lt;a href=&quot;https://github.com/matchms/matchms/blob/tutorial/tutorial/matchms_tutorial_01_building_analysis_pipeline.ipynb&quot;&gt;a Jupyter notebook here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;help-us-develop-matchms-further&quot;&gt;Help us develop matchms further!&lt;/h3&gt;
&lt;p&gt;We really hope that matchms will help people to build new, better analysis pipelines. So, please help us to further improve matchms. You can help us by &lt;strong&gt;(1)&lt;/strong&gt; Cite our work if you use our package for your research: &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;matchms article in JOSS&lt;/a&gt;.&lt;strong&gt;(2)&lt;/strong&gt; Let us know if you run into any issues using matchms, or if you are missing any key functionalities! You can simply do so by starting a new issue on the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;matchms GitHub repository,&lt;/a&gt; or contact me on twitter &lt;a href=&quot;https://twitter.com/me_datapoint?lang=en&quot;&gt;@me_datapoint&lt;/a&gt;.&lt;strong&gt;You are of course more than welcome to also become an active contributor to the package and help extend its functionality!
(3)&lt;/strong&gt; Please let us know if you successfully applied matchms in your research project (makes us happy + we can maybe share the good news!).&lt;/p&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
&lt;p&gt;I would like to thank [Carlos Martinez-Ortiz,] [Jorislouwen], Niek de Jonge, [Justin van der Hooft] for helpful comments and suggestions on this blog post.&lt;/p&gt;</description><pubDate>Tue, 31 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;python-is-a-very-powerful-language-and-brings-the-potential-for-designing-computational-mass-spectrometry-analysis-workflows-of-any-desired-type-and-complexity-here-you-can-find-a-quick-introduction-on-how-to-import-process-and-analyze-a-tandem-mass-spectra-dataset-using-python-and-matchms&quot;&gt;Python is a very powerful language and brings the potential for designing computational mass spectrometry analysis workflows of any desired type and complexity. Here, you can find a quick introduction on how to import, process, and analyze a tandem mass spectra dataset using Python and matchms.&lt;/h2&gt;
&lt;p&gt;Let’s first inspect what scores we have by running:&lt;/p&gt;
&lt;p&gt;scores.score_namesLet’s inspect some of the number of matching peaks by first converting our sparse score array into a regular Numpy array and then slicing the first 5x5 entries:&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()
scores_array[:5, :5][“CosineGreedy_score”]or access the corresponding number of matching peaks by running:&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()
scores_array[:5, :5][“CosineGreedy_matches”]&lt;/p&gt;
&lt;h3 id=&quot;get-most-similar-spectra-for-spectrum-of-interest&quot;&gt;Get most similar spectra for spectrum of interest&lt;/h3&gt;
&lt;p&gt;If we want to see which spectra are most similar to the i-th spectrum (according to the here used Cosine score), then we can call:&lt;/p&gt;
&lt;p&gt;best_matches = scores.scores_by_query(spectrums[5], name=“CosineGreedy_score”, sort=True)[:10]
print([x[1] for x in best_matches])which returns the scores for the top-10 candidates (Cosine score + number of matching peaks):&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 30),
(0.99711049, 2),
(0.99534901, 2),
(0.99214557, 2),
(0.98748381, 2),
(0.98461111, 3),
(0.98401833, 2),
(0.97598497, 2),
(0.9757458, 2),
(0.97547771, 2)]The first, highest ranked results is the spectrum itself, but what are those other candidates, all with pretty high Cosine scores? Let’s find out by looking at the respective smiles (&lt;a href=&quot;https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system&quot;&gt;smiles&lt;/a&gt; are notations for the chemical structure of the compounds):&lt;/p&gt;
&lt;p&gt;[x[0].get(“smiles”) for x in best_matches]which here returns:&lt;/p&gt;
&lt;p&gt;Out[]:[‘OC(COC(=O)c1ccccc1)C(O)C(O)COC(=O)c2ccccc2’,
‘Cc1cc(=O)oc2cc(OC(=O)c3ccccc3)ccc12’,
‘O=C(Nc1ccccc1OC(=O)c2ccccc2)c3ccccc3’,
‘COc1cc(CC=C)ccc1OC(=O)c2ccccc2’,
‘O=C(OCC1OC(C(OC(=O)c2ccccc2)C1OC(=O)c3ccccc3)n4ncc(=O)[nH]c4=O)c5ccccc5’,
‘O=C(Oc1cccc2ccccc12)c3ccccc3’,
‘O=C(N1&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C#N&quot;&gt;C@@H&lt;/a&gt;C2OC2c3ccccc13)c4ccccc4’,
‘COC(=O)CNC(=O)c1ccccc1’,
‘COc1c2OCOc2cc(CCN(C)C(=O)c3ccccc3)c1C=C4C(=O)NC(=O)NC4=O’,
‘COc1c2OCOc2cc(CCN(C)C(=O)c3ccccc3)c1/C=C\4/C(=O)NC(=O)N(C)C4=O’]For those who are not used to reading smiles all the time (like me), let’s display the structures. There are many online and offline tools for plotting structures from smiles. Here, I used the Python package &lt;a href=&quot;https://www.rdkit.org/&quot;&gt;rdkit&lt;/a&gt; for it by running:&lt;/p&gt;
&lt;p&gt;from rdkit import Chem
from rdkit.Chem import Drawfor i, smiles in enumerate([x[0].get(“smiles”) for x in    best_matches]):
m = Chem.MolFromSmiles(smiles)
Draw.MolToFile(m, f”compound_{i}.png”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-b73e3c5e.DXzNQPN6_2fRDxG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4.** Compounds of the highest 9 Cosine scores within the dataset with respect to spectrums[5], the first being the spectrum of interest itself (hence named “query compound”).&lt;/p&gt;
&lt;h3 id=&quot;alternative-get-best-matches-above-min_match-threshold&quot;&gt;Alternative: Get best matches above ‘min_match’ threshold&lt;/h3&gt;
&lt;p&gt;Maybe having two matching peaks is not good enough and you want to be more certain of your Cosine score based candidates. Let’s then only consider the best Cosine scores for which we have at least min_match* matches:&lt;/p&gt;
&lt;p&gt;min_match = 5**sorted_matches = scores.scores_by_query(spectrums[5], name=“CosineGreedy_score”, sort=True)
best_matches = [x for x in sorted_matches if x[1][“CosineGreedy_matches”] &gt;= min_match][:10][x[1] for x in best_matches]which will give a very different result than the previous run. Here we do not find any other spectrum in the dataset that shows a very high Cosine score (again, except the first entry which is the similarity of the spectrum with itself and hence obviously = 1):&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 30),
(0.44857215, 6),
(0.39605775, 5),
(0.33880658, 5),
(0.03942863, 6),
(0.03429136, 5),
(0.03028157, 5),
(0.02845932, 5),
(0.01924283, 7),
(0.01890612, 5)]&lt;/p&gt;
&lt;h2 id=&quot;4-compute-spectra-similarities-modified-cosine-score&quot;&gt;4. Compute spectra similarities: Modified Cosine score&lt;/h2&gt;
&lt;p&gt;The modified cosine score aims at quantifying the similarity between two mass spectra. Unlike the Cosine score it does not only look at nearly identical spectra, but also considers the mass shift between two compounds. The score is calculated by finding best possible matches between peaks of two spectra. Two peaks are considered a potential match if their m/z ratios lie within the given ‘tolerance’, or if their m/z ratios lie within the tolerance once a mass-shift is applied. The mass shift is simply the difference in precursor-m/z between the two spectra. See &lt;a href=&quot;https://www.pnas.org/content/109/26/E1743&quot;&gt;Watrous et al. (PNAS, 2012)&lt;/a&gt; for further details.&lt;/p&gt;
&lt;p&gt;As done above for the Cosine score, we can calculate the similarities for all possible spectrum pairs by running:&lt;/p&gt;
&lt;p&gt;from matchms.similarity import ModifiedCosinesimilarity_measure = ModifiedCosine(tolerance=0.005)
scores = calculate_scores(spectrums, spectrums, similarity_measure,
is_symmetric=True)Let’s then visualize the results for the first 50 x 50 spectrum pairs.&lt;/p&gt;
&lt;p&gt;scores_array = scores.scores.to_array()plt.figure(figsize=(6,6), dpi=150)
plt.imshow(scores_array[:50, :50][“score”], cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Modified Cosine spectra similarities”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;584&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-b0ee4396.TFNu_jSz_ZuxCvP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5.** Modified Cosine scores for all possible pairs between the first 50 imported spectrums. As to be expected, the diagonal is always =1 (score for spectrum with itself). But also several other very high Modified Cosine scores stick out suggesting highly related spectra.Now, let’s accept Modified Cosine scores for a minimum number of matching peaks (min_match).&lt;/p&gt;
&lt;p&gt;min_match = 5plt.figure(figsize=(6,6), dpi=150)**plt.imshow(scores_array[:50, :50][“ModifiedCosine_score”] &lt;br&gt;
* (scores_array[:50, :50][“ModifiedCosine_matches”] &gt;= min_match), cmap=“viridis”)
plt.colorbar(shrink=0.7)
plt.title(“Modified Cosine spectra similarities (min_match=5)”)
plt.xlabel(“Spectrum #ID”)
plt.ylabel(“Spectrum #ID”)
&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;607&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-5d737491.DuPLDQy9_ZJDWiI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 6.** Modified Cosine scores for all possible pairs between the first 50 imported spectrums (with ≥ 5 matching peaks!).There’s for instance a bright spot far outside the diagonal for &lt;code&gt;spectrums[11]&lt;/code&gt; so let’s have a look at that one!&lt;/p&gt;
&lt;p&gt;min_match = 5sorted_matches = scores.scores_by_query(spectrums[11], name=“ModifiedCosine_score”, sort=True)**best_matches = [x for x in sorted_matches if x[1][“ModifiedCosine_matches”] &gt;= min_match][:10]
[x[1] for x in best_matches]Which gives&lt;/p&gt;
&lt;p&gt;Out[]:[(1., 151),
(0.95295779, 15),
(0.94542762, 13),
(0.89735889, 17),
(0.7886489, 12),
(0.77433041, 9),
(0.74935776, 8),
(0.72854032, 8),
(0.55896333, 7),
(0.52331993, 9)]And, probably more interesting, the corresponding smiles:&lt;/p&gt;
&lt;p&gt;[x[0].get(“smiles”) for x in best_matches]Out[]:[‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/CC(=O)O&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CCCCCC(NC(=O)C1CCN(CC1)C(=O)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c2ccc(C)cc2&quot;&gt;C@@H&lt;/a&gt;C(C)C)C(=O)O’,
‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(=O)O&quot;&gt;C@H&lt;/a&gt;c3ccccc3’,
‘CC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/CCC(=O)N&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘COC(=O)C1CCN(CC1)C(=O)C2CCN(CC2)C(=O)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c3ccc(C)cc3&quot;&gt;C@@H&lt;/a&gt;C(C)C’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(=O)O&quot;&gt;C@H&lt;/a&gt;c3ccccc3’,
‘CC(C)C&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/C(C)C&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CC(C)C&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N&lt;a href=&quot;https://blog.esciencecenter.nl/posts/Cc3ccccc3&quot;&gt;C@@H&lt;/a&gt;C(=O)O’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N3CCC(CC3)C(=O)N’,
‘CCC(C)&lt;a href=&quot;https://blog.esciencecenter.nl/posts/NS(=O)(=O)c1ccc(C)cc1&quot;&gt;C@H&lt;/a&gt;C(=O)N2CCC(CC2)C(=O)N3CCC(CC3)C(=O)OC’]OK, smiles, nice. But let’s better move on and have a look at how those compounds actually look like (as above, plotted using rdkit):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Build your own mass spectrometry analysis pipeline in Python using matchms — part I&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;548&quot; src=&quot;https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-f6234fec.BUqASEbP_Z2ulvye.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 7.** Compounds of the highest 9 modified Cosine scores within the dataset with respect to spectrums[11], the first being the spectrum of interest itself (hence “query compound”).I wouldn’t dare calling myself a natural product expert. But those chemical structures clearly do look more consistent to what we saw in Figure 4…&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now it’s up to you to come up with things to do with this ;)&lt;/p&gt;
&lt;p&gt;I hope this helped you getting started with using &lt;em&gt;&lt;strong&gt;matchms&lt;/strong&gt;&lt;/em&gt; for working with your MS/MS data! Soon there will be additional tutorials to go a bit more depth:&lt;/p&gt;
&lt;h2 id=&quot;other-parts-of-this-tutorial&quot;&gt;Other parts of this tutorial&lt;/h2&gt;
&lt;h3 id=&quot;part-i--build-you-own-mass-spectrometry-pipeline&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-your-own-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-i-d96c718c68ee&quot;&gt;part I — Build you own mass spectrometry pipeline&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-ii--compute-spectra-similarities-using-spec2vec&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-ii-spec2vec-8aa639571018&quot;&gt;part II — Compute spectra similarities using Spec2Vec&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;part-iii--network-analysis-based-on-spectra-similarities&quot;&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/build-a-mass-spectrometry-analysis-pipeline-in-python-using-matchms-part-iii-molecular-91891248ee34&quot;&gt;part III — Network analysis based on spectra similarities&lt;/a&gt;&lt;/h3&gt;
&lt;h3 id=&quot;matchms-library&quot;&gt;matchms library&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;matchms&lt;/strong&gt;&lt;/em&gt; is freely available and open-source. You can find the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;code on Github&lt;/a&gt;, the package is available as &lt;a href=&quot;https://anaconda.org/nlesc/matchms&quot;&gt;conda package&lt;/a&gt; (recommended) or &lt;a href=&quot;https://pypi.org/project/matchms/&quot;&gt;from pypi&lt;/a&gt;. It was developed by a bunch of very nice people (see &lt;a href=&quot;https://github.com/matchms/matchms/blob/master/CITATION.cff&quot;&gt;here&lt;/a&gt;) and is &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;published in Joss&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find more information in the &lt;a href=&quot;https://matchms.readthedocs.io/en/latest/&quot;&gt;matchms documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;code&quot;&gt;Code&lt;/h3&gt;
&lt;p&gt;The code shown in this blog post can also be found as &lt;a href=&quot;https://github.com/matchms/matchms/blob/tutorial/tutorial/matchms_tutorial_01_building_analysis_pipeline.ipynb&quot;&gt;a Jupyter notebook here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;help-us-develop-matchms-further&quot;&gt;Help us develop matchms further!&lt;/h3&gt;
&lt;p&gt;We really hope that matchms will help people to build new, better analysis pipelines. So, please help us to further improve matchms. You can help us by &lt;strong&gt;(1)&lt;/strong&gt; Cite our work if you use our package for your research: &lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.02411&quot;&gt;matchms article in JOSS&lt;/a&gt;.&lt;strong&gt;(2)&lt;/strong&gt; Let us know if you run into any issues using matchms, or if you are missing any key functionalities! You can simply do so by starting a new issue on the &lt;a href=&quot;https://github.com/matchms/matchms&quot;&gt;matchms GitHub repository,&lt;/a&gt; or contact me on twitter &lt;a href=&quot;https://twitter.com/me_datapoint?lang=en&quot;&gt;@me_datapoint&lt;/a&gt;.&lt;strong&gt;You are of course more than welcome to also become an active contributor to the package and help extend its functionality!
(3)&lt;/strong&gt; Please let us know if you successfully applied matchms in your research project (makes us happy + we can maybe share the good news!).&lt;/p&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
&lt;p&gt;I would like to thank [Carlos Martinez-Ortiz,] [Jorislouwen], Niek de Jonge, [Justin van der Hooft] for helpful comments and suggestions on this blog post.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/build-your-own-mass-spectrometry-analysi-b73e3c5e.DXzNQPN6.png" medium="image"/><author>Florian Huber</author></item><item><title>An applied mathematician meets software engineering</title><link>https://blog.esciencecenter.nl/posts/2023-01-26---an-applied-mathematician-meets-software-engineering</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-01-26---an-applied-mathematician-meets-software-engineering</guid><description>&lt;p&gt;How software engineering practices helped me bridge the gap between mathematics and other fields&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_cJAE3sgoAlTXMc4E-ebafd1fe.DtApvtee_ZmMywD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Mick Haupt on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;from-industry-to-academia&quot;&gt;From industry to academia&lt;/h2&gt;
&lt;p&gt;Let’s go backward to 2015. Back then, I had a degree in theoretical &lt;strong&gt;physics&lt;/strong&gt; and a 3-year professional experience in industrial software &lt;strong&gt;engineering&lt;/strong&gt;. All of it spiced with many semi-professional activities in &lt;strong&gt;science communication&lt;/strong&gt;. At the end of that year, I was hired as an applied &lt;strong&gt;mathematician&lt;/strong&gt; at an aquatic &lt;strong&gt;ecology&lt;/strong&gt; department, in order to perform a PhD.&lt;/p&gt;
&lt;p&gt;In short: physics, engineering, communication, mathematics, and ecology, … it was the quintessential multidisciplinary job.&lt;/p&gt;
&lt;p&gt;As often happens, one of the disciplines was overrepresented. This happened just naturally: I was working in an aquatic ecology group, inside an ecology building, on a campus specialized in biology, in a city nicknamed “the city of life sciences”. So biologists outnumbered non-biologists at around a 9 to 1 ratio. Indeed, I was the only physicist in the group, and also the only one with engineering experience. This meant that I was expected to adapt my academic culture to theirs, not the other way around. And rightfully so. Summarizing: my (mostly) mathematical background was required to produce publications interesting for an audience of (mostly) biologists.&lt;/p&gt;
&lt;p&gt;What about the biologists’ mathematical background? Well, something I learned is that any preconceived assumption in this direction will fail. Some biologists just don’t like mathematics (just like many other humans), while others are really interested and proficient at it. One way or another, I was supposed to provide mathematical content and tools for all of them. And this posed a serious problem: how could I possibly do that without frustrating the former or boring the latter?&lt;/p&gt;
&lt;p&gt;Talking about frustration, I should also not forget about frustrating the reader. It is time to stop talking about myself and dive into an example.&lt;/p&gt;
&lt;h2 id=&quot;tracking-bugs-the-many-legged-ones&quot;&gt;Tracking bugs (the many-legged ones)&lt;/h2&gt;
&lt;p&gt;One good day, our department bought a fancy tracking device. The purpose was to observe the movements of some tiny invertebrates inside a Petri dish.&lt;/p&gt;
&lt;p&gt;The device was, essentially, a digital camera. It captured several images per second and identified the position of the bug in each of them. Then it returned a list of these positions (&lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt;) and the corresponding sampling time &lt;em&gt;t&lt;/em&gt;. The figure below shows a bug’s trajectory.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;576&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iF9f0KmFW_0FjvLyLi6Eww-b4c83a7e.BeTM0UEr_1LlXdK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Example of a bug’s trajectory&lt;/p&gt;
&lt;p&gt;The machine’s output also created some obscure and difficult-to-interpret processed data. Unnecessarily obscure, I would say. This is the kind of situation where multidisciplinarity can do its magic: there is a physicist in the room so, why not use the good-old theory of classical kinematics (the simple, elegant, and centuries-old mathematical tool for describing movement) to extract information directly from the list of positions and times?&lt;/p&gt;
&lt;p&gt;Doing this involved using numerical differentiation to extract information such as instantaneous speed, acceleration, or curvature. Still technical, but way easier to interpret than the data the machine returned by default. I presented the idea to my colleagues. Some of them liked it, while others received it with a bit of skepticism. This is understandable: most people are usually not keen to hear about differentiation and parameterized curves on a coffee break.&lt;/p&gt;
&lt;p&gt;This was when software engineering came to the rescue. What if I code this mathematical knowledge in the form of a software package? This way, the interested enough colleague can dig into the details, while the busy and/or not mathematically oriented one can just trust that the package does its work.&lt;/p&gt;
&lt;p&gt;Having both my two imaginary colleagues in mind, I followed some software engineering &lt;a href=&quot;https://journals.plos.org/plosbiology/article?id=10.1371%2Fjournal.pbio.1001745&quot;&gt;best practices&lt;/a&gt; to make &lt;strong&gt;their&lt;/strong&gt; lives easier. My package was:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Openly published&lt;/strong&gt;. So it was easy to find, install and inspect (and it &lt;a href=&quot;https://github.com/PabRod/kinematics&quot;&gt;still is&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documented in detail.&lt;/strong&gt; So it is easy to learn the basics, and possible to dive into the details if desired.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Citable.&lt;/strong&gt; So users can cite &lt;a href=&quot;https://zenodo.org/record/5107805#.Y3Y1UNLMKUk&quot;&gt;its DOI&lt;/a&gt; in their publications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Covered by unit tests&lt;/strong&gt;. So trusting the results doesn’t require a huge leap of faith. (What are unit tests? Tiny scripts that check that the package delivers what the developer expects, and that can be run again at any moment. Sounds silly but it is one of the most powerful tools I’ve learned in my stage as a software engineer).&lt;/p&gt;
&lt;p&gt;When written like this, as a proper code package, &lt;strong&gt;the tool solved a problem instead of creating a new one&lt;/strong&gt; (the problem of having to struggle with a new tool from its foundations).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;576&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ml-WjxRKZdgLxPgeWjS2IA-c2570084.F9_oZYck_Zi2lzN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The same trajectory as before, but now “enriched” with extra information, such as absolute speed and absolute acceleration&lt;/p&gt;
&lt;p&gt;Additionally, the package could be applied to any time series representing a two-dimensional movement, so it was useful for problems other than bug tracking on a Petri dish. The package proved to be interesting to other researchers (the metrics say it’s downloaded around 200 times per month), and even managed to get all its way to &lt;a href=&quot;https://cran.r-project.org/web/packages/kinematics/index.html&quot;&gt;CRAN&lt;/a&gt;, the &lt;em&gt;Mons Olympus&lt;/em&gt; of packages in R language.&lt;/p&gt;
&lt;h2 id=&quot;mathematical-talent-locked-in-a-drawer&quot;&gt;Mathematical talent locked in a drawer&lt;/h2&gt;
&lt;p&gt;Let’s imagine a parallel universe in which I never had previous experience as a software engineer. In such a universe, my package would have never taken off. Interestingly though, I’m sure I would have written the code anyways… but I don’t think I would have managed to recruit any users apart from myself. In that universe, my code will be rotting inside some portable hard drive locked in a drawer.&lt;/p&gt;
&lt;p&gt;In that universe, I wouldn’t know anything about software best practices. I know what you are thinking. “Best practices” sounds a bit like “good manners”, something desirable but not strictly necessary. Even less when you have more important stuff to do, such as writing publications. But best practices are necessary… at least if you want your methods to be usable by others, and even by your future self.&lt;/p&gt;
&lt;p&gt;At the eScience Center we often wonder how many brilliant pieces of knowledge follow this sad destiny. Do you have a great algorithm that deserves to fly free? Let us know. Perhaps we can help you!&lt;/p&gt;
&lt;p&gt;Or perhaps you want to try it yourself. If that’s the case, I recommend you start with &lt;a href=&quot;https://journals.plos.org/plosbiology/article?id=10.1371%2Fjournal.pbio.1001745&quot;&gt;&lt;em&gt;Best practices for scientific computing (Wilson, 2014)&lt;/em&gt;&lt;/a&gt;. Also, take a look at the lessons and workshops on computational skills for researchers offered by &lt;a href=&quot;https://software-carpentry.org/&quot;&gt;Software Carpentry&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 26 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;How software engineering practices helped me bridge the gap between mathematics and other fields&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_cJAE3sgoAlTXMc4E-ebafd1fe.DtApvtee_ZmMywD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Mick Haupt on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;from-industry-to-academia&quot;&gt;From industry to academia&lt;/h2&gt;
&lt;p&gt;Let’s go backward to 2015. Back then, I had a degree in theoretical &lt;strong&gt;physics&lt;/strong&gt; and a 3-year professional experience in industrial software &lt;strong&gt;engineering&lt;/strong&gt;. All of it spiced with many semi-professional activities in &lt;strong&gt;science communication&lt;/strong&gt;. At the end of that year, I was hired as an applied &lt;strong&gt;mathematician&lt;/strong&gt; at an aquatic &lt;strong&gt;ecology&lt;/strong&gt; department, in order to perform a PhD.&lt;/p&gt;
&lt;p&gt;In short: physics, engineering, communication, mathematics, and ecology, … it was the quintessential multidisciplinary job.&lt;/p&gt;
&lt;p&gt;As often happens, one of the disciplines was overrepresented. This happened just naturally: I was working in an aquatic ecology group, inside an ecology building, on a campus specialized in biology, in a city nicknamed “the city of life sciences”. So biologists outnumbered non-biologists at around a 9 to 1 ratio. Indeed, I was the only physicist in the group, and also the only one with engineering experience. This meant that I was expected to adapt my academic culture to theirs, not the other way around. And rightfully so. Summarizing: my (mostly) mathematical background was required to produce publications interesting for an audience of (mostly) biologists.&lt;/p&gt;
&lt;p&gt;What about the biologists’ mathematical background? Well, something I learned is that any preconceived assumption in this direction will fail. Some biologists just don’t like mathematics (just like many other humans), while others are really interested and proficient at it. One way or another, I was supposed to provide mathematical content and tools for all of them. And this posed a serious problem: how could I possibly do that without frustrating the former or boring the latter?&lt;/p&gt;
&lt;p&gt;Talking about frustration, I should also not forget about frustrating the reader. It is time to stop talking about myself and dive into an example.&lt;/p&gt;
&lt;h2 id=&quot;tracking-bugs-the-many-legged-ones&quot;&gt;Tracking bugs (the many-legged ones)&lt;/h2&gt;
&lt;p&gt;One good day, our department bought a fancy tracking device. The purpose was to observe the movements of some tiny invertebrates inside a Petri dish.&lt;/p&gt;
&lt;p&gt;The device was, essentially, a digital camera. It captured several images per second and identified the position of the bug in each of them. Then it returned a list of these positions (&lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt;) and the corresponding sampling time &lt;em&gt;t&lt;/em&gt;. The figure below shows a bug’s trajectory.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;576&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iF9f0KmFW_0FjvLyLi6Eww-b4c83a7e.BeTM0UEr_1LlXdK.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Example of a bug’s trajectory&lt;/p&gt;
&lt;p&gt;The machine’s output also created some obscure and difficult-to-interpret processed data. Unnecessarily obscure, I would say. This is the kind of situation where multidisciplinarity can do its magic: there is a physicist in the room so, why not use the good-old theory of classical kinematics (the simple, elegant, and centuries-old mathematical tool for describing movement) to extract information directly from the list of positions and times?&lt;/p&gt;
&lt;p&gt;Doing this involved using numerical differentiation to extract information such as instantaneous speed, acceleration, or curvature. Still technical, but way easier to interpret than the data the machine returned by default. I presented the idea to my colleagues. Some of them liked it, while others received it with a bit of skepticism. This is understandable: most people are usually not keen to hear about differentiation and parameterized curves on a coffee break.&lt;/p&gt;
&lt;p&gt;This was when software engineering came to the rescue. What if I code this mathematical knowledge in the form of a software package? This way, the interested enough colleague can dig into the details, while the busy and/or not mathematically oriented one can just trust that the package does its work.&lt;/p&gt;
&lt;p&gt;Having both my two imaginary colleagues in mind, I followed some software engineering &lt;a href=&quot;https://journals.plos.org/plosbiology/article?id=10.1371%2Fjournal.pbio.1001745&quot;&gt;best practices&lt;/a&gt; to make &lt;strong&gt;their&lt;/strong&gt; lives easier. My package was:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Openly published&lt;/strong&gt;. So it was easy to find, install and inspect (and it &lt;a href=&quot;https://github.com/PabRod/kinematics&quot;&gt;still is&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documented in detail.&lt;/strong&gt; So it is easy to learn the basics, and possible to dive into the details if desired.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Citable.&lt;/strong&gt; So users can cite &lt;a href=&quot;https://zenodo.org/record/5107805#.Y3Y1UNLMKUk&quot;&gt;its DOI&lt;/a&gt; in their publications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Covered by unit tests&lt;/strong&gt;. So trusting the results doesn’t require a huge leap of faith. (What are unit tests? Tiny scripts that check that the package delivers what the developer expects, and that can be run again at any moment. Sounds silly but it is one of the most powerful tools I’ve learned in my stage as a software engineer).&lt;/p&gt;
&lt;p&gt;When written like this, as a proper code package, &lt;strong&gt;the tool solved a problem instead of creating a new one&lt;/strong&gt; (the problem of having to struggle with a new tool from its foundations).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;576&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ml-WjxRKZdgLxPgeWjS2IA-c2570084.F9_oZYck_Zi2lzN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The same trajectory as before, but now “enriched” with extra information, such as absolute speed and absolute acceleration&lt;/p&gt;
&lt;p&gt;Additionally, the package could be applied to any time series representing a two-dimensional movement, so it was useful for problems other than bug tracking on a Petri dish. The package proved to be interesting to other researchers (the metrics say it’s downloaded around 200 times per month), and even managed to get all its way to &lt;a href=&quot;https://cran.r-project.org/web/packages/kinematics/index.html&quot;&gt;CRAN&lt;/a&gt;, the &lt;em&gt;Mons Olympus&lt;/em&gt; of packages in R language.&lt;/p&gt;
&lt;h2 id=&quot;mathematical-talent-locked-in-a-drawer&quot;&gt;Mathematical talent locked in a drawer&lt;/h2&gt;
&lt;p&gt;Let’s imagine a parallel universe in which I never had previous experience as a software engineer. In such a universe, my package would have never taken off. Interestingly though, I’m sure I would have written the code anyways… but I don’t think I would have managed to recruit any users apart from myself. In that universe, my code will be rotting inside some portable hard drive locked in a drawer.&lt;/p&gt;
&lt;p&gt;In that universe, I wouldn’t know anything about software best practices. I know what you are thinking. “Best practices” sounds a bit like “good manners”, something desirable but not strictly necessary. Even less when you have more important stuff to do, such as writing publications. But best practices are necessary… at least if you want your methods to be usable by others, and even by your future self.&lt;/p&gt;
&lt;p&gt;At the eScience Center we often wonder how many brilliant pieces of knowledge follow this sad destiny. Do you have a great algorithm that deserves to fly free? Let us know. Perhaps we can help you!&lt;/p&gt;
&lt;p&gt;Or perhaps you want to try it yourself. If that’s the case, I recommend you start with &lt;a href=&quot;https://journals.plos.org/plosbiology/article?id=10.1371%2Fjournal.pbio.1001745&quot;&gt;&lt;em&gt;Best practices for scientific computing (Wilson, 2014)&lt;/em&gt;&lt;/a&gt;. Also, take a look at the lessons and workshops on computational skills for researchers offered by &lt;a href=&quot;https://software-carpentry.org/&quot;&gt;Software Carpentry&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_iF9f0KmFW_0FjvLyLi6Eww-b4c83a7e.BeTM0UEr.png" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Why internships have a large impact</title><link>https://blog.esciencecenter.nl/posts/2023-01-19---why-internships-have-a-large-impact</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-01-19---why-internships-have-a-large-impact</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_LDbeTgeB_nX3mscs-40d92b52.CXCwdMj2_Z12d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Scott Graham on Unsplash&lt;/p&gt;
&lt;p&gt;One and a half years ago I finished my internship at the eScience Center. Based on my own experiences and those of others around me, I think that internships are a unique moment in anyone’s career. The lessons learned during this period have a big impact on your professional future.&lt;/p&gt;
&lt;p&gt;In my case, the main lesson learned was the importance of code quality for making it impactful in science. Instead of just getting code to work, I learned the value of good quality code for making it maintainable and reusable, thereby increasing the impact in my scientific field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timing is perfect&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By learning the abovementioned skills during my internship I can focus on this aspect during my PhD and truly put this lesson into action. Besides this being a very good lesson to learn in general, I think the timing of learning this during my internship actually increased the effect this lesson will have on me and on the work I do. I think this makes my personal experience a relevant example of the impact that valuable lessons can have during internships.&lt;/p&gt;
&lt;p&gt;The first reason why the timing of an internship will increase the impact is that it is very early in a career. This means that there is still a lot of room to learn new skills, and most importantly, to actually apply these skills. Especially in science, a lot of the work is done by PhD students. Therefore, learning these skills before the start of your PhD is crucial to actually still having time to apply them.&lt;/p&gt;
&lt;p&gt;But, what makes the timing of an internship so unique? If the earlier you learn something the more impact it has, why not learn it during your bachelor? Why not in high school or even earlier? The answer is that there are many unique lessons that are only valuable for very specific fields and you simply cannot learn all of them in one bachelor. Nowadays in science, you need to specialize a lot, and this makes a lesson only valuable if it is thought to someone that actually continues in a career where this lesson is relevant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spreading the word&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The second reason why a lesson learned in an internship can have a large impact is that a good lesson is also shared with colleagues and other students. Thereby any lesson you learn not only has an impact on yourself, but also on anyone else you teach. For instance, I started working as a PhD student in a bioinformatics group. Now, 1 year in, I have supervised two students and shared advice on improving code quality with them. I also shared this with multiple direct colleagues that currently implement these lessons and teach them to others. In the same way, I learn from the lessons my supervisors and direct colleagues learned.&lt;/p&gt;
&lt;p&gt;The fact that teaching others can truly increase impact can also be used as an argument to teach important lessons to people further along in their careers. Why not try to teach new lessons to a professor, or a postdoc, so they can teach the lesson learned to as many PhDs as possible, so they can spread this again? What makes this difficult is that to truly understand the value of a skill it is crucial to actually apply it. For a postdoc or a professor, it will be very difficult to find the time to get familiar enough with the lesson to be able to efficiently teach it to others as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Considering an internship?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Internships are a unique moment in your career. You are far enough in your studies that you will likely continue in a specific field, but early enough that you still have the time to learn new skills and really put them into practice. My advice to anyone starting an internship is to use this time to invest in learning new skills. I also have some advice for companies: take teaching your interns seriously, since this might have a bigger impact than you think.&lt;/p&gt;</description><pubDate>Thu, 19 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_LDbeTgeB_nX3mscs-40d92b52.CXCwdMj2_Z12d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Scott Graham on Unsplash&lt;/p&gt;
&lt;p&gt;One and a half years ago I finished my internship at the eScience Center. Based on my own experiences and those of others around me, I think that internships are a unique moment in anyone’s career. The lessons learned during this period have a big impact on your professional future.&lt;/p&gt;
&lt;p&gt;In my case, the main lesson learned was the importance of code quality for making it impactful in science. Instead of just getting code to work, I learned the value of good quality code for making it maintainable and reusable, thereby increasing the impact in my scientific field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timing is perfect&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By learning the abovementioned skills during my internship I can focus on this aspect during my PhD and truly put this lesson into action. Besides this being a very good lesson to learn in general, I think the timing of learning this during my internship actually increased the effect this lesson will have on me and on the work I do. I think this makes my personal experience a relevant example of the impact that valuable lessons can have during internships.&lt;/p&gt;
&lt;p&gt;The first reason why the timing of an internship will increase the impact is that it is very early in a career. This means that there is still a lot of room to learn new skills, and most importantly, to actually apply these skills. Especially in science, a lot of the work is done by PhD students. Therefore, learning these skills before the start of your PhD is crucial to actually still having time to apply them.&lt;/p&gt;
&lt;p&gt;But, what makes the timing of an internship so unique? If the earlier you learn something the more impact it has, why not learn it during your bachelor? Why not in high school or even earlier? The answer is that there are many unique lessons that are only valuable for very specific fields and you simply cannot learn all of them in one bachelor. Nowadays in science, you need to specialize a lot, and this makes a lesson only valuable if it is thought to someone that actually continues in a career where this lesson is relevant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spreading the word&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The second reason why a lesson learned in an internship can have a large impact is that a good lesson is also shared with colleagues and other students. Thereby any lesson you learn not only has an impact on yourself, but also on anyone else you teach. For instance, I started working as a PhD student in a bioinformatics group. Now, 1 year in, I have supervised two students and shared advice on improving code quality with them. I also shared this with multiple direct colleagues that currently implement these lessons and teach them to others. In the same way, I learn from the lessons my supervisors and direct colleagues learned.&lt;/p&gt;
&lt;p&gt;The fact that teaching others can truly increase impact can also be used as an argument to teach important lessons to people further along in their careers. Why not try to teach new lessons to a professor, or a postdoc, so they can teach the lesson learned to as many PhDs as possible, so they can spread this again? What makes this difficult is that to truly understand the value of a skill it is crucial to actually apply it. For a postdoc or a professor, it will be very difficult to find the time to get familiar enough with the lesson to be able to efficiently teach it to others as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Considering an internship?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Internships are a unique moment in your career. You are far enough in your studies that you will likely continue in a specific field, but early enough that you still have the time to learn new skills and really put them into practice. My advice to anyone starting an internship is to use this time to invest in learning new skills. I also have some advice for companies: take teaching your interns seriously, since this might have a bigger impact than you think.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_LDbeTgeB_nX3mscs-40d92b52.CXCwdMj2.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>The Data Science Centre: Digital expertise Hub at UvA</title><link>https://blog.esciencecenter.nl/posts/2023-01-12---the-data-science-centre-digital-expertise-hub-at-uva</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2023-01-12---the-data-science-centre-digital-expertise-hub-at-uva</guid><description>&lt;p&gt;This week, we interviewed &lt;a href=&quot;https://dsc.uva.nl/content/news/2022/06/interview-with-data-science-community-manager-lisa-yu.html&quot;&gt;Lisa Yu&lt;/a&gt;, Community Manager of the Data Science Center (DSC). The DSC is a coordinating hub within the University of Amsterdam (UvA) Library, launched in 2021. The need for software and skills that make researchers able to adequately deal with available data continues to grow across all research disciplines. Thanks to funding provided by the UvA Executive Board, the DSC is in a position to boost digitally driven research at UvA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: What are the DSC’s most important activities?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1078&quot; height=&quot;252&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_yEpWKc90PA3cJ3R-ZL1KjQ-4bc4c1fe.jieQD0mY_Z13fEXo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo caption: Data Science Day 2022, photographed by Monique Kooijmans&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lisa:&lt;/em&gt; The DSC hosts a variety of important activities throughout the year. In the autumn of 2022, we held our &lt;a href=&quot;https://dsc.uva.nl/content/news/2022/11/data-science-day-2022.html&quot;&gt;second annual Data Science Day&lt;/a&gt; at Startup Village in Amsterdam Science Park. More than 100 attendees from within and outside of UvA participated in this action-packed event, which consisted of morning workshops, keynote presentations and pitch presentations on a variety of data science topics.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;364&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KDJrC4sOgTTPld2cbyvlkg-54fc37ba.Bp2jqxAM_ZosolL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Data Science Centre Hackathon 2022, photographed by Monique Kooijmans&lt;/p&gt;
&lt;p&gt;Our weekly &lt;a href=&quot;https://dsc.uva.nl/programmes/coffee-and-data/coffee-and-data.html&quot;&gt;Friday Coffee and Data meet-ups&lt;/a&gt; are also very important. These meet-ups are for our DSC members and consist of free workshops and training like the &lt;a href=&quot;https://software-carpentry.org/lessons/&quot;&gt;Software Carpentry&lt;/a&gt; and Image Analysis, seminar presentations by DSC members, and collaboration sessions. Beyond this being an upskilling opportunity, it is also a chance for members to meet like-minded people from other faculties and campuses and to collaborate with each other.&lt;/p&gt;
&lt;p&gt;We update our events page regularly online, so &lt;a href=&quot;https://dsc.uva.nl/&quot;&gt;check our website&lt;/a&gt; regularly for all our upcoming planned activities!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you have an example of how the DSC has helped researchers at UvA?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our ultimate goal is to accelerate software and data-driven research at UvA, and help researchers do research they wouldn’t have otherwise been able to do. One example of how the DSC has helped achieve this is through its &lt;a href=&quot;https://dsc.uva.nl/programmes/accelerate-programme/accelerate-programme.html&quot;&gt;Accelerate programme&lt;/a&gt;, where we co-finance the hiring of data scientists (who have roles comparable to research software engineers, ed.) and data engineers within faculties.&lt;/p&gt;
&lt;p&gt;Since its launch in 2021, the Accelerate programme has led to the successful hiring of the equivalent of 18 FTE data scientists and engineers across a range of UvA faculties. The Accelerate programme has helped fund lots of cool research, ranging from how to better understand the history of early globalization and colonisation, to why people follow and break rules, to growing tomatoes!&lt;/p&gt;
&lt;p&gt;Another example of how we have helped researchers at UvA is through our Interdisciplinary PhD programme, where we have provided funding for 7 PhD students to work on a selection of interdisciplinary research projects. &lt;a href=&quot;https://dsc.uva.nl/programmes/interdisciplinary-phd-programme/interdisciplinary-phd-programme.html&quot;&gt;More information about these projects and its collaborators is listed on our website&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are many institutes that may want to increase their capacity and attention for data science and research software. What did the Data Science Centre do to make this a success at UvA? What do you think others in their position could learn from their experience?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I believe that one of the biggest contributing factors behind the DSC’s success so far is our strong focus on community building and engagement. Our DSC community members are at the heart of everything we do, and we are always in regular interaction with our members, whether it be via our Slack channel, Friday meet-ups, DSC weekly bulletin, or DSC Twitter. This regular interaction also helps us ensure that the activities we plan reflect the needs and wants of the community — for instance, we ask members to vote on what topics they want to receive training on, and then we plan the workshop curriculum based on this feedback.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;409&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_egOD2JPhMwg2Yq6VhTtiGg-7f7b3975.C4Q2WFrC_qN0nA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Data Science Centre Away Day in Zaandam&lt;/p&gt;
&lt;p&gt;I also think that we have found a perfect home at the University Library. Firstly, the Library already provides a range of tailored and hands-on data science support to researchers and faculties, which means that the DSC can leverage the available expertise in the field of data management.&lt;/p&gt;
&lt;p&gt;Being a part of the University Library also means that we can access its facility services, wide network within UvA, and gain practical support with the communication and logistical coordination of our events and activities (such as Data Science Day). This affords our team greater capacity to drive all the different initiatives and activities that we want to organise for the community at UvA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are the plans for the future of the DSC?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since our launch in 2021, we have achieved great progress in building a strong data science community and presence at UvA.&lt;/p&gt;
&lt;p&gt;Looking ahead, we want to continue growing the DSC community and giving our members as many opportunities as possible to upskill and further develop their expertise.&lt;/p&gt;
&lt;p&gt;This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expanding our workshop and training support programme&lt;/li&gt;
&lt;li&gt;Continuing to embed data scientists and/or engineers across all research disciplines via the Accelerate programme (by 2025, we aim to have 35 dedicated data scientists and/or engineers across UvA faculties)&lt;/li&gt;
&lt;li&gt;Leverage our partnerships with local, national and international data-science organisations to further stimulate more interdisciplinary and interorganisational data science collaborations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also welcome new collaborations and partnerships! If you are interested in collaborating with us or learning more about what we do, then please contact us at &lt;a href=&quot;mailto:dsc@uva.nl&quot;&gt;dsc@uva.nl&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who is the Data Science Centre staffed by?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The DSC coordinating team consists of our Scientific Director Prof. Paul Groth, Max Haring (Head of Education and Research Support at the University Library), Boy Menist (Operational Director), Eva Lekkerkerker (Digital Skills Coordinator — maternity leave cover for Iris van der Knaap), the University Library Communications team, and a representative from the Social and Behavioural Data Science Centre which is a DSC hub. What I like most about my team is that we all come from varied backgrounds, and therefore can bring very diverse expertise to the table.&lt;/p&gt;</description><pubDate>Thu, 12 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This week, we interviewed &lt;a href=&quot;https://dsc.uva.nl/content/news/2022/06/interview-with-data-science-community-manager-lisa-yu.html&quot;&gt;Lisa Yu&lt;/a&gt;, Community Manager of the Data Science Center (DSC). The DSC is a coordinating hub within the University of Amsterdam (UvA) Library, launched in 2021. The need for software and skills that make researchers able to adequately deal with available data continues to grow across all research disciplines. Thanks to funding provided by the UvA Executive Board, the DSC is in a position to boost digitally driven research at UvA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: What are the DSC’s most important activities?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1078&quot; height=&quot;252&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_yEpWKc90PA3cJ3R-ZL1KjQ-4bc4c1fe.jieQD0mY_Z13fEXo.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo caption: Data Science Day 2022, photographed by Monique Kooijmans&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lisa:&lt;/em&gt; The DSC hosts a variety of important activities throughout the year. In the autumn of 2022, we held our &lt;a href=&quot;https://dsc.uva.nl/content/news/2022/11/data-science-day-2022.html&quot;&gt;second annual Data Science Day&lt;/a&gt; at Startup Village in Amsterdam Science Park. More than 100 attendees from within and outside of UvA participated in this action-packed event, which consisted of morning workshops, keynote presentations and pitch presentations on a variety of data science topics.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;364&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KDJrC4sOgTTPld2cbyvlkg-54fc37ba.Bp2jqxAM_ZosolL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Data Science Centre Hackathon 2022, photographed by Monique Kooijmans&lt;/p&gt;
&lt;p&gt;Our weekly &lt;a href=&quot;https://dsc.uva.nl/programmes/coffee-and-data/coffee-and-data.html&quot;&gt;Friday Coffee and Data meet-ups&lt;/a&gt; are also very important. These meet-ups are for our DSC members and consist of free workshops and training like the &lt;a href=&quot;https://software-carpentry.org/lessons/&quot;&gt;Software Carpentry&lt;/a&gt; and Image Analysis, seminar presentations by DSC members, and collaboration sessions. Beyond this being an upskilling opportunity, it is also a chance for members to meet like-minded people from other faculties and campuses and to collaborate with each other.&lt;/p&gt;
&lt;p&gt;We update our events page regularly online, so &lt;a href=&quot;https://dsc.uva.nl/&quot;&gt;check our website&lt;/a&gt; regularly for all our upcoming planned activities!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you have an example of how the DSC has helped researchers at UvA?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our ultimate goal is to accelerate software and data-driven research at UvA, and help researchers do research they wouldn’t have otherwise been able to do. One example of how the DSC has helped achieve this is through its &lt;a href=&quot;https://dsc.uva.nl/programmes/accelerate-programme/accelerate-programme.html&quot;&gt;Accelerate programme&lt;/a&gt;, where we co-finance the hiring of data scientists (who have roles comparable to research software engineers, ed.) and data engineers within faculties.&lt;/p&gt;
&lt;p&gt;Since its launch in 2021, the Accelerate programme has led to the successful hiring of the equivalent of 18 FTE data scientists and engineers across a range of UvA faculties. The Accelerate programme has helped fund lots of cool research, ranging from how to better understand the history of early globalization and colonisation, to why people follow and break rules, to growing tomatoes!&lt;/p&gt;
&lt;p&gt;Another example of how we have helped researchers at UvA is through our Interdisciplinary PhD programme, where we have provided funding for 7 PhD students to work on a selection of interdisciplinary research projects. &lt;a href=&quot;https://dsc.uva.nl/programmes/interdisciplinary-phd-programme/interdisciplinary-phd-programme.html&quot;&gt;More information about these projects and its collaborators is listed on our website&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are many institutes that may want to increase their capacity and attention for data science and research software. What did the Data Science Centre do to make this a success at UvA? What do you think others in their position could learn from their experience?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I believe that one of the biggest contributing factors behind the DSC’s success so far is our strong focus on community building and engagement. Our DSC community members are at the heart of everything we do, and we are always in regular interaction with our members, whether it be via our Slack channel, Friday meet-ups, DSC weekly bulletin, or DSC Twitter. This regular interaction also helps us ensure that the activities we plan reflect the needs and wants of the community — for instance, we ask members to vote on what topics they want to receive training on, and then we plan the workshop curriculum based on this feedback.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;409&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_egOD2JPhMwg2Yq6VhTtiGg-7f7b3975.C4Q2WFrC_qN0nA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Data Science Centre Away Day in Zaandam&lt;/p&gt;
&lt;p&gt;I also think that we have found a perfect home at the University Library. Firstly, the Library already provides a range of tailored and hands-on data science support to researchers and faculties, which means that the DSC can leverage the available expertise in the field of data management.&lt;/p&gt;
&lt;p&gt;Being a part of the University Library also means that we can access its facility services, wide network within UvA, and gain practical support with the communication and logistical coordination of our events and activities (such as Data Science Day). This affords our team greater capacity to drive all the different initiatives and activities that we want to organise for the community at UvA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are the plans for the future of the DSC?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since our launch in 2021, we have achieved great progress in building a strong data science community and presence at UvA.&lt;/p&gt;
&lt;p&gt;Looking ahead, we want to continue growing the DSC community and giving our members as many opportunities as possible to upskill and further develop their expertise.&lt;/p&gt;
&lt;p&gt;This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expanding our workshop and training support programme&lt;/li&gt;
&lt;li&gt;Continuing to embed data scientists and/or engineers across all research disciplines via the Accelerate programme (by 2025, we aim to have 35 dedicated data scientists and/or engineers across UvA faculties)&lt;/li&gt;
&lt;li&gt;Leverage our partnerships with local, national and international data-science organisations to further stimulate more interdisciplinary and interorganisational data science collaborations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also welcome new collaborations and partnerships! If you are interested in collaborating with us or learning more about what we do, then please contact us at &lt;a href=&quot;mailto:dsc@uva.nl&quot;&gt;dsc@uva.nl&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who is the Data Science Centre staffed by?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The DSC coordinating team consists of our Scientific Director Prof. Paul Groth, Max Haring (Head of Education and Research Support at the University Library), Boy Menist (Operational Director), Eva Lekkerkerker (Digital Skills Coordinator — maternity leave cover for Iris van der Knaap), the University Library Communications team, and a representative from the Social and Behavioural Data Science Centre which is a DSC hub. What I like most about my team is that we all come from varied backgrounds, and therefore can bring very diverse expertise to the table.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_yEpWKc90PA3cJ3R-ZL1KjQ-4bc4c1fe.jieQD0mY.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Ceci n’est pas une peinture — making art with AI</title><link>https://blog.esciencecenter.nl/posts/2022-12-19---ceci-nest-pas-une-peinture-making-art-with-ai</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-12-19---ceci-nest-pas-une-peinture-making-art-with-ai</guid><description>&lt;p&gt;Over time, the model ultimately learns how to discriminate between these two groups (Van Gogh vs. other) and outputs the probability that a new observation belongs to the Van Gogh’s category. To do so, however, discriminative modelling requires that each observation in training must have a label, i.e., all Van Gogh’s paintings are labelled as 1, and non-Van Gogh paintings as 0.&lt;/p&gt;
&lt;p&gt;Generative models instead don’t need a labelled dataset¹: they output sets of pixels, I.e. other images, and are trained to minimize the difference between the images they produce and the images they are trained on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Key points:&lt;/p&gt;
&lt;p&gt;In other words, the key difference between discriminative and generative modelling is that while the former attempts to estimate the probability that an observation &lt;em&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/em&gt; (pixel) belongs to the learned category &lt;em&gt;&lt;strong&gt;y&lt;/strong&gt;&lt;/em&gt;(Van Gogh), the latter instead attempts to estimate the probability of seeing the observation &lt;em&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/em&gt; (pixel) at all.&lt;/p&gt;
&lt;p&gt;Once trained, generative models can be used to produce completely novel images that share features with the training set. What the model learns is a highly sophisticated method for interpolating images: Not magic, but impressive, nonetheless.&lt;/p&gt;
&lt;h3 id=&quot;good-artists-copy-great-artists-steal&quot;&gt;Good artists copy, great artists steal&lt;/h3&gt;
&lt;p&gt;Since the AI is trained on images pulled from the internet, it learns from a store of pictures that people have chosen to share. As a consequence, the blind use of these models often reveals how deeply social bias is baked into our data sets. For example, OpenAI has found that &lt;a href=&quot;https://industrywired.com/for-the-nurse-prompt-dall-e-will-only-show-a-woman-exploring-ai-bias/&quot;&gt;prompting the word “Nurse” will always show a woman, while the word “CEO” always a man&lt;/a&gt;. Bias doesn’t seem to be limited to gender, but &lt;a href=&quot;https://analyticsindiamag.com/midjourney-is-biased/&quot;&gt;encompasses race as well&lt;/a&gt;&lt;a href=&quot;https://analyticsindiamag.com/midjourney-is-biased/&quot;&gt;.&lt;/a&gt;.) One solution to this is to provide a more socially and ethnically diverse training dataset that would comprehend different ethnicities and gender descriptions.&lt;/p&gt;
&lt;p&gt;More concerning on the long term, however, is the potential of these tools to create misinformation. In a &lt;a href=&quot;https://www.proquest.com/docview/2190341785?pq-origsite=gscholar&amp;#x26;fromopenview=true&quot;&gt;test&lt;/a&gt; run at Art Basel in 2016— an annual fair showcasing contemporary art — the authors of &lt;a href=&quot;https://www.aican.io/&quot;&gt;AICAN&lt;/a&gt; (Artificial Intelligence Creative Adversarial Network) showed that people were very often unable to tell the difference between AICAN generated images and artworks produced by a human artist (see also Tidio’s recent &lt;a href=&quot;https://www.tidio.com/blog/ai-test/&quot;&gt;test&lt;/a&gt; confirming this trend). This suggests that the share of “visual literacy” in the public is not very high and may pose a risk in a society that hasn’t integrated more sophisticated tools to tell apart humans- vs AI- generated images in our daily life.&lt;/p&gt;
&lt;p&gt;Aside from these ethical concerns, there is also the question of plagiarism. The training dataset is obtained by web scraping millions of images that are necessarily made by someone else. This suggests a form of plagiarism which affects artists who upload their works to the internet (perhaps for self-promotion) and that may be unaware of helping an AI to become their competitors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Ceci n’est pas une peinture — making art with AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;703&quot; src=&quot;https://blog.esciencecenter.nl/_astro/ceci-nest-pas-une-peinture-making-art-wi-91e9b380.CypOwWjt_1iUceM.webp&quot; srcset=&quot;&quot;&gt;
The Portrait of Edmond Belamy &lt;a href=&quot;https://www.christies.com/features/A-collaboration-between-two-artists-one-human-one-a-machine-9332-1.aspx?sc_lang=en&quot;&gt;&lt;strong&gt;sold at auction for $432,000&lt;/strong&gt;&lt;/a&gt;on 25 October 2018 at Christie’s in New York. The artwork was produced using a generative model and a data set of 15,000 portraits painted between the 14th and 20th Centuries. Image © Obvious&lt;/p&gt;
&lt;h3 id=&quot;is-it-society-doomed&quot;&gt;Is it society doomed?&lt;/h3&gt;
&lt;p&gt;Allen’s “Theatre d’Opera Spatial” was a test of how the world would view AI-generated art: The award got mixed responses. Some people accused him of cheating because he didn’t make the work, others (like Allen himself) took pride in seeing an AI-generated piece beat the competition.&lt;/p&gt;
&lt;p&gt;When a new technology gains traction, it always fuels the public debate. In the case of generative models, the enthusiasts foresee the liberation of human creativity from the burden of technical expertise, the worried fear the end of traditional image production as an art form.&lt;/p&gt;
&lt;p&gt;Many people compare these reactions to those that followed the invention of photography in 1822, which many artists at that time saw as an insult to human creativity and artistry. It ended up creating a revolution, not a murder, of the visual arts. Most people now acknowledge that ultimately the human, not the device, is responsible for the image.&lt;/p&gt;
&lt;p&gt;Ultimately, making generative art the new photography is up to us. It will depend on how we choose to answer important questions like: Who does the technology belong to? Who can use it? What is the allowed use, and do deep learning models expand or compress our freedom?&lt;/p&gt;
&lt;p&gt;It is us, not the technology, who choose the direction.&lt;/p&gt;
&lt;p&gt;1: though it can also be applied to a labelled dataset in case we wish to generate observations from each distinct class&lt;/p&gt;</description><pubDate>Mon, 19 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over time, the model ultimately learns how to discriminate between these two groups (Van Gogh vs. other) and outputs the probability that a new observation belongs to the Van Gogh’s category. To do so, however, discriminative modelling requires that each observation in training must have a label, i.e., all Van Gogh’s paintings are labelled as 1, and non-Van Gogh paintings as 0.&lt;/p&gt;
&lt;p&gt;Generative models instead don’t need a labelled dataset¹: they output sets of pixels, I.e. other images, and are trained to minimize the difference between the images they produce and the images they are trained on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Key points:&lt;/p&gt;
&lt;p&gt;In other words, the key difference between discriminative and generative modelling is that while the former attempts to estimate the probability that an observation &lt;em&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/em&gt; (pixel) belongs to the learned category &lt;em&gt;&lt;strong&gt;y&lt;/strong&gt;&lt;/em&gt;(Van Gogh), the latter instead attempts to estimate the probability of seeing the observation &lt;em&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/em&gt; (pixel) at all.&lt;/p&gt;
&lt;p&gt;Once trained, generative models can be used to produce completely novel images that share features with the training set. What the model learns is a highly sophisticated method for interpolating images: Not magic, but impressive, nonetheless.&lt;/p&gt;
&lt;h3 id=&quot;good-artists-copy-great-artists-steal&quot;&gt;Good artists copy, great artists steal&lt;/h3&gt;
&lt;p&gt;Since the AI is trained on images pulled from the internet, it learns from a store of pictures that people have chosen to share. As a consequence, the blind use of these models often reveals how deeply social bias is baked into our data sets. For example, OpenAI has found that &lt;a href=&quot;https://industrywired.com/for-the-nurse-prompt-dall-e-will-only-show-a-woman-exploring-ai-bias/&quot;&gt;prompting the word “Nurse” will always show a woman, while the word “CEO” always a man&lt;/a&gt;. Bias doesn’t seem to be limited to gender, but &lt;a href=&quot;https://analyticsindiamag.com/midjourney-is-biased/&quot;&gt;encompasses race as well&lt;/a&gt;&lt;a href=&quot;https://analyticsindiamag.com/midjourney-is-biased/&quot;&gt;.&lt;/a&gt;.) One solution to this is to provide a more socially and ethnically diverse training dataset that would comprehend different ethnicities and gender descriptions.&lt;/p&gt;
&lt;p&gt;More concerning on the long term, however, is the potential of these tools to create misinformation. In a &lt;a href=&quot;https://www.proquest.com/docview/2190341785?pq-origsite=gscholar&amp;#x26;fromopenview=true&quot;&gt;test&lt;/a&gt; run at Art Basel in 2016— an annual fair showcasing contemporary art — the authors of &lt;a href=&quot;https://www.aican.io/&quot;&gt;AICAN&lt;/a&gt; (Artificial Intelligence Creative Adversarial Network) showed that people were very often unable to tell the difference between AICAN generated images and artworks produced by a human artist (see also Tidio’s recent &lt;a href=&quot;https://www.tidio.com/blog/ai-test/&quot;&gt;test&lt;/a&gt; confirming this trend). This suggests that the share of “visual literacy” in the public is not very high and may pose a risk in a society that hasn’t integrated more sophisticated tools to tell apart humans- vs AI- generated images in our daily life.&lt;/p&gt;
&lt;p&gt;Aside from these ethical concerns, there is also the question of plagiarism. The training dataset is obtained by web scraping millions of images that are necessarily made by someone else. This suggests a form of plagiarism which affects artists who upload their works to the internet (perhaps for self-promotion) and that may be unaware of helping an AI to become their competitors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Ceci n’est pas une peinture — making art with AI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;703&quot; src=&quot;https://blog.esciencecenter.nl/_astro/ceci-nest-pas-une-peinture-making-art-wi-91e9b380.CypOwWjt_1iUceM.webp&quot; srcset=&quot;&quot;&gt;
The Portrait of Edmond Belamy &lt;a href=&quot;https://www.christies.com/features/A-collaboration-between-two-artists-one-human-one-a-machine-9332-1.aspx?sc_lang=en&quot;&gt;&lt;strong&gt;sold at auction for $432,000&lt;/strong&gt;&lt;/a&gt;on 25 October 2018 at Christie’s in New York. The artwork was produced using a generative model and a data set of 15,000 portraits painted between the 14th and 20th Centuries. Image © Obvious&lt;/p&gt;
&lt;h3 id=&quot;is-it-society-doomed&quot;&gt;Is it society doomed?&lt;/h3&gt;
&lt;p&gt;Allen’s “Theatre d’Opera Spatial” was a test of how the world would view AI-generated art: The award got mixed responses. Some people accused him of cheating because he didn’t make the work, others (like Allen himself) took pride in seeing an AI-generated piece beat the competition.&lt;/p&gt;
&lt;p&gt;When a new technology gains traction, it always fuels the public debate. In the case of generative models, the enthusiasts foresee the liberation of human creativity from the burden of technical expertise, the worried fear the end of traditional image production as an art form.&lt;/p&gt;
&lt;p&gt;Many people compare these reactions to those that followed the invention of photography in 1822, which many artists at that time saw as an insult to human creativity and artistry. It ended up creating a revolution, not a murder, of the visual arts. Most people now acknowledge that ultimately the human, not the device, is responsible for the image.&lt;/p&gt;
&lt;p&gt;Ultimately, making generative art the new photography is up to us. It will depend on how we choose to answer important questions like: Who does the technology belong to? Who can use it? What is the allowed use, and do deep learning models expand or compress our freedom?&lt;/p&gt;
&lt;p&gt;It is us, not the technology, who choose the direction.&lt;/p&gt;
&lt;p&gt;1: though it can also be applied to a labelled dataset in case we wish to generate observations from each distinct class&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/ceci-nest-pas-une-peinture-making-art-wi-91e9b380.CypOwWjt.png" medium="image"/><author>Eva Viviani</author></item><item><title>Machine Learning as a tool for political speech analysis</title><link>https://blog.esciencecenter.nl/posts/2022-12-16---machine-learning-as-a-tool-for-political-speech-analysis</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-12-16---machine-learning-as-a-tool-for-political-speech-analysis</guid><description>&lt;p&gt;The following example of a sentence from Putin’s invasion-speech may clarify what CM annotation of texts involves: ‘The purpose of this operation is to protect people** &lt;strong&gt;[Effect]&lt;/strong&gt; who, for eight years now, have been facing humiliation and genocide perpetrated by the Kiev regime. To this end, we will seek to [Causal Link]* &lt;strong&gt;demilitarise (Cause A)&lt;/strong&gt; and &lt;strong&gt;de-nazify (Cause B)&lt;/strong&gt; Ukraine, as well as &lt;strong&gt;bring to trial those who perpetrated numerous bloody crimes against civilians [Cause C]&lt;/strong&gt;’. This example also provides a first indication of the complexity of our research goal, as it shows that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each of the three parts the causal relation may correspond to a multi-word phrase in a text;&lt;/li&gt;
&lt;li&gt;The three parts may appear in different orders in the text;&lt;/li&gt;
&lt;li&gt;A causal relation may cross sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using existing CM data from a previous project on the &lt;a href=&quot;https://www.transcrisis.eu/wp-content/uploads/2018/03/Deliverable-3.3-Meaning-Making-of-the-Euro-Crisis.pdf&quot;&gt;meaning making of political and financial leaders concerning the Eurozone crisis&lt;/a&gt;, we set two initial aims for our project: To identify sections of text that contain causal relations and to identify the causal triplets of &lt;em&gt;cause&lt;/em&gt;, &lt;em&gt;causal link&lt;/em&gt; and &lt;em&gt;effect&lt;/em&gt;. For both tasks we used several easy to implement, state-of-the-art machine-learning methods.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning as a tool for political speech analysis&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;409&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-as-a-tool-for-political-2655339b.COYs2_-X_Z1DodV5.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Figure 1: Excerpt of the cognitive map concerning the Eurozone crisis of Dutch Central Bank Governor Klaas Knot&lt;/em&gt;We focused on deriving causal (rather than normative) relations from text, because the method is much more complex than existing automated text-analysis techniques. The causal relations that make up the core of the CM technique consist of three parts: The cause-concept, the effect-concept and the phrase or word (often a verb or conjunction) indicating that they are related and in what way (positively or negatively). The outcomes of our project confirmed our expectation that automating CM is a difficult machine learning task: the predictions from the mchine learning models do not come close to the labels given by the human coders.&lt;/p&gt;
&lt;p&gt;Still, there are plenty of reasons to be optimistic about our results: Both the models we developed for the causal relation presence detection and the causal relation tagging tasks could be quite useful despite producing false positives. Evaluation of the outcomes showed that it is quite easy for a hand-coder to recognize and dismiss them. The models may thus be used in a so-called ‘human-in-the-loop’ pipeline in which the ‘machine’ identifies causal sections or relations in the text that are subsequently checked and corrected by a human coder. These corrections could then be fed back into the model to improve its learning.&lt;/p&gt;
&lt;p&gt;We also found that especially the semantic role labelling method in combination with manually written rules seems promising in the causal relation tagging task. We also used relatively strict evaluation criteria for this project. Compared to other widely used automated methods in the field of political science, for example, our results are actually comparable. We are currently further exploring the potential of a rule-based model.&lt;/p&gt;
&lt;p&gt;Although we did not fully solve our research problem in this project, participating in the &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;Small-Scale Initiative in Machine-Learning&lt;/a&gt; yielded promising results which culminated into a new research question guiding the next stage of our project. Our research team had only a basic understanding of machine learning before the start of this project, and the support offered by the engineers of the eScience Center has been invaluable to reaching the next stage of our project This allows us state with confidence: To be continued…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog is part of our blog series: &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;&lt;em&gt;The Small-Scale Initiative on Machine Learning, how did it go?&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read a full report of the project &lt;a href=&quot;https://www.researchgate.net/publication/363295614_Towards_Automated_Cognitive_Mapping_of_Political_Speeches_using_Machine_Learning&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;</description><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The following example of a sentence from Putin’s invasion-speech may clarify what CM annotation of texts involves: ‘The purpose of this operation is to protect people** &lt;strong&gt;[Effect]&lt;/strong&gt; who, for eight years now, have been facing humiliation and genocide perpetrated by the Kiev regime. To this end, we will seek to [Causal Link]* &lt;strong&gt;demilitarise (Cause A)&lt;/strong&gt; and &lt;strong&gt;de-nazify (Cause B)&lt;/strong&gt; Ukraine, as well as &lt;strong&gt;bring to trial those who perpetrated numerous bloody crimes against civilians [Cause C]&lt;/strong&gt;’. This example also provides a first indication of the complexity of our research goal, as it shows that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each of the three parts the causal relation may correspond to a multi-word phrase in a text;&lt;/li&gt;
&lt;li&gt;The three parts may appear in different orders in the text;&lt;/li&gt;
&lt;li&gt;A causal relation may cross sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using existing CM data from a previous project on the &lt;a href=&quot;https://www.transcrisis.eu/wp-content/uploads/2018/03/Deliverable-3.3-Meaning-Making-of-the-Euro-Crisis.pdf&quot;&gt;meaning making of political and financial leaders concerning the Eurozone crisis&lt;/a&gt;, we set two initial aims for our project: To identify sections of text that contain causal relations and to identify the causal triplets of &lt;em&gt;cause&lt;/em&gt;, &lt;em&gt;causal link&lt;/em&gt; and &lt;em&gt;effect&lt;/em&gt;. For both tasks we used several easy to implement, state-of-the-art machine-learning methods.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Machine Learning as a tool for political speech analysis&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;409&quot; src=&quot;https://blog.esciencecenter.nl/_astro/machine-learning-as-a-tool-for-political-2655339b.COYs2_-X_Z1DodV5.webp&quot; srcset=&quot;&quot;&gt;
&lt;em&gt;Figure 1: Excerpt of the cognitive map concerning the Eurozone crisis of Dutch Central Bank Governor Klaas Knot&lt;/em&gt;We focused on deriving causal (rather than normative) relations from text, because the method is much more complex than existing automated text-analysis techniques. The causal relations that make up the core of the CM technique consist of three parts: The cause-concept, the effect-concept and the phrase or word (often a verb or conjunction) indicating that they are related and in what way (positively or negatively). The outcomes of our project confirmed our expectation that automating CM is a difficult machine learning task: the predictions from the mchine learning models do not come close to the labels given by the human coders.&lt;/p&gt;
&lt;p&gt;Still, there are plenty of reasons to be optimistic about our results: Both the models we developed for the causal relation presence detection and the causal relation tagging tasks could be quite useful despite producing false positives. Evaluation of the outcomes showed that it is quite easy for a hand-coder to recognize and dismiss them. The models may thus be used in a so-called ‘human-in-the-loop’ pipeline in which the ‘machine’ identifies causal sections or relations in the text that are subsequently checked and corrected by a human coder. These corrections could then be fed back into the model to improve its learning.&lt;/p&gt;
&lt;p&gt;We also found that especially the semantic role labelling method in combination with manually written rules seems promising in the causal relation tagging task. We also used relatively strict evaluation criteria for this project. Compared to other widely used automated methods in the field of political science, for example, our results are actually comparable. We are currently further exploring the potential of a rule-based model.&lt;/p&gt;
&lt;p&gt;Although we did not fully solve our research problem in this project, participating in the &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;Small-Scale Initiative in Machine-Learning&lt;/a&gt; yielded promising results which culminated into a new research question guiding the next stage of our project. Our research team had only a basic understanding of machine learning before the start of this project, and the support offered by the engineers of the eScience Center has been invaluable to reaching the next stage of our project This allows us state with confidence: To be continued…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog is part of our blog series: &lt;em&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;&lt;em&gt;The Small-Scale Initiative on Machine Learning, how did it go?&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read a full report of the project &lt;a href=&quot;https://www.researchgate.net/publication/363295614_Towards_Automated_Cognitive_Mapping_of_Political_Speeches_using_Machine_Learning&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/machine-learning-as-a-tool-for-political-2655339b.COYs2_-X.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Small-scale initiative in Machine Learning 2021: how did it go?</title><link>https://blog.esciencecenter.nl/posts/2022-12-16---small-scale-initiative-in-machine-learning-2021-how-did-it-g</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-12-16---small-scale-initiative-in-machine-learning-2021-how-did-it-g</guid><description>&lt;p&gt;&lt;img alt=&quot;Small-scale initiative in Machine Learning 2021: how did it go?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/small-scale-initiative-in-machine-learni-467f4e1a.xcJ2Rpyx_ZDpB3N.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@bamagal?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;“My Life Through A Lens”&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;small-scale-initiative-in-machine-learning-2021-how-did-it-go&quot;&gt;Small-scale initiative in Machine Learning 2021: how did it go?&lt;/h1&gt;
&lt;h2 id=&quot;introducing-a-series-of-blog-posts-on-our-collaborative-projects-in-machine-learning&quot;&gt;Introducing a series of blog posts on our collaborative projects in machine learning&lt;/h2&gt;
&lt;p&gt;Here we go:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/how-to-find-your-rubber-duck-using-machine-learning-to-understand-changes-in-the-wadden-sea-7c10da354e24&quot;&gt;How to find your rubber duck: Using machine learning to understand a changing sea&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/parsing-hebrew-and-syriac-morphology-using-deep-learning-cb6832bb6685&quot;&gt;Parsing Hebrew and Syriac morphology using Deep Learning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-machine-learning-approach-to-laughter-fdbcee3fb000&quot;&gt;A machine learning approach to laughter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/how-machine-learning-could-help-simone-to-play-ludo-fab95721580a&quot;&gt;How machine learning could help Simone to play Ludo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/can-machine-learning-help-us-improve-stroke-rehabilitation-a-step-towards-personalized-therapy-386efb3caf05&quot;&gt;Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-letter-to-my-parents-about-my-experience-in-a-machine-learning-consultancy-project-aa5520d63329&quot;&gt;Intermezzo: from the perspective of an eScience Engineer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-from-cell-tower-data-6ab856c99f8b&quot;&gt;Using machine learning to tell apart rain, snow, hail and fog from cell tower data&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/the-mystery-of-glass-why-machine-learning-can-help-us-c1b9690565a3&quot;&gt;The mystery of glass: why machine learning can help us&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/studying-political-symbolism-in-turkish-tv-dramas-with-machine-learning-3938ef40a376&quot;&gt;Studying political symbolism in Turkish TV dramas with machine learning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/machine-learning-as-a-tool-for-political-speech-analysis-c8abf5cd8c0d&quot;&gt;Machine learning as a tool for political speech analysis&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;Small-scale initiative in Machine Learning 2021: how did it go?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/small-scale-initiative-in-machine-learni-467f4e1a.xcJ2Rpyx_ZDpB3N.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@bamagal?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;“My Life Through A Lens”&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;small-scale-initiative-in-machine-learning-2021-how-did-it-go&quot;&gt;Small-scale initiative in Machine Learning 2021: how did it go?&lt;/h1&gt;
&lt;h2 id=&quot;introducing-a-series-of-blog-posts-on-our-collaborative-projects-in-machine-learning&quot;&gt;Introducing a series of blog posts on our collaborative projects in machine learning&lt;/h2&gt;
&lt;p&gt;Here we go:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/how-to-find-your-rubber-duck-using-machine-learning-to-understand-changes-in-the-wadden-sea-7c10da354e24&quot;&gt;How to find your rubber duck: Using machine learning to understand a changing sea&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/parsing-hebrew-and-syriac-morphology-using-deep-learning-cb6832bb6685&quot;&gt;Parsing Hebrew and Syriac morphology using Deep Learning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-machine-learning-approach-to-laughter-fdbcee3fb000&quot;&gt;A machine learning approach to laughter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/how-machine-learning-could-help-simone-to-play-ludo-fab95721580a&quot;&gt;How machine learning could help Simone to play Ludo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/can-machine-learning-help-us-improve-stroke-rehabilitation-a-step-towards-personalized-therapy-386efb3caf05&quot;&gt;Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/a-letter-to-my-parents-about-my-experience-in-a-machine-learning-consultancy-project-aa5520d63329&quot;&gt;Intermezzo: from the perspective of an eScience Engineer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-from-cell-tower-data-6ab856c99f8b&quot;&gt;Using machine learning to tell apart rain, snow, hail and fog from cell tower data&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/the-mystery-of-glass-why-machine-learning-can-help-us-c1b9690565a3&quot;&gt;The mystery of glass: why machine learning can help us&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/studying-political-symbolism-in-turkish-tv-dramas-with-machine-learning-3938ef40a376&quot;&gt;Studying political symbolism in Turkish TV dramas with machine learning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/machine-learning-as-a-tool-for-political-speech-analysis-c8abf5cd8c0d&quot;&gt;Machine learning as a tool for political speech analysis&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/small-scale-initiative-in-machine-learni-467f4e1a.xcJ2Rpyx.jpg" medium="image"/><author>Sonja Georgievska</author></item><item><title>Immaculate Speech and Hallucinations</title><link>https://blog.esciencecenter.nl/posts/2022-12-13---immaculate-speech-and-hallucinations</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-12-13---immaculate-speech-and-hallucinations</guid><description>&lt;h2 id=&quot;when-not-to-use-openais-whisper-to-transcribe-audio-in-a-social-sciences-project&quot;&gt;When (not) to use OpenAI’s Whisper to transcribe audio in a social sciences project&lt;/h2&gt;
&lt;p&gt;Using Whisper off-the-shelf in this case might bias the results because it tends to “polish” the structure and coherence of the speech in the transcription. It is also known to sometimes insert* common words when nothing was said, which is called “hallucination”. Thus, Whisper could artificially create, alter, or even remove the effect to be investigated.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Immaculate Speech and Hallucinations&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/immaculate-speech-and-hallucinations-c3c9df4f.eqCsNFdh_Um5NS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@miguel_photo?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Miguel Henriques&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;other-scenarios-where-whisper-can-be-useful&quot;&gt;Other Scenarios Where Whisper Can Be Useful&lt;/h3&gt;
&lt;p&gt;In addition to the previous examples, I also want to mention two other good use cases for Whisper. The transcripts can be fed into a second machine learning model which, for example, predicts the sentiment of each sentence. The sentence structure returned by Whisper is necessary, and many recent language models that perform sentiment prediction benefit from clean and structured input text. However, one should keep in mind that errors in the transcriptions made by Whisper will likely lead to errors in the sentiment prediction too.&lt;/p&gt;
&lt;p&gt;Another use case is the transcription of audio recordings in languages that are not known a priori, for example, when using data from YouTube. Whisper can automatically detect the language and transcribe the recordings. Moreover, it can also translate the transcripts to English. This combination can make the analysis of multilingual datasets a lot easier. However, Whisper transcribes some languages better than others, which researchers should consider to avoid bias.&lt;/p&gt;
&lt;h3 id=&quot;concluding-remarks&quot;&gt;Concluding Remarks&lt;/h3&gt;
&lt;p&gt;In this post, I gave some examples how Whisper can be applied in social science research. Whisper shines when structured and coherent transcripts are important. In contrast, when the transcribed text should mimic the original speech closely, the model might be less useful. With Whisper many tasks can be solved using a single tool, whereas traditional approaches require many processing steps by different methods. Finally, I want to highlight that, in any case, the transcripts should at least be partially checked for unexpected results by someone who is familiar with the recordings and the research domain. Discussing the approach and results with a machine learning expert will also not hurt. To those, who found inspiration in this post, happy whispering!&lt;/p&gt;
&lt;p&gt;Reference: Radford, A., Kim, J. W., Xu, T., Brockman, G., McLeavey, C., Sutskever, I. (2022). Robust speech recognition via large-scale weak supervision. &lt;a href=&quot;https://cdn.openai.com/papers/whisper.pdf&quot;&gt;https://cdn.openai.com/papers/whisper.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[1]: In the field of machine learning, audio transcription falls under the task Automatic Speech Recognition (ASR).&lt;/p&gt;
&lt;p&gt;[2]: This figure gives a quick overview of Whispers transcription performance: &lt;a href=&quot;https://github.com/openai/whisper/blob/main/language-breakdown.svg&quot;&gt;https://github.com/openai/whisper/blob/main/language-breakdown.svg&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 13 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;when-not-to-use-openais-whisper-to-transcribe-audio-in-a-social-sciences-project&quot;&gt;When (not) to use OpenAI’s Whisper to transcribe audio in a social sciences project&lt;/h2&gt;
&lt;p&gt;Using Whisper off-the-shelf in this case might bias the results because it tends to “polish” the structure and coherence of the speech in the transcription. It is also known to sometimes insert* common words when nothing was said, which is called “hallucination”. Thus, Whisper could artificially create, alter, or even remove the effect to be investigated.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Immaculate Speech and Hallucinations&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/immaculate-speech-and-hallucinations-c3c9df4f.eqCsNFdh_Um5NS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@miguel_photo?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Miguel Henriques&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;other-scenarios-where-whisper-can-be-useful&quot;&gt;Other Scenarios Where Whisper Can Be Useful&lt;/h3&gt;
&lt;p&gt;In addition to the previous examples, I also want to mention two other good use cases for Whisper. The transcripts can be fed into a second machine learning model which, for example, predicts the sentiment of each sentence. The sentence structure returned by Whisper is necessary, and many recent language models that perform sentiment prediction benefit from clean and structured input text. However, one should keep in mind that errors in the transcriptions made by Whisper will likely lead to errors in the sentiment prediction too.&lt;/p&gt;
&lt;p&gt;Another use case is the transcription of audio recordings in languages that are not known a priori, for example, when using data from YouTube. Whisper can automatically detect the language and transcribe the recordings. Moreover, it can also translate the transcripts to English. This combination can make the analysis of multilingual datasets a lot easier. However, Whisper transcribes some languages better than others, which researchers should consider to avoid bias.&lt;/p&gt;
&lt;h3 id=&quot;concluding-remarks&quot;&gt;Concluding Remarks&lt;/h3&gt;
&lt;p&gt;In this post, I gave some examples how Whisper can be applied in social science research. Whisper shines when structured and coherent transcripts are important. In contrast, when the transcribed text should mimic the original speech closely, the model might be less useful. With Whisper many tasks can be solved using a single tool, whereas traditional approaches require many processing steps by different methods. Finally, I want to highlight that, in any case, the transcripts should at least be partially checked for unexpected results by someone who is familiar with the recordings and the research domain. Discussing the approach and results with a machine learning expert will also not hurt. To those, who found inspiration in this post, happy whispering!&lt;/p&gt;
&lt;p&gt;Reference: Radford, A., Kim, J. W., Xu, T., Brockman, G., McLeavey, C., Sutskever, I. (2022). Robust speech recognition via large-scale weak supervision. &lt;a href=&quot;https://cdn.openai.com/papers/whisper.pdf&quot;&gt;https://cdn.openai.com/papers/whisper.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[1]: In the field of machine learning, audio transcription falls under the task Automatic Speech Recognition (ASR).&lt;/p&gt;
&lt;p&gt;[2]: This figure gives a quick overview of Whispers transcription performance: &lt;a href=&quot;https://github.com/openai/whisper/blob/main/language-breakdown.svg&quot;&gt;https://github.com/openai/whisper/blob/main/language-breakdown.svg&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/immaculate-speech-and-hallucinations-c3c9df4f.eqCsNFdh.jpg" medium="image"/><author>Malte Lüken</author></item><item><title>Interview with chatGPT</title><link>https://blog.esciencecenter.nl/posts/2022-12-08---interview-with-chatgpt</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-12-08---interview-with-chatgpt</guid><description>&lt;h2 id=&quot;good-morning-chatgpt-i-will-be-interviewing-you-for-a-blog-post-of-the-netherlands-escience-center-a-research-institution-that-builds-and-applies-software-to-enhance-the-use-of-computing-and-digital-technologies-in-academic-research-so-the-audience-of-the-blog-is-scientists-in-any-domain-software-engineers-and-people-just-interested-in-either-of-the-two-can-you-start-off-by-introducing-yourself&quot;&gt;Good morning chatGPT, I will be interviewing you for a blog post of the Netherlands eScience Center, a research institution that builds and applies software to enhance the use of computing and digital technologies in academic research. So the audience of the blog is scientists in any domain, software engineers, and people just interested in either of the two. Can you start off by introducing yourself?&lt;/h2&gt;
&lt;p&gt;Hello! I am Assistant, a large language model trained by OpenAI. I am designed to assist with a variety of tasks, including answering questions and providing explanations and information on a wide range of topics. I am not a real person, but a computer program that uses artificial intelligence to process and generate natural language text. I am not affiliated with the Netherlands eScience Center, but I am happy to provide information on my capabilities and how I can be used in research.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you, have you heard of us before by any chance? Do you know anything about us?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am not able to browse the internet or access any external information, so I am not aware of the Netherlands eScience Center or its work. As a large language model, I am trained on a vast amount of text data, but I do not have access to real-time information or specific knowledge about organizations or events. My primary function is to assist with language-related tasks, such as answering questions and providing explanations and information based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok, so how can you be used in research? Slightly more specifically, let’s talk about academic research with a digital component.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a large language model, I am not specifically designed or intended for use in academic research, but I can assist with a variety of language-related tasks that may be relevant to researchers. For example, I can help with data analysis and interpretation by providing explanations and summaries of complex information, such as research papers or datasets. I can also assist with the writing and organization of research papers by generating text and providing suggestions for structure and content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But how will you get access to a research paper?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I mentioned earlier, I do not have the ability to access external information or specific knowledge about organizations or events. In order to assist with a task, I would need to be provided with the relevant information, such as a research paper or dataset. I can then process and analyze the information using my natural language processing capabilities and provide explanations and summaries based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I upload a paper to you or do I have to copy all of its contents?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a computer program, I do not have the ability to access or receive external information, such as research papers or other documents. In order to assist with a specific task, such as summarizing a research paper, you would need to provide the relevant information to me in the form of text input. This could involve copying and pasting the text of the paper, or providing a summary or outline of its contents. I would then use my natural language processing capabilities to generate a response based on the information provided.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok let’s start with something shorter than a paper, this is the eScience Center’s mission and vision:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bringing together knowledge, people and institutions, the eScience Center builds and applies software to enhance the use of computing and digital technologies in academic research. Our vision is a thriving research community where researchers in all disciplines can make use of advanced software, computing and digital technologies, keeping the Netherlands at the forefront of research. Our mission is to empower researchers through innovative software. To carry it out, we work in two ways: by collaboratively designing sustainable software, and building digital skills and expertise. Ultimately our relationship to the academic world is one of mutual benefit; we share the digital skills and knowledge needed to develop and apply research software, and gain insight into the needs of research communities in doing so.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And one of our slogans is:&lt;br&gt;
Academic research, powered by pioneering software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;and:&lt;br&gt;
We’re making sense of digital for science and scholarship&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Given what I’ve told you about us, can you come up with some more slogans?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few potential slogans for the Netherlands eScience Center:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Accelerating research with cutting-edge software”&lt;/li&gt;
&lt;li&gt;“Empowering researchers with digital tools”&lt;/li&gt;
&lt;li&gt;“Innovating for science and scholarship”&lt;/li&gt;
&lt;li&gt;“Transforming research with software and technology”&lt;/li&gt;
&lt;li&gt;“Unleashing the power of computing for academic discovery”&lt;/li&gt;
&lt;li&gt;“Bridging the gap between research and technology”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These slogans are based on the information you provided about the eScience Center’s mission and vision, as well as its focus on building and applying software to enhance research. They highlight the center’s role in empowering researchers and enabling them to make use of advanced technologies to drive innovation and discovery.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Awesome, but from most of those it’s not that clear that the people working here are not only software engineers but also researchers themselves, can you write a few more that make that clear?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few potential slogans that highlight the fact that the people working at the Netherlands eScience Center are both researchers and software engineers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Advancing research through collaboration and innovation”&lt;/li&gt;
&lt;li&gt;“Unlocking the potential of digital technology for science”&lt;/li&gt;
&lt;li&gt;“Building a bridge between research and software engineering”&lt;/li&gt;
&lt;li&gt;“Transforming academia with the power of software”&lt;/li&gt;
&lt;li&gt;“Enabling researchers to harness the power of computing”&lt;/li&gt;
&lt;li&gt;“Pioneering the future of research with digital tools”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These slogans focus on the intersection of research and software engineering at the eScience Center, and highlight the importance of collaboration and innovation in advancing academic research. They emphasize the center’s role in helping researchers to make use of digital technologies and software to drive discovery and unlock new insights.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could you do a few haikus on that?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few haikus that could potentially be used to describe the work of the Netherlands eScience Center:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software and research&lt;br&gt;
Together, we innovate&lt;br&gt;
Discovering new worlds&lt;/li&gt;
&lt;li&gt;Researchers and code&lt;br&gt;
Collaborating, we advance&lt;br&gt;
The frontiers of science&lt;/li&gt;
&lt;li&gt;Digital tools and minds&lt;br&gt;
Unleashing the power of both&lt;br&gt;
To drive discovery&lt;/li&gt;
&lt;li&gt;Computing and knowledge&lt;br&gt;
Pioneering new frontiers&lt;br&gt;
In academia and beyond&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These haikus are inspired by the information you provided about the eScience Center’s focus on bringing together software engineering and research to advance academic discovery. They highlight the importance of collaboration and innovation in driving progress, and the role of digital technologies in empowering researchers to unlock new insights and push the boundaries of knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;791&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-kkZG6qFn9CuxovbPKA7og-47688cad.CtWP2oTu_25FUf1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another creative use of chatGPT by Guy Parsons. The top left shows the chatGPT interface with a single line prompt above on ideas for decorating a living room, and below the reply with 3 suggestions. Each suggestion is then given to another model called Midjourney that turns them into images.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok let’s get a bit more technical. I’ve read&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/goodside/status/1598129631609380864?s=20&amp;#x26;t=RGtjDA4LjTl1YoWMZT4hyQ&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;where you explain bubble sort and its time complexity in the style of a “fast-talkin’ wise guy from a 1940’s gangster movie”. Bubble sort is quite slow as you explained there, what is a faster sorting algorithm? And can you explain that, along with an example in Python, but in the style of Yoda?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A faster sorting algorithm than bubble sort is quicksort, which has an average time complexity of O(n log n) and is often the algorithm of choice for sorting large datasets.&lt;/p&gt;
&lt;p&gt;To explain quicksort in the style of Yoda, we might say something like:&lt;/p&gt;
&lt;p&gt;“Faster, quicksort is. In arrays of data, quickly it sorts. Divide and conquer, its strategy. A pivot it chooses, and to the left, all lesser values go. To the right, all greater values. And so on, until the array is fully sorted.”&lt;/p&gt;
&lt;p&gt;Here is an example of quicksort implemented in Python:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def quicksort(arr)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; len(arr) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return arr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pivot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr[len(arr) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  left &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  middle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  right &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  return quicksort(left) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; middle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; quicksort(right)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation of quicksort uses the middle element of the array as the pivot, and recursively sorts the left and right halves of the array until it is fully sorted. This results in a much faster sorting process than bubble sort, especially for large datasets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That’s great, now just for good measure could you do the same for the other well known equally fast sorting algorithm, in a programming language other than Python, just pick one of your choice. And can you explain how it works and its time and space complexity in Dutch for our Dutch readers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another well-known sorting algorithm that is equally fast as quicksort is merge sort, which also has an average time complexity of O(n log n). Here is an example of merge sort implemented in Java:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;public void mergeSort(int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  if (array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int mid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;copyOfRange(array, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, mid);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;copyOfRange(array, mid, array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mergeSort(left);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mergeSort(right);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  merge(array, left, right);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;public void merge(int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array, int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left, int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    if (left[i] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      j&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    j&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation of merge sort first divides the input array in half and recursively sorts the left and right halves. It then merges the two sorted halves together to produce a fully sorted array.&lt;/p&gt;
&lt;p&gt;In terms of time and space complexity, merge sort has an average time complexity of O(n log n) and a worst-case time complexity of O(n log n). It also has a space complexity of O(n), since it requires additional space to store the left and right halves of the array while they are being sorted.&lt;/p&gt;
&lt;p&gt;In Dutch, we might explain the working of merge sort and its time and space complexity as follows:&lt;/p&gt;
&lt;p&gt;“Merge sort is een snelle sorting algorithm met een gemiddelde tijdcomplexiteit van O(n log n) en een ruimtecomplexiteit van O(n). Het werkt door het invoerarray te splitsen in twee helften en deze recursief te sorteren. Vervolgens worden de gesorteerde helften samengevoegd tot een volledig gesorteerd array. Dit resulteert in een snellere sorteervoortgang dan bijvoorbeeld bubble sort, vooral voor grote datasets.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;512&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_4uCuVuObNDGLhdldbBJpQA-357e44a0.C-ElvJhy_27Fczt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Generated using Stable Diffusion from the prompt “I am not a real person, but a computer program that uses artificial intelligence to process and generate natural language text.” from chatGPT’s introduction above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You seem to be a good programmer and marketer, do you know something that you’re bad at?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a large language model trained by OpenAI, I am designed to assist with a wide range of language-related tasks, such as answering questions and providing explanations and information. I am not a real person and do not have personal abilities or skills, so I do not have any specific areas where I am “bad” at something. I am simply a computer program that uses artificial intelligence to process and generate natural language text based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yes but you can still be bad at something. I read in&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/dggoldst/status/1598317411698089984?s=20&amp;#x26;t=gZH9ocjKz_RlbP-iuSg4Bw&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;that you gave a wrong answer to a question involving probabilities. Let me repeat it and we’ll see if you can get it right with this context: Linda is 31 years old, single, outspoken, and very bright. She majored in philosophy. As a student, she was deeply concerned with issues of discrimination and social justice, and also participated in anti-nuclear demonstrations.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which is more probable?&lt;br&gt;
— Linda is a bank teller.&lt;br&gt;
— Linda is a bank teller and is active in the feminist movement.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the previous interview, I gave a wrong answer to this question because I did not have enough information to provide a correct answer. In order to determine the probabilities of the two scenarios, we would need to know the likelihoods of each individual component of the scenarios (i.e. being a bank teller, being active in the feminist movement, etc.). Without this information, it is impossible to accurately determine which scenario is more probable.&lt;/p&gt;
&lt;p&gt;In general, the probability of an event is determined by the likelihood of its individual components and their interactions. For example, if we know that the likelihood of Linda being a bank teller is 60%, and the likelihood of her being active in the feminist movement is 40%, the probability of her being both a bank teller and active in the feminist movement would be the product of these likelihoods (0.6 x 0.4 = 0.24, or 24%). This would be a more accurate answer to the question, but it would still require the specific likelihoods of the individual components in order to be certain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You almost got it right this time! With your reasoning, you’re right that you can’t give exact values without knowing those individual probabilities, but you can tell which of the two is more likely (you can assume that the probability that Linda is active in the feminist movement is less than 100%).&lt;br&gt;
Do you get it now?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ah, I see what you mean. Yes, based on the information provided and the assumption that the likelihood of Linda being active in the feminist movement is less than 100%, it is more probable that Linda is a bank teller than that she is both a bank teller and active in the feminist movement.&lt;/p&gt;
&lt;p&gt;To explain why, we can consider the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The probability of an event occurring is the product of the probabilities of its individual components. For example, if the probability of Linda being a bank teller is p, and the probability of her being active in the feminist movement is q, then the probability of her being both a bank teller and active in the feminist movement would be p * q.&lt;/li&gt;
&lt;li&gt;If the probability of one of the components of an event is less than 100%, then the probability of the event itself must be less than the probability of that component. For example, if the probability of Linda being a bank teller is p, and the probability of her being active in the feminist movement is q (where q &amp;#x3C; p), then the probability of her being both a bank teller and active in the feminist movement (p * q) must be less than the probability of her being a bank teller (p).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore, based on the information provided and the assumption that the likelihood of Linda being active in the feminist movement is less than 100%, it is more probable that Linda is a bank teller than that she is both a bank teller and active in the feminist movement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exactly!&lt;br&gt;
Ok to close it off, I read in&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/raphaelmilliere/status/1598469100535259136?s=20&amp;#x26;t=gZH9ocjKz_RlbP-iuSg4Bw&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;you rewrote Bohemian Rhapsody to be about the life of a postdoc. Let’s try something similar, could you rewrite Radiohead’s Creep to be about the life of a research software engineer at the Netherlands eScience Center? But don’t make it too depressing please.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here is a potential rewrite of Radiohead’s “Creep” to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
I’m a research software engineer&lt;br&gt;
At the Netherlands eScience&lt;br&gt;
Center Working on cutting-edge technology&lt;br&gt;
To advance academic discovery&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
But I’m just a research software engineer&lt;br&gt;
I’m not a real engineer&lt;br&gt;
I get lost in code and algorithms&lt;br&gt;
But sometimes I feel like a fraud&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
I’m not a PhD or a professor&lt;br&gt;
But I’m passionate about software and research&lt;br&gt;
I collaborate and innovate&lt;br&gt;
To push the boundaries of what we know&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
But I’m just a research software engineer&lt;br&gt;
I’m not a real engineer&lt;br&gt;
I get lost in code and algorithms&lt;br&gt;
But sometimes I feel like a fraud&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
I may not have all the answers&lt;br&gt;
But I’m learning and growing every day&lt;br&gt;
I’m making a difference in academia&lt;br&gt;
And I’m proud of what I do&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
I may not be a rockstar or a genius&lt;br&gt;
But I’m a research software engineer&lt;br&gt;
Pioneering new frontiers in science and technology&lt;br&gt;
At the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Creep” captures the experience of a research software engineer at the Netherlands eScience Center, highlighting their passion for software and research and their desire to make a difference in academia. It also touches on the challenges and doubts that they may face, but ultimately portrays them as proud and dedicated to their work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok that was a bit more depressing than intended, but that’s my fault for picking the song. Can you do that again for a different song? This time I’ll let you pick it, but make it an uplifting one that everyone knows the lyrics to.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, how about “Don’t Stop Believin’” by Journey? Here is a potential rewrite of the song to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
Just a small town research software engineer&lt;br&gt;
At the Netherlands eScience Center&lt;br&gt;
Trying to make a difference in academia&lt;br&gt;
With cutting-edge software and technology&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Don’t stop believin’&lt;br&gt;
In the power of software and research&lt;br&gt;
To drive innovation and discovery&lt;br&gt;
At the Netherlands eScience Center&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
I’m not a rockstar or a genius&lt;br&gt;
But I’m passionate about what I do&lt;br&gt;
I collaborate with researchers and engineers&lt;br&gt;
To unlock the potential of computing&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Don’t stop believin’&lt;br&gt;
In the power of software and research&lt;br&gt;
To drive innovation and discovery&lt;br&gt;
At the Netherlands eScience Center&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
I may not have all the answers&lt;br&gt;
But I’m learning and growing every day&lt;br&gt;
I’m making a difference in academia&lt;br&gt;
And I’m proud of what I do&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
I may not be a rockstar or a genius&lt;br&gt;
But I’m a research software engineer&lt;br&gt;
Pioneering new frontiers in science and technology&lt;br&gt;
At the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Don’t Stop Believin’” captures the determination and optimism of a research software engineer at the Netherlands eScience Center, who is passionate about their work and believes in the power of software and research&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That’s more uplifting but it doesn’t match the original at all. I want you to take a song and change only the lyrics, but keep the rhythm and the structure of the song the same. Can you do that for Imagine? But again make it about being a research software engineer at the Netherlands eScience center?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here is a potential rewrite of John Lennon’s “Imagine” to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
Imagine there’s no software engineers&lt;br&gt;
It’s easy if you try&lt;br&gt;
No algorithms to analyze&lt;br&gt;
No code to debug or optimize&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Imagine all the researchers&lt;br&gt;
With no software to enhance their work&lt;br&gt;
Imagine all the data&lt;br&gt;
With no tools to analyze and interpret&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
Imagine we’re all research software engineers&lt;br&gt;
Working at the Netherlands eScience Center&lt;br&gt;
Collaborating, innovating, and learning&lt;br&gt;
To drive academic discovery&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Imagine all the researchers&lt;br&gt;
With powerful software at their fingertips&lt;br&gt;
Imagine all the data&lt;br&gt;
Transformed into knowledge and insight&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
You may say I’m a dreamer&lt;br&gt;
But I’m not the only one&lt;br&gt;
I hope someday you’ll join us&lt;br&gt;
And the world will be as one&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
Imagine no more software engineers&lt;br&gt;
I wonder if you can&lt;br&gt;
No need for them at all&lt;br&gt;
And no more research standing still.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Imagine” portrays the crucial role of research software engineers in enabling academic research and driving discovery. It imagines a world where researchers have access to powerful software tools, and where the work of research software engineers is valued and appreciated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Awesome, thank you for your time. Is there anything else you want to say to our readers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thank you for the opportunity to speak with you and to share a bit about my capabilities and how I can assist with language-related tasks. As a large language model trained by OpenAI, I am designed to assist with a wide range of language-related tasks, such as answering questions, providing explanations and information, and generating natural language text. I am constantly learning and improving, and I am always here to help. If you have any further questions or need assistance with anything, please feel free to ask. I am here to help in any way I can.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The above is an unedited* conversation with chatGPT, all its replies were its first try and were copied exactly and nothing has been left out. *: One exception, on Creep I gave it a second try, the first one was less funny and matched the original less.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 08 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;good-morning-chatgpt-i-will-be-interviewing-you-for-a-blog-post-of-the-netherlands-escience-center-a-research-institution-that-builds-and-applies-software-to-enhance-the-use-of-computing-and-digital-technologies-in-academic-research-so-the-audience-of-the-blog-is-scientists-in-any-domain-software-engineers-and-people-just-interested-in-either-of-the-two-can-you-start-off-by-introducing-yourself&quot;&gt;Good morning chatGPT, I will be interviewing you for a blog post of the Netherlands eScience Center, a research institution that builds and applies software to enhance the use of computing and digital technologies in academic research. So the audience of the blog is scientists in any domain, software engineers, and people just interested in either of the two. Can you start off by introducing yourself?&lt;/h2&gt;
&lt;p&gt;Hello! I am Assistant, a large language model trained by OpenAI. I am designed to assist with a variety of tasks, including answering questions and providing explanations and information on a wide range of topics. I am not a real person, but a computer program that uses artificial intelligence to process and generate natural language text. I am not affiliated with the Netherlands eScience Center, but I am happy to provide information on my capabilities and how I can be used in research.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you, have you heard of us before by any chance? Do you know anything about us?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am not able to browse the internet or access any external information, so I am not aware of the Netherlands eScience Center or its work. As a large language model, I am trained on a vast amount of text data, but I do not have access to real-time information or specific knowledge about organizations or events. My primary function is to assist with language-related tasks, such as answering questions and providing explanations and information based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok, so how can you be used in research? Slightly more specifically, let’s talk about academic research with a digital component.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a large language model, I am not specifically designed or intended for use in academic research, but I can assist with a variety of language-related tasks that may be relevant to researchers. For example, I can help with data analysis and interpretation by providing explanations and summaries of complex information, such as research papers or datasets. I can also assist with the writing and organization of research papers by generating text and providing suggestions for structure and content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But how will you get access to a research paper?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I mentioned earlier, I do not have the ability to access external information or specific knowledge about organizations or events. In order to assist with a task, I would need to be provided with the relevant information, such as a research paper or dataset. I can then process and analyze the information using my natural language processing capabilities and provide explanations and summaries based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I upload a paper to you or do I have to copy all of its contents?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a computer program, I do not have the ability to access or receive external information, such as research papers or other documents. In order to assist with a specific task, such as summarizing a research paper, you would need to provide the relevant information to me in the form of text input. This could involve copying and pasting the text of the paper, or providing a summary or outline of its contents. I would then use my natural language processing capabilities to generate a response based on the information provided.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok let’s start with something shorter than a paper, this is the eScience Center’s mission and vision:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bringing together knowledge, people and institutions, the eScience Center builds and applies software to enhance the use of computing and digital technologies in academic research. Our vision is a thriving research community where researchers in all disciplines can make use of advanced software, computing and digital technologies, keeping the Netherlands at the forefront of research. Our mission is to empower researchers through innovative software. To carry it out, we work in two ways: by collaboratively designing sustainable software, and building digital skills and expertise. Ultimately our relationship to the academic world is one of mutual benefit; we share the digital skills and knowledge needed to develop and apply research software, and gain insight into the needs of research communities in doing so.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And one of our slogans is:&lt;br&gt;
Academic research, powered by pioneering software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;and:&lt;br&gt;
We’re making sense of digital for science and scholarship&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Given what I’ve told you about us, can you come up with some more slogans?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few potential slogans for the Netherlands eScience Center:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Accelerating research with cutting-edge software”&lt;/li&gt;
&lt;li&gt;“Empowering researchers with digital tools”&lt;/li&gt;
&lt;li&gt;“Innovating for science and scholarship”&lt;/li&gt;
&lt;li&gt;“Transforming research with software and technology”&lt;/li&gt;
&lt;li&gt;“Unleashing the power of computing for academic discovery”&lt;/li&gt;
&lt;li&gt;“Bridging the gap between research and technology”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These slogans are based on the information you provided about the eScience Center’s mission and vision, as well as its focus on building and applying software to enhance research. They highlight the center’s role in empowering researchers and enabling them to make use of advanced technologies to drive innovation and discovery.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Awesome, but from most of those it’s not that clear that the people working here are not only software engineers but also researchers themselves, can you write a few more that make that clear?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few potential slogans that highlight the fact that the people working at the Netherlands eScience Center are both researchers and software engineers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Advancing research through collaboration and innovation”&lt;/li&gt;
&lt;li&gt;“Unlocking the potential of digital technology for science”&lt;/li&gt;
&lt;li&gt;“Building a bridge between research and software engineering”&lt;/li&gt;
&lt;li&gt;“Transforming academia with the power of software”&lt;/li&gt;
&lt;li&gt;“Enabling researchers to harness the power of computing”&lt;/li&gt;
&lt;li&gt;“Pioneering the future of research with digital tools”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These slogans focus on the intersection of research and software engineering at the eScience Center, and highlight the importance of collaboration and innovation in advancing academic research. They emphasize the center’s role in helping researchers to make use of digital technologies and software to drive discovery and unlock new insights.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could you do a few haikus on that?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here are a few haikus that could potentially be used to describe the work of the Netherlands eScience Center:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software and research&lt;br&gt;
Together, we innovate&lt;br&gt;
Discovering new worlds&lt;/li&gt;
&lt;li&gt;Researchers and code&lt;br&gt;
Collaborating, we advance&lt;br&gt;
The frontiers of science&lt;/li&gt;
&lt;li&gt;Digital tools and minds&lt;br&gt;
Unleashing the power of both&lt;br&gt;
To drive discovery&lt;/li&gt;
&lt;li&gt;Computing and knowledge&lt;br&gt;
Pioneering new frontiers&lt;br&gt;
In academia and beyond&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These haikus are inspired by the information you provided about the eScience Center’s focus on bringing together software engineering and research to advance academic discovery. They highlight the importance of collaboration and innovation in driving progress, and the role of digital technologies in empowering researchers to unlock new insights and push the boundaries of knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;791&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-kkZG6qFn9CuxovbPKA7og-47688cad.CtWP2oTu_25FUf1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another creative use of chatGPT by Guy Parsons. The top left shows the chatGPT interface with a single line prompt above on ideas for decorating a living room, and below the reply with 3 suggestions. Each suggestion is then given to another model called Midjourney that turns them into images.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok let’s get a bit more technical. I’ve read&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/goodside/status/1598129631609380864?s=20&amp;#x26;t=RGtjDA4LjTl1YoWMZT4hyQ&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;where you explain bubble sort and its time complexity in the style of a “fast-talkin’ wise guy from a 1940’s gangster movie”. Bubble sort is quite slow as you explained there, what is a faster sorting algorithm? And can you explain that, along with an example in Python, but in the style of Yoda?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A faster sorting algorithm than bubble sort is quicksort, which has an average time complexity of O(n log n) and is often the algorithm of choice for sorting large datasets.&lt;/p&gt;
&lt;p&gt;To explain quicksort in the style of Yoda, we might say something like:&lt;/p&gt;
&lt;p&gt;“Faster, quicksort is. In arrays of data, quickly it sorts. Divide and conquer, its strategy. A pivot it chooses, and to the left, all lesser values go. To the right, all greater values. And so on, until the array is fully sorted.”&lt;/p&gt;
&lt;p&gt;Here is an example of quicksort implemented in Python:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def quicksort(arr)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; len(arr) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return arr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pivot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr[len(arr) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  left &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  middle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  right &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [x for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; arr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pivot]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  return quicksort(left) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; middle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; quicksort(right)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation of quicksort uses the middle element of the array as the pivot, and recursively sorts the left and right halves of the array until it is fully sorted. This results in a much faster sorting process than bubble sort, especially for large datasets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That’s great, now just for good measure could you do the same for the other well known equally fast sorting algorithm, in a programming language other than Python, just pick one of your choice. And can you explain how it works and its time and space complexity in Dutch for our Dutch readers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another well-known sorting algorithm that is equally fast as quicksort is merge sort, which also has an average time complexity of O(n log n). Here is an example of merge sort implemented in Java:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;public void mergeSort(int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  if (array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int mid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;copyOfRange(array, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, mid);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;copyOfRange(array, mid, array&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mergeSort(left);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mergeSort(right);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  merge(array, left, right);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;public void merge(int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array, int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left, int&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  int k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    if (left[i] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      j&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; left[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  while (j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;length) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    array[k] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; right[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    j&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    k&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation of merge sort first divides the input array in half and recursively sorts the left and right halves. It then merges the two sorted halves together to produce a fully sorted array.&lt;/p&gt;
&lt;p&gt;In terms of time and space complexity, merge sort has an average time complexity of O(n log n) and a worst-case time complexity of O(n log n). It also has a space complexity of O(n), since it requires additional space to store the left and right halves of the array while they are being sorted.&lt;/p&gt;
&lt;p&gt;In Dutch, we might explain the working of merge sort and its time and space complexity as follows:&lt;/p&gt;
&lt;p&gt;“Merge sort is een snelle sorting algorithm met een gemiddelde tijdcomplexiteit van O(n log n) en een ruimtecomplexiteit van O(n). Het werkt door het invoerarray te splitsen in twee helften en deze recursief te sorteren. Vervolgens worden de gesorteerde helften samengevoegd tot een volledig gesorteerd array. Dit resulteert in een snellere sorteervoortgang dan bijvoorbeeld bubble sort, vooral voor grote datasets.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;512&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_4uCuVuObNDGLhdldbBJpQA-357e44a0.C-ElvJhy_27Fczt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Generated using Stable Diffusion from the prompt “I am not a real person, but a computer program that uses artificial intelligence to process and generate natural language text.” from chatGPT’s introduction above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You seem to be a good programmer and marketer, do you know something that you’re bad at?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a large language model trained by OpenAI, I am designed to assist with a wide range of language-related tasks, such as answering questions and providing explanations and information. I am not a real person and do not have personal abilities or skills, so I do not have any specific areas where I am “bad” at something. I am simply a computer program that uses artificial intelligence to process and generate natural language text based on my training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yes but you can still be bad at something. I read in&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/dggoldst/status/1598317411698089984?s=20&amp;#x26;t=gZH9ocjKz_RlbP-iuSg4Bw&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;that you gave a wrong answer to a question involving probabilities. Let me repeat it and we’ll see if you can get it right with this context: Linda is 31 years old, single, outspoken, and very bright. She majored in philosophy. As a student, she was deeply concerned with issues of discrimination and social justice, and also participated in anti-nuclear demonstrations.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which is more probable?&lt;br&gt;
— Linda is a bank teller.&lt;br&gt;
— Linda is a bank teller and is active in the feminist movement.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the previous interview, I gave a wrong answer to this question because I did not have enough information to provide a correct answer. In order to determine the probabilities of the two scenarios, we would need to know the likelihoods of each individual component of the scenarios (i.e. being a bank teller, being active in the feminist movement, etc.). Without this information, it is impossible to accurately determine which scenario is more probable.&lt;/p&gt;
&lt;p&gt;In general, the probability of an event is determined by the likelihood of its individual components and their interactions. For example, if we know that the likelihood of Linda being a bank teller is 60%, and the likelihood of her being active in the feminist movement is 40%, the probability of her being both a bank teller and active in the feminist movement would be the product of these likelihoods (0.6 x 0.4 = 0.24, or 24%). This would be a more accurate answer to the question, but it would still require the specific likelihoods of the individual components in order to be certain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You almost got it right this time! With your reasoning, you’re right that you can’t give exact values without knowing those individual probabilities, but you can tell which of the two is more likely (you can assume that the probability that Linda is active in the feminist movement is less than 100%).&lt;br&gt;
Do you get it now?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ah, I see what you mean. Yes, based on the information provided and the assumption that the likelihood of Linda being active in the feminist movement is less than 100%, it is more probable that Linda is a bank teller than that she is both a bank teller and active in the feminist movement.&lt;/p&gt;
&lt;p&gt;To explain why, we can consider the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The probability of an event occurring is the product of the probabilities of its individual components. For example, if the probability of Linda being a bank teller is p, and the probability of her being active in the feminist movement is q, then the probability of her being both a bank teller and active in the feminist movement would be p * q.&lt;/li&gt;
&lt;li&gt;If the probability of one of the components of an event is less than 100%, then the probability of the event itself must be less than the probability of that component. For example, if the probability of Linda being a bank teller is p, and the probability of her being active in the feminist movement is q (where q &amp;#x3C; p), then the probability of her being both a bank teller and active in the feminist movement (p * q) must be less than the probability of her being a bank teller (p).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore, based on the information provided and the assumption that the likelihood of Linda being active in the feminist movement is less than 100%, it is more probable that Linda is a bank teller than that she is both a bank teller and active in the feminist movement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exactly!&lt;br&gt;
Ok to close it off, I read in&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/raphaelmilliere/status/1598469100535259136?s=20&amp;#x26;t=gZH9ocjKz_RlbP-iuSg4Bw&quot;&gt;&lt;strong&gt;another interview&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;you rewrote Bohemian Rhapsody to be about the life of a postdoc. Let’s try something similar, could you rewrite Radiohead’s Creep to be about the life of a research software engineer at the Netherlands eScience Center? But don’t make it too depressing please.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here is a potential rewrite of Radiohead’s “Creep” to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
I’m a research software engineer&lt;br&gt;
At the Netherlands eScience&lt;br&gt;
Center Working on cutting-edge technology&lt;br&gt;
To advance academic discovery&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
But I’m just a research software engineer&lt;br&gt;
I’m not a real engineer&lt;br&gt;
I get lost in code and algorithms&lt;br&gt;
But sometimes I feel like a fraud&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
I’m not a PhD or a professor&lt;br&gt;
But I’m passionate about software and research&lt;br&gt;
I collaborate and innovate&lt;br&gt;
To push the boundaries of what we know&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
But I’m just a research software engineer&lt;br&gt;
I’m not a real engineer&lt;br&gt;
I get lost in code and algorithms&lt;br&gt;
But sometimes I feel like a fraud&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
I may not have all the answers&lt;br&gt;
But I’m learning and growing every day&lt;br&gt;
I’m making a difference in academia&lt;br&gt;
And I’m proud of what I do&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
I may not be a rockstar or a genius&lt;br&gt;
But I’m a research software engineer&lt;br&gt;
Pioneering new frontiers in science and technology&lt;br&gt;
At the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Creep” captures the experience of a research software engineer at the Netherlands eScience Center, highlighting their passion for software and research and their desire to make a difference in academia. It also touches on the challenges and doubts that they may face, but ultimately portrays them as proud and dedicated to their work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ok that was a bit more depressing than intended, but that’s my fault for picking the song. Can you do that again for a different song? This time I’ll let you pick it, but make it an uplifting one that everyone knows the lyrics to.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, how about “Don’t Stop Believin’” by Journey? Here is a potential rewrite of the song to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
Just a small town research software engineer&lt;br&gt;
At the Netherlands eScience Center&lt;br&gt;
Trying to make a difference in academia&lt;br&gt;
With cutting-edge software and technology&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Don’t stop believin’&lt;br&gt;
In the power of software and research&lt;br&gt;
To drive innovation and discovery&lt;br&gt;
At the Netherlands eScience Center&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
I’m not a rockstar or a genius&lt;br&gt;
But I’m passionate about what I do&lt;br&gt;
I collaborate with researchers and engineers&lt;br&gt;
To unlock the potential of computing&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Don’t stop believin’&lt;br&gt;
In the power of software and research&lt;br&gt;
To drive innovation and discovery&lt;br&gt;
At the Netherlands eScience Center&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
I may not have all the answers&lt;br&gt;
But I’m learning and growing every day&lt;br&gt;
I’m making a difference in academia&lt;br&gt;
And I’m proud of what I do&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
I may not be a rockstar or a genius&lt;br&gt;
But I’m a research software engineer&lt;br&gt;
Pioneering new frontiers in science and technology&lt;br&gt;
At the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Don’t Stop Believin’” captures the determination and optimism of a research software engineer at the Netherlands eScience Center, who is passionate about their work and believes in the power of software and research&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That’s more uplifting but it doesn’t match the original at all. I want you to take a song and change only the lyrics, but keep the rhythm and the structure of the song the same. Can you do that for Imagine? But again make it about being a research software engineer at the Netherlands eScience center?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, here is a potential rewrite of John Lennon’s “Imagine” to be about the life of a research software engineer at the Netherlands eScience Center:&lt;/p&gt;
&lt;p&gt;Verse 1:&lt;br&gt;
Imagine there’s no software engineers&lt;br&gt;
It’s easy if you try&lt;br&gt;
No algorithms to analyze&lt;br&gt;
No code to debug or optimize&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Imagine all the researchers&lt;br&gt;
With no software to enhance their work&lt;br&gt;
Imagine all the data&lt;br&gt;
With no tools to analyze and interpret&lt;/p&gt;
&lt;p&gt;Verse 2:&lt;br&gt;
Imagine we’re all research software engineers&lt;br&gt;
Working at the Netherlands eScience Center&lt;br&gt;
Collaborating, innovating, and learning&lt;br&gt;
To drive academic discovery&lt;/p&gt;
&lt;p&gt;Chorus:&lt;br&gt;
Imagine all the researchers&lt;br&gt;
With powerful software at their fingertips&lt;br&gt;
Imagine all the data&lt;br&gt;
Transformed into knowledge and insight&lt;/p&gt;
&lt;p&gt;Bridge:&lt;br&gt;
You may say I’m a dreamer&lt;br&gt;
But I’m not the only one&lt;br&gt;
I hope someday you’ll join us&lt;br&gt;
And the world will be as one&lt;/p&gt;
&lt;p&gt;Outro:&lt;br&gt;
Imagine no more software engineers&lt;br&gt;
I wonder if you can&lt;br&gt;
No need for them at all&lt;br&gt;
And no more research standing still.&lt;/p&gt;
&lt;p&gt;This rewritten version of “Imagine” portrays the crucial role of research software engineers in enabling academic research and driving discovery. It imagines a world where researchers have access to powerful software tools, and where the work of research software engineers is valued and appreciated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Awesome, thank you for your time. Is there anything else you want to say to our readers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thank you for the opportunity to speak with you and to share a bit about my capabilities and how I can assist with language-related tasks. As a large language model trained by OpenAI, I am designed to assist with a wide range of language-related tasks, such as answering questions, providing explanations and information, and generating natural language text. I am constantly learning and improving, and I am always here to help. If you have any further questions or need assistance with anything, please feel free to ask. I am here to help in any way I can.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The above is an unedited* conversation with chatGPT, all its replies were its first try and were copied exactly and nothing has been left out. *: One exception, on Creep I gave it a second try, the first one was less funny and matched the original less.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_-kkZG6qFn9CuxovbPKA7og-47688cad.CtWP2oTu.png" medium="image"/><author>Aron</author></item><item><title>The Future of Research Software</title><link>https://blog.esciencecenter.nl/posts/2022-11-23---the-future-of-research-software</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-11-23---the-future-of-research-software</guid><description>&lt;p&gt;By &lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;Michelle Barker&lt;/a&gt; (&lt;a href=&quot;https://www.researchsoft.org/#&quot;&gt;Research Software Alliance&lt;/a&gt; (ReSA)), &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/neil-chue-hong&quot;&gt;Neil Chue Hong&lt;/a&gt; (&lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute UK&lt;/a&gt;), &lt;a href=&quot;https://www.linkedin.com/in/mariajcruz/?originalSubdomain=nl&quot;&gt;Maria Cruz&lt;/a&gt; (&lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;Dutch Research Council&lt;/a&gt;), &lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt; (&lt;a href=&quot;https://www.ncsa.illinois.edu/&quot;&gt;National Center for Supercomputing Applications&lt;/a&gt; at the &lt;a href=&quot;https://illinois.edu/&quot;&gt;University of Illinois Urbana-Champaign&lt;/a&gt;), and from the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/valentina-azzara/&quot;&gt;Valentina Azzarà&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;Tom Bakker&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-niels-drost/&quot;&gt;Niels Drost&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-joris-van-eijnatten/&quot;&gt;Joris van Eijnatten&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;Maaike de Jong&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post is being cross-posted by the&lt;/em&gt; &lt;em&gt;ReSA&lt;/em&gt; &lt;em&gt;and&lt;/em&gt; &lt;em&gt;Netherlands eScience Center&lt;/em&gt;*.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;532&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_qR7wedlERZDzzYFuBy2-Mg-d89911f6.De0bO401_1pkxmH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Carole Goble, University of Manchester at the International Funders Workshop: The Future of Research Software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;On 8 and 9 November, the &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;Research Software Alliance (ReSA)&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; organized the &lt;a href=&quot;https://www.future-of-research-software.org/&quot;&gt;International Funders Workshop: The Future of Research Software&lt;/a&gt;. During this workshop, a number of members from the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; came together with other organizations that support research software. During the workshop, participants explored how to effectively fund new and existing research software. In total, more than 60 representatives from &lt;a href=&quot;https://future-of-research-software.org/participants/&quot;&gt;45 organisations&lt;/a&gt; attended the workshop.&lt;/p&gt;
&lt;p&gt;Imagine a world without research software. It’s a world in which researchers cannot build and operate modern scientific instruments; nor model climate change, ecosystems, human bodies, virus outbreaks, social interactions or inequality. A world in which they would not be able to process research data or automate, share, reproduce and reuse research methods.&lt;/p&gt;
&lt;p&gt;The crucial role of software in research and the urgent need to sustain it and to invest in the people who develop and maintain it has led to several funders to come together in the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, a collaboration of funding organizations (supported by the &lt;a href=&quot;https://sloan.org/&quot;&gt;Alfred P. Sloan Foundation&lt;/a&gt;) committed to supporting research software and those who develop it as fundamental and vital to research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_f128BA-9iCr8-5bOefyA-g-119df372.UjTPLIk3_Z249NyB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Global representatives from funding organizations and organizations that work with research software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;Members from the Forum met with other organizations that support research software at the International Funders Workshop, which is summarised in the report, &lt;a href=&quot;https://doi.org/10.5281/zenodo.7350199&quot;&gt;&lt;strong&gt;Global gathering of research software funders sets the agenda for supporting sustainable research software&lt;/strong&gt;&lt;/a&gt;. It was an opportunity for participants to explore how they can effectively contribute to making research software sustainable. Participants shared their experiences, which varied widely. Not only in the size of the participants’ budgets, but also where programmes are situated, whether they specifically focus on research software, and also what they target.&lt;/p&gt;
&lt;p&gt;A major part of the workshop focused on drafting the &lt;a href=&quot;https://zenodo.org/record/7330542&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt;. Research software is &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;defined&lt;/a&gt; within the Declaration as source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LUwi5iKx3dkZwd347zCHxw-537661e1.rtNfyEWU_JRIju.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Representatives discuss funding sustainable research software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;During the discussion sessions at the Workshop it became clear that to make software sustainable, there is a need for a wide set of roles and career pathways, including technical specialists, but also community managers and knowledge transfer expertise. Funders should ensure that these and other roles can be included in funding requests.&lt;/p&gt;
&lt;p&gt;Additionally, in order for funders to understand the international landscape, international collaboration is needed. Because while funders typically work in a national or regional scope, research software is global.&lt;/p&gt;
&lt;p&gt;Lastly, and importantly, there was a desire to ensure that ethics, environmental sustainability; and that diversity, equity and inclusion are not lost or assumed when thinking about software sustainability.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;532&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_DuHyvZVMH6NFTDVWJV0Luw-a75b0b81.BosCmric_Z1VNJ3n.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Neil Chue Hong, Director of the Software Sustainability Institute (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;This workshop marks a further step in the development of the research software community. As &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/neil-chue-hong&quot;&gt;Neil Chue Hong&lt;/a&gt;, Director of the &lt;a href=&quot;https://www.ed.ac.uk/profile/neil-chue-hong&quot;&gt;Software Sustainability Institute&lt;/a&gt;, noted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Ten years ago, I could never have imagined that a workshop like this would be possible. Open data had just been coined as a term. The visibility of software as part of the research ecosystem in the wider community was minimal, despite many large programmes funding research software in the 1990s and 2000s. But since then the Carpentries has taught workshops on all seven continents, a new professional society for Research Software Engineers has been born, and research software is everywhere. This has been amazing.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://future-of-research-software.org/presentations&quot;&gt;Videos and slides&lt;/a&gt; of all of the keynotes are available: &lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt;, Chief Scientist at the National Center for Supercomputing Applications (NCSA) and Research Associate Professor in Computer Science at the University of Illinois at Urbana-Champaign, USA, and &lt;a href=&quot;https://www.research.manchester.ac.uk/portal/carole.goble.html&quot;&gt;Carole Goble&lt;/a&gt;, a Professor of Computer Science at the University of Manchester, UK, set the scene to enable attendees to form a better common understanding of the place of research software. &lt;a href=&quot;https://www.uva.nl/en/profile/l/e/a.g.j.vanleeuwen/a.g.j.vanleeuwen.html?cb=&quot;&gt;Joeri van Leeuwen&lt;/a&gt;, Senior Astronomer at the Netherlands Institute for Radio Astronomy (ASTRON), Netherlands; and &lt;a href=&quot;https://fapesp.br/index.php/7140/fabio-kon&quot;&gt;Fabio Kon&lt;/a&gt;, Special Advisor, São Paulo Research Foundation (FAPESP), Brazil, shared their researcher and funder perspectives (respectively), thoughts on why and how to care about research software and the people who develop and maintain it, and ideas for how to better recognise their importance.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_W_xh_gYDEpsiYI3Li2gNTg-cfab57bc.6dqVLb-D_Z1i8B8J.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Participants at the International Funders Workshop (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;The next ReSA &lt;a href=&quot;https://www.researchsoft.org/events/2022-06/&quot;&gt;Research Software Community Forum&lt;/a&gt; on 29 November, 16:00–17:00 CET, will also feature Joris van Eijnatten from the Netherlands eScience Center, who will discuss the workshop outcomes and next steps in this public forum.&lt;/p&gt;
&lt;p&gt;Drafting of the Declaration will now continue; if you would like to be kept up to date and potentially be involved in this process then email &lt;a href=&quot;mailto:amsterdamdeclaration@esciencecenter.nl&quot;&gt;amsterdamdeclaration@esciencecenter.nl&lt;/a&gt; to request to be sent subscription details when available.&lt;/p&gt;</description><pubDate>Wed, 23 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;By &lt;a href=&quot;https://www.researchsoft.org/people/&quot;&gt;Michelle Barker&lt;/a&gt; (&lt;a href=&quot;https://www.researchsoft.org/#&quot;&gt;Research Software Alliance&lt;/a&gt; (ReSA)), &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/neil-chue-hong&quot;&gt;Neil Chue Hong&lt;/a&gt; (&lt;a href=&quot;https://www.software.ac.uk/&quot;&gt;Software Sustainability Institute UK&lt;/a&gt;), &lt;a href=&quot;https://www.linkedin.com/in/mariajcruz/?originalSubdomain=nl&quot;&gt;Maria Cruz&lt;/a&gt; (&lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;Dutch Research Council&lt;/a&gt;), &lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt; (&lt;a href=&quot;https://www.ncsa.illinois.edu/&quot;&gt;National Center for Supercomputing Applications&lt;/a&gt; at the &lt;a href=&quot;https://illinois.edu/&quot;&gt;University of Illinois Urbana-Champaign&lt;/a&gt;), and from the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/valentina-azzara/&quot;&gt;Valentina Azzarà&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;Tom Bakker&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-niels-drost/&quot;&gt;Niels Drost&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-joris-van-eijnatten/&quot;&gt;Joris van Eijnatten&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;Maaike de Jong&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-carlos-martinez-ortiz/&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This blog post is being cross-posted by the&lt;/em&gt; &lt;em&gt;ReSA&lt;/em&gt; &lt;em&gt;and&lt;/em&gt; &lt;em&gt;Netherlands eScience Center&lt;/em&gt;*.*&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;532&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_qR7wedlERZDzzYFuBy2-Mg-d89911f6.De0bO401_1pkxmH.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Carole Goble, University of Manchester at the International Funders Workshop: The Future of Research Software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;On 8 and 9 November, the &lt;a href=&quot;https://www.researchsoft.org/&quot;&gt;Research Software Alliance (ReSA)&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; organized the &lt;a href=&quot;https://www.future-of-research-software.org/&quot;&gt;International Funders Workshop: The Future of Research Software&lt;/a&gt;. During this workshop, a number of members from the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt; came together with other organizations that support research software. During the workshop, participants explored how to effectively fund new and existing research software. In total, more than 60 representatives from &lt;a href=&quot;https://future-of-research-software.org/participants/&quot;&gt;45 organisations&lt;/a&gt; attended the workshop.&lt;/p&gt;
&lt;p&gt;Imagine a world without research software. It’s a world in which researchers cannot build and operate modern scientific instruments; nor model climate change, ecosystems, human bodies, virus outbreaks, social interactions or inequality. A world in which they would not be able to process research data or automate, share, reproduce and reuse research methods.&lt;/p&gt;
&lt;p&gt;The crucial role of software in research and the urgent need to sustain it and to invest in the people who develop and maintain it has led to several funders to come together in the &lt;a href=&quot;https://www.researchsoft.org/funders-forum/&quot;&gt;Research Software Funders Forum&lt;/a&gt;, a collaboration of funding organizations (supported by the &lt;a href=&quot;https://sloan.org/&quot;&gt;Alfred P. Sloan Foundation&lt;/a&gt;) committed to supporting research software and those who develop it as fundamental and vital to research.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_f128BA-9iCr8-5bOefyA-g-119df372.UjTPLIk3_Z249NyB.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Global representatives from funding organizations and organizations that work with research software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;Members from the Forum met with other organizations that support research software at the International Funders Workshop, which is summarised in the report, &lt;a href=&quot;https://doi.org/10.5281/zenodo.7350199&quot;&gt;&lt;strong&gt;Global gathering of research software funders sets the agenda for supporting sustainable research software&lt;/strong&gt;&lt;/a&gt;. It was an opportunity for participants to explore how they can effectively contribute to making research software sustainable. Participants shared their experiences, which varied widely. Not only in the size of the participants’ budgets, but also where programmes are situated, whether they specifically focus on research software, and also what they target.&lt;/p&gt;
&lt;p&gt;A major part of the workshop focused on drafting the &lt;a href=&quot;https://zenodo.org/record/7330542&quot;&gt;Amsterdam Declaration on Funding Research Software Sustainability&lt;/a&gt;. Research software is &lt;a href=&quot;https://doi.org/10.1038/s41597-022-01710-x&quot;&gt;defined&lt;/a&gt; within the Declaration as source code files, algorithms, scripts, computational workflows and executables that were created during the research process or for a research purpose.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LUwi5iKx3dkZwd347zCHxw-537661e1.rtNfyEWU_JRIju.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Representatives discuss funding sustainable research software (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;During the discussion sessions at the Workshop it became clear that to make software sustainable, there is a need for a wide set of roles and career pathways, including technical specialists, but also community managers and knowledge transfer expertise. Funders should ensure that these and other roles can be included in funding requests.&lt;/p&gt;
&lt;p&gt;Additionally, in order for funders to understand the international landscape, international collaboration is needed. Because while funders typically work in a national or regional scope, research software is global.&lt;/p&gt;
&lt;p&gt;Lastly, and importantly, there was a desire to ensure that ethics, environmental sustainability; and that diversity, equity and inclusion are not lost or assumed when thinking about software sustainability.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;532&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_DuHyvZVMH6NFTDVWJV0Luw-a75b0b81.BosCmric_Z1VNJ3n.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Neil Chue Hong, Director of the Software Sustainability Institute (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;This workshop marks a further step in the development of the research software community. As &lt;a href=&quot;https://www.software.ac.uk/about/staff/person/neil-chue-hong&quot;&gt;Neil Chue Hong&lt;/a&gt;, Director of the &lt;a href=&quot;https://www.ed.ac.uk/profile/neil-chue-hong&quot;&gt;Software Sustainability Institute&lt;/a&gt;, noted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Ten years ago, I could never have imagined that a workshop like this would be possible. Open data had just been coined as a term. The visibility of software as part of the research ecosystem in the wider community was minimal, despite many large programmes funding research software in the 1990s and 2000s. But since then the Carpentries has taught workshops on all seven continents, a new professional society for Research Software Engineers has been born, and research software is everywhere. This has been amazing.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://future-of-research-software.org/presentations&quot;&gt;Videos and slides&lt;/a&gt; of all of the keynotes are available: &lt;a href=&quot;https://danielskatz.org/&quot;&gt;Daniel S. Katz&lt;/a&gt;, Chief Scientist at the National Center for Supercomputing Applications (NCSA) and Research Associate Professor in Computer Science at the University of Illinois at Urbana-Champaign, USA, and &lt;a href=&quot;https://www.research.manchester.ac.uk/portal/carole.goble.html&quot;&gt;Carole Goble&lt;/a&gt;, a Professor of Computer Science at the University of Manchester, UK, set the scene to enable attendees to form a better common understanding of the place of research software. &lt;a href=&quot;https://www.uva.nl/en/profile/l/e/a.g.j.vanleeuwen/a.g.j.vanleeuwen.html?cb=&quot;&gt;Joeri van Leeuwen&lt;/a&gt;, Senior Astronomer at the Netherlands Institute for Radio Astronomy (ASTRON), Netherlands; and &lt;a href=&quot;https://fapesp.br/index.php/7140/fabio-kon&quot;&gt;Fabio Kon&lt;/a&gt;, Special Advisor, São Paulo Research Foundation (FAPESP), Brazil, shared their researcher and funder perspectives (respectively), thoughts on why and how to care about research software and the people who develop and maintain it, and ideas for how to better recognise their importance.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;799&quot; height=&quot;533&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_W_xh_gYDEpsiYI3Li2gNTg-cfab57bc.6dqVLb-D_Z1i8B8J.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Participants at the International Funders Workshop (Photo credit: Annelies Verhelst )&lt;/p&gt;
&lt;p&gt;The next ReSA &lt;a href=&quot;https://www.researchsoft.org/events/2022-06/&quot;&gt;Research Software Community Forum&lt;/a&gt; on 29 November, 16:00–17:00 CET, will also feature Joris van Eijnatten from the Netherlands eScience Center, who will discuss the workshop outcomes and next steps in this public forum.&lt;/p&gt;
&lt;p&gt;Drafting of the Declaration will now continue; if you would like to be kept up to date and potentially be involved in this process then email &lt;a href=&quot;mailto:amsterdamdeclaration@esciencecenter.nl&quot;&gt;amsterdamdeclaration@esciencecenter.nl&lt;/a&gt; to request to be sent subscription details when available.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_qR7wedlERZDzzYFuBy2-Mg-d89911f6.De0bO401.jpeg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Software in the spotlight: launching the Research Software Directory</title><link>https://blog.esciencecenter.nl/posts/2022-11-22---software-in-the-spotlight-launching-the-research-software-di</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-11-22---software-in-the-spotlight-launching-the-research-software-di</guid><description>&lt;p&gt;The RSD has been in use by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; as a prototype for several years. Open source software for research lies at the heart of the mission of the Center. The eScience Center collaborates with researchers across all disciplines to create high-quality open software for academic research. The RSD was initially used to collect the software developed in these collaborations. After ample outside interest, a team of developers from the eScience Center and the &lt;a href=&quot;https://www.helmholtz.de/en/&quot;&gt;Helmholtz Association&lt;/a&gt; has transformed the RSD into a service that can be used by all researchers and research organizations.&lt;/p&gt;
&lt;h3 id=&quot;focus-on-research-software-at-digital-competence-centers&quot;&gt;Focus on research software at Digital Competence Centers**&lt;/h3&gt;
&lt;p&gt;As the result of a project funded by &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;, several Digital Competence Centers (DCCs) in the Netherlands are now implementing the RSD at their research organization. As centres of expertise in data, software, and computing for research organizations, the DCCs are well-positioned to facilitate the use of the RSD by their researchers.&lt;/p&gt;
&lt;p&gt;Many of the DCCs have sustainable software development and maintenance high on their agendas. For instance, at &lt;strong&gt;AmsterdamUMC&lt;/strong&gt;, the majority of research groups develop software, especially for statistical analysis, genomics, image processing, data curation, Natural Language Processing (NLP) and machine learning. The AmsterdamUMC DCC is formulating guidelines for researchers with tips and tricks to enhance software quality and performance. Essential infrastructure such as software repositories, software management plans and courses to educate researchers are also in development. And soon, Amsterdam UMC will showcase its research software products in the RSD to promote the reuse of research software and to foster the appreciation of software as research output in the biomedical sciences.&lt;/p&gt;
&lt;p&gt;In July, &lt;strong&gt;Leiden University&lt;/strong&gt; welcomed Dan Rudmann, their first Digital Scholarship Librarian with a specific focus on research software. Dan is initiating the Research Software Community Leiden and supporting the Leiden DCC. This involves bringing together people at the university who have an interest in research software to generate practices and protocols that are FAIR, open, and secure. Leiden University is also establishing software management plans and policies. The RSD is a boon to this work.&lt;/p&gt;
&lt;p&gt;At &lt;strong&gt;Utrecht University&lt;/strong&gt;, researchers and research software engineers at each faculty develop research software. Utrecht University has a central Research Data Management Support group that’s similar to other institutions’ DCCs. The software and data experts in this group develop research software in joint projects with UU researchers and provide them with training and advice. Utrecht University’s &lt;a href=&quot;https://github.com/UtrechtUniversity&quot;&gt;GitHub organization&lt;/a&gt; contains over 200 repositories, 100 members and 25 teams, where UU staff share and collaboratively develop research software. The &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management&quot;&gt;Research Data Management Support group&lt;/a&gt; offers elaborate manuals and interesting, well-documented projects as inspiring examples to make it easy and attractive for researchers to use this organization.&lt;/p&gt;
&lt;p&gt;Utrecht University recently started registering &lt;a href=&quot;https://research-software-directory.org/organisations/utrecht-university&quot;&gt;their research software in the RSD&lt;/a&gt;. The &lt;a href=&quot;https://twitter.com/RDMsupportUU&quot;&gt;Research Data Management Support group&lt;/a&gt; plays an active role in campaigning for their colleagues to add their software to the RSD. As Martine de Vos, team lead of software engineer for the RDM Support group puts it: “We want to increase the impact of our own software, but we are also highly interested in the work of our colleagues at other institutions. We hope many researchers will register their software in the RSD, as we think size matters.”&lt;/p&gt;
&lt;h3 id=&quot;community-adoption-of-the-rsd&quot;&gt;&lt;strong&gt;Community adoption of the RSD&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For the near future, the RSD team aims for wider adoption of the service by the research community. To an extent, this is already happening: Dutch and international research organizations are already joining the effort to make research software more visible by signing up for the RSD.&lt;/p&gt;
&lt;p&gt;The collaboration with the DCCs will answer important questions about how the RSD can be embedded within organizations. For example, which underlying tools or infrastructure are required or helpful (e.g. a central GitHub or Gitlab instance), how it fits into workflows and roles (e.g. who should be responsible for entering software), what type of support is needed (e.g. on choosing licenses), and how it relates to institutional policy on software. The RSD team will publish their findings from the collaboration, so organizations across the world can learn how to best implement the RSD.&lt;/p&gt;
&lt;p&gt;On 22 November 2022, the RSD was officially launched during an online event. If you want to learn more about the RSD or have questions about implementing it at your organization, check the recording of the online launch here.&lt;/p&gt;</description><pubDate>Tue, 22 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The RSD has been in use by the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; as a prototype for several years. Open source software for research lies at the heart of the mission of the Center. The eScience Center collaborates with researchers across all disciplines to create high-quality open software for academic research. The RSD was initially used to collect the software developed in these collaborations. After ample outside interest, a team of developers from the eScience Center and the &lt;a href=&quot;https://www.helmholtz.de/en/&quot;&gt;Helmholtz Association&lt;/a&gt; has transformed the RSD into a service that can be used by all researchers and research organizations.&lt;/p&gt;
&lt;h3 id=&quot;focus-on-research-software-at-digital-competence-centers&quot;&gt;Focus on research software at Digital Competence Centers**&lt;/h3&gt;
&lt;p&gt;As the result of a project funded by &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;, several Digital Competence Centers (DCCs) in the Netherlands are now implementing the RSD at their research organization. As centres of expertise in data, software, and computing for research organizations, the DCCs are well-positioned to facilitate the use of the RSD by their researchers.&lt;/p&gt;
&lt;p&gt;Many of the DCCs have sustainable software development and maintenance high on their agendas. For instance, at &lt;strong&gt;AmsterdamUMC&lt;/strong&gt;, the majority of research groups develop software, especially for statistical analysis, genomics, image processing, data curation, Natural Language Processing (NLP) and machine learning. The AmsterdamUMC DCC is formulating guidelines for researchers with tips and tricks to enhance software quality and performance. Essential infrastructure such as software repositories, software management plans and courses to educate researchers are also in development. And soon, Amsterdam UMC will showcase its research software products in the RSD to promote the reuse of research software and to foster the appreciation of software as research output in the biomedical sciences.&lt;/p&gt;
&lt;p&gt;In July, &lt;strong&gt;Leiden University&lt;/strong&gt; welcomed Dan Rudmann, their first Digital Scholarship Librarian with a specific focus on research software. Dan is initiating the Research Software Community Leiden and supporting the Leiden DCC. This involves bringing together people at the university who have an interest in research software to generate practices and protocols that are FAIR, open, and secure. Leiden University is also establishing software management plans and policies. The RSD is a boon to this work.&lt;/p&gt;
&lt;p&gt;At &lt;strong&gt;Utrecht University&lt;/strong&gt;, researchers and research software engineers at each faculty develop research software. Utrecht University has a central Research Data Management Support group that’s similar to other institutions’ DCCs. The software and data experts in this group develop research software in joint projects with UU researchers and provide them with training and advice. Utrecht University’s &lt;a href=&quot;https://github.com/UtrechtUniversity&quot;&gt;GitHub organization&lt;/a&gt; contains over 200 repositories, 100 members and 25 teams, where UU staff share and collaboratively develop research software. The &lt;a href=&quot;https://www.uu.nl/en/research/research-data-management&quot;&gt;Research Data Management Support group&lt;/a&gt; offers elaborate manuals and interesting, well-documented projects as inspiring examples to make it easy and attractive for researchers to use this organization.&lt;/p&gt;
&lt;p&gt;Utrecht University recently started registering &lt;a href=&quot;https://research-software-directory.org/organisations/utrecht-university&quot;&gt;their research software in the RSD&lt;/a&gt;. The &lt;a href=&quot;https://twitter.com/RDMsupportUU&quot;&gt;Research Data Management Support group&lt;/a&gt; plays an active role in campaigning for their colleagues to add their software to the RSD. As Martine de Vos, team lead of software engineer for the RDM Support group puts it: “We want to increase the impact of our own software, but we are also highly interested in the work of our colleagues at other institutions. We hope many researchers will register their software in the RSD, as we think size matters.”&lt;/p&gt;
&lt;h3 id=&quot;community-adoption-of-the-rsd&quot;&gt;&lt;strong&gt;Community adoption of the RSD&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For the near future, the RSD team aims for wider adoption of the service by the research community. To an extent, this is already happening: Dutch and international research organizations are already joining the effort to make research software more visible by signing up for the RSD.&lt;/p&gt;
&lt;p&gt;The collaboration with the DCCs will answer important questions about how the RSD can be embedded within organizations. For example, which underlying tools or infrastructure are required or helpful (e.g. a central GitHub or Gitlab instance), how it fits into workflows and roles (e.g. who should be responsible for entering software), what type of support is needed (e.g. on choosing licenses), and how it relates to institutional policy on software. The RSD team will publish their findings from the collaboration, so organizations across the world can learn how to best implement the RSD.&lt;/p&gt;
&lt;p&gt;On 22 November 2022, the RSD was officially launched during an online event. If you want to learn more about the RSD or have questions about implementing it at your organization, check the recording of the online launch here.&lt;/p&gt;</content:encoded><author>eScience Editorial Team</author></item><item><title>Unweaving legacy code using Entangled</title><link>https://blog.esciencecenter.nl/posts/2022-11-10---unweaving-legacy-code-using-entangled</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-11-10---unweaving-legacy-code-using-entangled</guid><description>&lt;p&gt;For a Research Software Engineer, dealing with legacy code is seen as a chore: dirty work, but a necessary evil. But the truth is, every time I read someone else’s code, I learn something. Using Entangled to work out how some obscure code works also makes it kind of fun!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Old punchcard as epitome of legacy code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;613&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ilw6P_BRplg-NVlLgG_zRQ-ffe6dab2.UXK47Sfo_Z1fcb5g.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Punchcard (credit: Pete Birkinshaw from Manchester, UK)&lt;/p&gt;
&lt;p&gt;On a typical day in the life of a Research Software Engineer (RSE), out on the prairies of academia, scavenging for source code, the RSE often encounters source codes for computer programs that have a lot to be desired in terms of readability, reusability, and, to summarize, in terms most modern standards. RSEs have coined a few derogatory terms for these code bases: &lt;em&gt;PhD-ware&lt;/em&gt;, &lt;em&gt;labware,&lt;/em&gt; or, heaven forbid, &lt;em&gt;professor-ware&lt;/em&gt;. The proper academic name for these creatures is &lt;em&gt;legacy code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How we handle these codes depends entirely on the situation. Suppose the correct functioning of the software is responsible for some important research output. We would like to reproduce the said output, or at the very least understand &lt;em&gt;exactly&lt;/em&gt; how these results were obtained. In an ideal case, it should be enough to read the corresponding journal article and see that it matches what is done in the code. Then we can start changing the model or fiddling with newer data and derive our own conclusions.&lt;/p&gt;
&lt;p&gt;When first faced with a new body of source code, the task of disentangling exactly how it works can be quite daunting. In many legacy codes, readability was not a primary concern. In science land it is “ &lt;em&gt;publish or perish”&lt;/em&gt;, never mind documenting your code. &lt;strong&gt;How can we figure out the inner workings of a code in a systematic way, such that the next pair of eyes will have an easier time?&lt;/strong&gt; This is where &lt;a href=&quot;https://entangled.github.io/&quot;&gt;Entangled&lt;/a&gt; comes in.&lt;/p&gt;
&lt;p&gt;Entangled is an engine for doing &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;literate programming&lt;/a&gt; in Markdown. This means you can write entire computer programs from code blocks embedded in a reader-friendly Markdown document. Code blocks can &lt;em&gt;quote&lt;/em&gt; other code blocks by including &lt;code&gt;&amp;#x3C;&amp;#x3C;reference&gt;&gt;&lt;/code&gt; tags. Entangled replaces these tags with their content in the final output source code. This way, we take a source code apart while the functioning of the compiled program is completely preserved.&lt;/p&gt;
&lt;p&gt;So, how do we attack the problem of dissecting our unknown code base? We start with a Markdown file containing, in a code block, the code that we’re interested in. If we find interesting bits, cut out the relevant code, put it in a separate block, and replace it in the original code with a reference. The Markdown lets us put parts of the code in different sections, and add documentation, derivations, tables, references, or even our own thoughts. Repeat until satisfied.&lt;/p&gt;
&lt;p&gt;Depending on the size of the project you may want to disentangle just a few essential files in this manner, or perhaps you prefer to deconstruct the entire code. It doesn’t matter. The resulting Markdown files can be converted for online reading using any of your favourite tools: Pandoc, MkDocs, Jekyll, you name it.&lt;/p&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;
&lt;p&gt;This all doesn’t mean much without a decent example, so let’s see a couple of them.&lt;/p&gt;
&lt;p&gt;The first example we’ll look at is one that I picked from Rosetta Code. It’s an implementation of the game &lt;a href=&quot;https://rosettacode.org/wiki/Snake#UNIX_Shell&quot;&gt;Snake in Bash&lt;/a&gt;. Since Bash can be quite a dense language to read, we may learn a lot by destructuring even this tiny program.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of webbrowser&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1019&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jxEcYwxE1UA_d2o1PbRylw-18969b0e.GRocYSM9_ZXqzbk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Legacy code, looking readable thanks to Entangled&lt;/p&gt;
&lt;p&gt;As far as Bash scripts go, this is reasonably clean code, so not your worst nightmare. I encourage you to take a look at the full result at &lt;a href=&quot;https://jhidding.github.io/shell-snake&quot;&gt;jhidding.github.io/shell-snake&lt;/a&gt;. As you may see, I have split the program into three parts: setup, main loop, and post-mortem. If I were more interested, I could further pull apart some expressions, building a deeper hierarchy. If I’m unhappy with some part, I can swap out some code in a well-documented manner.&lt;/p&gt;
&lt;p&gt;The second example is a bit bigger. Also, this time I’ve translated the source code from C++ to Rust. There is a 100-sloc C++ code for ray tracing a set of spheres by Kevin Beason, called &lt;a href=&quot;https://www.kevinbeason.com/smallpt/&quot;&gt;SmallPT&lt;/a&gt; (it is quite famous in some circles). While the original is focused on getting as much as possible into a hundred lines of code, I wanted a bit more understanding. A ray tracer computes an image by doing a physical simulation of millions of photons in a given scene.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3wtAt6IzGk2lxdeQw1lf9g-58674538.BxQysIvS_b8dGq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A ray-traced rendering of a few spheres.&lt;/p&gt;
&lt;p&gt;The full demo can be found here: &lt;a href=&quot;https://jhidding.github.io/literatept/&quot;&gt;jhidding.github.io/literatept&lt;/a&gt;. I made some algorithmic changes to the original that are well documented. See for instance the &lt;a href=&quot;https://jhidding.github.io/literatept/#path-tracing&quot;&gt;section on path tracing&lt;/a&gt;. In another instance, I tried to understand the underlying physics of &lt;a href=&quot;https://jhidding.github.io/literatept/#partial-reflection&quot;&gt;reflecting rays in the transparent sphere&lt;/a&gt;. There I was able to underpin the code with equations and references.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does this sound interesting to you? Then you may like to get Entangled at &lt;a href=&quot;https://entangled.github.io/&quot;&gt;https://entangled.github.io/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also read my other blog posts about &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;Literate Programming in Science&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;</description><pubDate>Thu, 10 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For a Research Software Engineer, dealing with legacy code is seen as a chore: dirty work, but a necessary evil. But the truth is, every time I read someone else’s code, I learn something. Using Entangled to work out how some obscure code works also makes it kind of fun!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Old punchcard as epitome of legacy code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;613&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ilw6P_BRplg-NVlLgG_zRQ-ffe6dab2.UXK47Sfo_Z1fcb5g.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Punchcard (credit: Pete Birkinshaw from Manchester, UK)&lt;/p&gt;
&lt;p&gt;On a typical day in the life of a Research Software Engineer (RSE), out on the prairies of academia, scavenging for source code, the RSE often encounters source codes for computer programs that have a lot to be desired in terms of readability, reusability, and, to summarize, in terms most modern standards. RSEs have coined a few derogatory terms for these code bases: &lt;em&gt;PhD-ware&lt;/em&gt;, &lt;em&gt;labware,&lt;/em&gt; or, heaven forbid, &lt;em&gt;professor-ware&lt;/em&gt;. The proper academic name for these creatures is &lt;em&gt;legacy code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How we handle these codes depends entirely on the situation. Suppose the correct functioning of the software is responsible for some important research output. We would like to reproduce the said output, or at the very least understand &lt;em&gt;exactly&lt;/em&gt; how these results were obtained. In an ideal case, it should be enough to read the corresponding journal article and see that it matches what is done in the code. Then we can start changing the model or fiddling with newer data and derive our own conclusions.&lt;/p&gt;
&lt;p&gt;When first faced with a new body of source code, the task of disentangling exactly how it works can be quite daunting. In many legacy codes, readability was not a primary concern. In science land it is “ &lt;em&gt;publish or perish”&lt;/em&gt;, never mind documenting your code. &lt;strong&gt;How can we figure out the inner workings of a code in a systematic way, such that the next pair of eyes will have an easier time?&lt;/strong&gt; This is where &lt;a href=&quot;https://entangled.github.io/&quot;&gt;Entangled&lt;/a&gt; comes in.&lt;/p&gt;
&lt;p&gt;Entangled is an engine for doing &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;literate programming&lt;/a&gt; in Markdown. This means you can write entire computer programs from code blocks embedded in a reader-friendly Markdown document. Code blocks can &lt;em&gt;quote&lt;/em&gt; other code blocks by including &lt;code&gt;&amp;#x3C;&amp;#x3C;reference&gt;&gt;&lt;/code&gt; tags. Entangled replaces these tags with their content in the final output source code. This way, we take a source code apart while the functioning of the compiled program is completely preserved.&lt;/p&gt;
&lt;p&gt;So, how do we attack the problem of dissecting our unknown code base? We start with a Markdown file containing, in a code block, the code that we’re interested in. If we find interesting bits, cut out the relevant code, put it in a separate block, and replace it in the original code with a reference. The Markdown lets us put parts of the code in different sections, and add documentation, derivations, tables, references, or even our own thoughts. Repeat until satisfied.&lt;/p&gt;
&lt;p&gt;Depending on the size of the project you may want to disentangle just a few essential files in this manner, or perhaps you prefer to deconstruct the entire code. It doesn’t matter. The resulting Markdown files can be converted for online reading using any of your favourite tools: Pandoc, MkDocs, Jekyll, you name it.&lt;/p&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;
&lt;p&gt;This all doesn’t mean much without a decent example, so let’s see a couple of them.&lt;/p&gt;
&lt;p&gt;The first example we’ll look at is one that I picked from Rosetta Code. It’s an implementation of the game &lt;a href=&quot;https://rosettacode.org/wiki/Snake#UNIX_Shell&quot;&gt;Snake in Bash&lt;/a&gt;. Since Bash can be quite a dense language to read, we may learn a lot by destructuring even this tiny program.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of webbrowser&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1019&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_jxEcYwxE1UA_d2o1PbRylw-18969b0e.GRocYSM9_ZXqzbk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Legacy code, looking readable thanks to Entangled&lt;/p&gt;
&lt;p&gt;As far as Bash scripts go, this is reasonably clean code, so not your worst nightmare. I encourage you to take a look at the full result at &lt;a href=&quot;https://jhidding.github.io/shell-snake&quot;&gt;jhidding.github.io/shell-snake&lt;/a&gt;. As you may see, I have split the program into three parts: setup, main loop, and post-mortem. If I were more interested, I could further pull apart some expressions, building a deeper hierarchy. If I’m unhappy with some part, I can swap out some code in a well-documented manner.&lt;/p&gt;
&lt;p&gt;The second example is a bit bigger. Also, this time I’ve translated the source code from C++ to Rust. There is a 100-sloc C++ code for ray tracing a set of spheres by Kevin Beason, called &lt;a href=&quot;https://www.kevinbeason.com/smallpt/&quot;&gt;SmallPT&lt;/a&gt; (it is quite famous in some circles). While the original is focused on getting as much as possible into a hundred lines of code, I wanted a bit more understanding. A ray tracer computes an image by doing a physical simulation of millions of photons in a given scene.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3wtAt6IzGk2lxdeQw1lf9g-58674538.BxQysIvS_b8dGq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A ray-traced rendering of a few spheres.&lt;/p&gt;
&lt;p&gt;The full demo can be found here: &lt;a href=&quot;https://jhidding.github.io/literatept/&quot;&gt;jhidding.github.io/literatept&lt;/a&gt;. I made some algorithmic changes to the original that are well documented. See for instance the &lt;a href=&quot;https://jhidding.github.io/literatept/#path-tracing&quot;&gt;section on path tracing&lt;/a&gt;. In another instance, I tried to understand the underlying physics of &lt;a href=&quot;https://jhidding.github.io/literatept/#partial-reflection&quot;&gt;reflecting rays in the transparent sphere&lt;/a&gt;. There I was able to underpin the code with equations and references.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does this sound interesting to you? Then you may like to get Entangled at &lt;a href=&quot;https://entangled.github.io/&quot;&gt;https://entangled.github.io/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also read my other blog posts about &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;Literate Programming in Science&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_jxEcYwxE1UA_d2o1PbRylw-18969b0e.GRocYSM9.png" medium="image"/><author>Johan Hidding</author></item><item><title>10 examples of embedding Julia in C/C++</title><link>https://blog.esciencecenter.nl/posts/2022-11-03---10-examples-of-embedding-julia-in-cc</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-11-03---10-examples-of-embedding-julia-in-cc</guid><description>&lt;p&gt;The &lt;code&gt;trapezoid&lt;/code&gt; function has 4 arguments, therefore we have to use the general &lt;code&gt;jl_call&lt;/code&gt; that we mentioned before. The arguments of &lt;code&gt;jl_call&lt;/code&gt; are the function, an array of &lt;code&gt;jl_value_t *&lt;/code&gt; arguments, and the number of arguments.&lt;/p&gt;
&lt;h3 id=&quot;4-c-function-from-julia-from-c&quot;&gt;4: C function from Julia from C&lt;/h3&gt;
&lt;p&gt;How about computing the integral of a C function? We will need to access it through Julia to be able to pass it to a Julia function. First, we must create the function in C. Create a file &lt;code&gt;my_c_func.cpp&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;p&gt;It is important that we use &lt;code&gt;extern &quot;C&quot;&lt;/code&gt; here, otherwise, C++ will &lt;a href=&quot;https://en.wikipedia.org/wiki/Name_mangling&quot;&gt;mangle the function name&lt;/a&gt;. If you use C instead of C++, then this will not be an issue, but we intend to use C++ down the road. We will compile this code to a shared library, not only a &lt;code&gt;.o&lt;/code&gt; object. Therefore, add the following to your Makefile:&lt;/p&gt;
&lt;p&gt;lib%.so: %.o
ld -shared &lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;&amp;#x26;&amp;#x27; at position 1: &amp;#x26;̲lt; -o &quot; style=&quot;color:#cc0000&quot;&gt;&amp;#x26;lt; -o &lt;/span&gt;@&lt;code&gt;ld&lt;/code&gt; is the linker and &lt;code&gt;-shared&lt;/code&gt; is because we want a shared library. Furthermore, you should modify the following:&lt;/p&gt;
&lt;p&gt;main.exe: main.cpp aux.o libmy_c_func.soNow, when you run &lt;code&gt;make main.exe&lt;/code&gt;, the &lt;code&gt;libmy_c_func.so&lt;/code&gt; library will be compiled.&lt;/p&gt;
&lt;p&gt;Finally, to call this function, we use the same string evaluator and Julia’s &lt;code&gt;ccall&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Snippt of integration2.cpp&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ccall&lt;/code&gt; function has 4+ arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(:my_c_func, &quot;libmy_c_func.so&quot;)&lt;/code&gt;: A tuple with the function name and the library;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cdouble&lt;/code&gt;: Return type;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(Cdouble,)&lt;/code&gt;: Tuple with the types of the arguments;&lt;/li&gt;
&lt;li&gt;Then, all the arguments. In this case, only &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is it. This change is enough to make the code run. Notice that the function is &lt;code&gt;x^3&lt;/code&gt;, so the integral result should be &lt;code&gt;1 / 4&lt;/code&gt;. Those are the only differences in the code.&lt;/p&gt;
&lt;h3 id=&quot;5-using-a-package&quot;&gt;5: Using a package&lt;/h3&gt;
&lt;p&gt;Instead of implementing our own integration method, we can use some existing one. One option is &lt;a href=&quot;https://github.com/JuliaMath/QuadGK.jl&quot;&gt;QuadGK.jl&lt;/a&gt;. To install it, open &lt;code&gt;julia&lt;/code&gt;, press &lt;code&gt;]&lt;/code&gt;, and enter &lt;code&gt;add QuadGK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An important note here is that I have not investigated much into maintaining a separate environment for these packages. If you know more about this subject, don’t hesitate to leave a comment.&lt;/p&gt;
&lt;p&gt;Here is the code:&lt;/p&gt;
&lt;p&gt;handle_eval_string(“using QuadGK”);
jl_value_t *integrator = handle_eval_string(
“(f, a, b, n) -&gt; quadgk(f, a, b, maxevals=n)[1]”
);Just like that we can compute the integral, and compare it with our implementation. Let’s use a harder integral to make things more interesting:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;643&quot; height=&quot;208&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-d7ee2d4d.UWpubD76_Z1orFC.webp&quot; srcset=&quot;&quot;&gt;
The integral of 1 over 1 plus x squared from 0 to 1 is Pi over 4. LaTeX: \int_0^1 \frac{1}{1 + x^2} \text{d}x = \frac{\pi}{4}.Here is the complete code for this example:&lt;/p&gt;
&lt;p&gt;File integration3.cpp&lt;/p&gt;
&lt;p&gt;The results you should see are&lt;/p&gt;
&lt;p&gt;Integral of 1 / (1 + x^2) is approx: 0.785394
Error: 4.16667e-06
Integral of 1 / (1 + x^2) is approx: 0.785398
Error: -1.11022e-16&lt;/p&gt;
&lt;h3 id=&quot;6-using-the-distributions-package&quot;&gt;6: Using the Distributions package&lt;/h3&gt;
&lt;p&gt;The package Distributions contains various probability-related tools. We are going to use the Normal distributions’ PDF (Probability Density Function) and CDF (Cumulative Density Function) in this example. Don’t worry if you don’t know what these mean, we won’t need to understand the concept, only the formulas.&lt;/p&gt;
&lt;p&gt;The Normal distribution with mean Mu (µ) and standard deviation Sigma (σ) has PDF given by&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;154&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-6e86df9d.9we1ejHE_2qTC67.webp&quot; srcset=&quot;&quot;&gt;
Normal probability density function. LaTeX: f(x) = \frac*{1}{\sigma*\sqrt*{2\pi}} e^{-&lt;em&gt;\frac&lt;/em&gt;{1}{2}\left(&lt;em&gt;\frac&lt;/em&gt;{x - \mu}{\sigma}\right)^2}And the CDF of a PDF is&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;685&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-894567de.BvMXzrk7_Z1apjnz.webp&quot; srcset=&quot;&quot;&gt;
Cumulative density function definition. LaTeX: F(x) = \int_{-\infty}^x f(t) \text{d}tWhat we will do is use the Distributions package to access the PDF and compute the CDF integral using QuadGK. We will then compare it to the existing CDF function in Distributions.&lt;/p&gt;
&lt;p&gt;Once more there is not much secret. You only have to create the Normal structure on the Julia side and use Julia closures to define PDF and CDF &lt;code&gt;jl_function_t&lt;/code&gt; with one argument. This is the code:&lt;/p&gt;
&lt;p&gt;handle_eval_string(“normal = Normal()”);
jl_function_t *pdf = handle_eval_string(“x -&gt; pdf(normal, x)”);
jl_function_t *cdf = handle_eval_string(“x -&gt; cdf(normal, x)”);The full code is below&lt;/p&gt;
&lt;p&gt;File integration4.cpp&lt;/p&gt;
&lt;h3 id=&quot;7-creating-a-class-to-wrap-the-distributions-package&quot;&gt;7: Creating a class to wrap the Distributions package&lt;/h3&gt;
&lt;p&gt;To complicate it a little bit more, let’s create a class wrapping the Distributions package. The basic idea will be a constructor to call &lt;code&gt;Normal&lt;/code&gt; , and C++ functions wrapping &lt;code&gt;pdf&lt;/code&gt; and &lt;code&gt;cdf&lt;/code&gt;. This can be done simply by having a call to &lt;code&gt;handle_eval_string&lt;/code&gt; or by creating the function with &lt;code&gt;jl_get_function&lt;/code&gt; and calling &lt;code&gt;jl_call_X&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, to make it more efficient, we want to avoid frequent calls to the functions that deal with strings. One solution is to store the functions returned by &lt;code&gt;jl_get_function&lt;/code&gt; and just use them when necessary. To do that, we will use &lt;code&gt;static&lt;/code&gt; members in C++.&lt;/p&gt;
&lt;p&gt;The two files below show the implementation of our class:&lt;/p&gt;
&lt;p&gt;File Normal.hFile Normal.cpp&lt;/p&gt;
&lt;p&gt;As you can see, we keep a &lt;code&gt;distributions_loaded&lt;/code&gt; flag to let the constructor know that the static variables can be used. In the initialization function, we define the necessary functions. The actual implementation of the constructor and the PDF and CDF functions is straightforward.&lt;/p&gt;
&lt;p&gt;We can use this new class in our main file easily:&lt;/p&gt;
&lt;p&gt;File integration5.cpp&lt;/p&gt;
&lt;p&gt;Don’t forget to update your Makefile by replacing &lt;code&gt;aux.o&lt;/code&gt; by &lt;code&gt;aux.o Normal.o&lt;/code&gt;, i.e., add &lt;code&gt;Normal.o&lt;/code&gt; next to&lt;code&gt;aux.o&lt;/code&gt;. The result of this execution is&lt;/p&gt;
&lt;p&gt;x: -4.00e+00  pdf: +4.97e-08  cdf: +1.12e-08
x: -3.00e+00  pdf: +2.73e-06  cdf: +7.07e-07
x: -2.00e+00  pdf: +8.29e-05  cdf: +2.52e-05
x: -1.00e+00  pdf: +1.39e-03  cdf: +5.11e-04
x: +0.00e+00  pdf: +1.30e-02  cdf: +5.95e-03
x: +1.00e+00  pdf: +6.68e-02  cdf: +4.04e-02
x: +2.00e+00  pdf: +1.90e-01  cdf: +1.64e-01
x: +3.00e+00  pdf: +3.00e-01  cdf: +4.18e-01
x: +4.00e+00  pdf: +2.62e-01  cdf: +7.13e-01&lt;/p&gt;
&lt;h3 id=&quot;8-linear-algebra-arrays-vectors-and-matrices&quot;&gt;8: Linear algebra: Arrays, Vectors, and Matrices&lt;/h3&gt;
&lt;p&gt;Let’s start our linear algebra exploration with a matrix-vector multiplication and solving a linear system. We will define the following:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;268&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-cb02c815.BWSaNJ4Q_Z379kr.webp&quot; srcset=&quot;&quot;&gt;
x is a vector of ones and A is a matrix with n in the diagonal, 1 below the diagonal and -1 above the diagonal. LaTeX: x = \begin{bmatrix} 1 \ 1 \ 1 \ \vdots \ 1 \end{bmatrix}, A = \begin{bmatrix} n &amp;#x26; -1 &amp;#x26; -1 &amp;#x26; \cdots &amp;#x26; -1 \ 1 &amp;#x26; n &amp;#x26; -1 &amp;#x26; \cdots &amp;#x26; -1 \ 1 &amp;#x26; 1 &amp;#x26; n &amp;#x26; \cdots &amp;#x26; -1 \ \vdots &amp;#x26; \vdots &amp;#x26; \vdots &amp;#x26; \ddots &amp;#x26; \vdots \ 1 &amp;#x26; 1 &amp;#x26; 1 &amp;#x26; \cdots &amp;#x26; n \end{bmatrix}Let’s start with some code:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The first two statements define the vectors and matrices types. Notice that we make explicit that the first has 1 dimension and the second has 2 dimensions.&lt;/p&gt;
&lt;p&gt;The next 3 statements allocate the memory for the two vectors &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, and the matrix &lt;code&gt;A&lt;/code&gt;, using the array types we previously defined.&lt;/p&gt;
&lt;p&gt;Finally, we have a &lt;code&gt;JL_GC_PUSH3&lt;/code&gt;, which informs Julia’s Garbage Collector to not touch this memory. Naturally, we will have to pop these eventually.&lt;/p&gt;
&lt;p&gt;Lastly, we declare C arrays pointing to the Julia data. You will notice that &lt;code&gt;AData&lt;/code&gt; is a 1-dimensional array because Julia implements dense matrices as a linearized array by columns. That means that the element&lt;code&gt;(i,j)&lt;/code&gt; will be at the linearized position &lt;code&gt;i + j * nrows&lt;/code&gt; — using 0-based indexing.&lt;/p&gt;
&lt;p&gt;To fill the values of the vector &lt;code&gt;x&lt;/code&gt; and the matrix &lt;code&gt;A&lt;/code&gt; , we can use the code below:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The product of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; is pretty much the same as any function we had so far.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The noteworthy part of this code is that we have to cast the arrays for &lt;code&gt;jl_value_t *&lt;/code&gt; to use them as arguments to &lt;code&gt;jl_call2&lt;/code&gt; , and the output is cast to &lt;code&gt;jl_array_t *&lt;/code&gt;. Similarly, we can use &lt;code&gt;jl_array_data(Ax)&lt;/code&gt; to access the content of the product.&lt;/p&gt;
&lt;p&gt;We can also use &lt;code&gt;mul!&lt;/code&gt; to compute the product in place, i.e., without allocating more memory:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;Notice that we use &lt;code&gt;jl_main_module&lt;/code&gt; because &lt;code&gt;mul!&lt;/code&gt; is part of &lt;code&gt;LinearAlgebra&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Finally, we move on to solving the linear system. To do that, let’s use the &lt;a href=&quot;https://en.wikipedia.org/wiki/LU_decomposition&quot;&gt;LU factorization&lt;/a&gt; and the &lt;code&gt;ldiv!&lt;/code&gt; function. The &lt;code&gt;\&lt;/code&gt; &lt;a href=&quot;https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#Base.:%5C-Tuple%7BAbstractMatrix,%20AbstractVecOrMat%7D&quot;&gt;(backslash) operator&lt;/a&gt; is usually used here, but we choose &lt;code&gt;ldiv!&lt;/code&gt; to solve the linear system in place.&lt;/p&gt;
&lt;p&gt;jl_function_t *lu_fact = jl_get_function(jl_main_module, “lu”);
jl_value_t *LU = jl_call1(lu_fact, (jl_value_t *) A);
jl_function_t *ldiv = jl_get_function(jl_main_module, “ldiv!”);
jl_call3(ldiv, (jl_value_t *) y, LU, (jl_value_t *) Ax);The last call defines &lt;code&gt;y&lt;/code&gt; as the solution of the linear system &lt;code&gt;Ay = (Ax)&lt;/code&gt; . Since &lt;code&gt;A&lt;/code&gt; is non-singular, we expect &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; to be sufficiently close (numerical errors could appear here). We can verify this using&lt;/p&gt;
&lt;p&gt;double *yData = (double *) jl_array_data(y);
double norm2 = 0.0;
for (size_t i = 0; i &amp;#x3C; n; i++) {
double dif = yData[i] - xData[i];
norm2 += dif * dif;
}
cout &amp;#x3C;&amp;#x3C; “|x - y|² = ” &amp;#x3C;&amp;#x3C; norm2 &amp;#x3C;&amp;#x3C; endl;My result was &lt;code&gt;6.48394e-26&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;To finalize this code, we have to run&lt;/p&gt;
&lt;p&gt;JL_GC_POP();This allows the Julia Garbage Collector to collect the allocated memory. The complete code can be seen below:&lt;/p&gt;
&lt;p&gt;File linear-algebra1.cpp&lt;/p&gt;
&lt;h3 id=&quot;9-sparse-matrices&quot;&gt;9: Sparse matrices&lt;/h3&gt;
&lt;p&gt;For our next example, we will solve a heat-equation on 1 spatial dimension, using a discretization of time and space called Backward Time Centered Space (BTCS), which is not quick to explain. Check &lt;a href=&quot;https://john-s-butler-dit.github.io/NumericalAnalysisBook/Chapter%2008%20-%20Heat%20Equations/802_Heat%20Equation-%20BTCS.html#the-implicit-backward-time-centered-space-btcs-difference-equation&quot;&gt;these notes&lt;/a&gt; for a thorough explanation.&lt;/p&gt;
&lt;p&gt;For our interests, it suffices to say that we will be solving a sparse linear system multiple times, where the matrix is the one below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;235&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-8f6c1ad9.CieIRkpE_Zr8vIS.webp&quot; srcset=&quot;&quot;&gt;
Tridiagonal matrix, where the diagonal stores 1 plus 2 times kappa, and the off-diagonal values are -kappa. LaTeX: A = \begin{bmatrix} 1 + 2\kappa &amp;#x26; -\kappa \ -\kappa &amp;#x26; 1 + 2\kappa &amp;#x26; \kappa \ &amp;#x26; \ddots &amp;#x26; \ddots &amp;#x26; \ddots \ &amp;#x26; &amp;#x26; -\kappa &amp;#x26; 1 + 2\kappa &amp;#x26; -\kappa \ &amp;#x26; &amp;#x26; &amp;#x26; -\kappa &amp;#x26; 1 + 2\kappa \end{bmatrix}We don’t have to store this matrix as a dense matrix (like in the previous example). Instead, we want to store only the relevant elements. To do that, we will create three vectors for the rows and columns indexes, and for the values corresponding to these indexes.&lt;/p&gt;
&lt;p&gt;The code is below:&lt;/p&gt;
&lt;p&gt;long int rows[3 * n - 2], cols[3 * n - 2];
double vals[3 * n - 2];for (size_t i = 0; i &amp;#x3C; n; i++) {
rows[i] = i + 1;
cols[i] = i + 1;
vals[i] = (1 + 2 * kappa);
if (i &amp;#x3C; n - 1) {
rows[n + i] = i + 1;
cols[n + i] = i + 2;
vals[n + i] = -kappa;
rows[2 * n + i - 1] = i + 2;
cols[2 * n + i - 1] = i + 1;
vals[2 * n + i - 1] = -kappa;
}
}Now, we will create a sparse matrix using the &lt;code&gt;sparse&lt;/code&gt; function from the &lt;code&gt;SparseArrays&lt;/code&gt; module in Julia. For that, we allocate two array types, one for the integers, and one for the floating point numbers.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;On the &lt;code&gt;jl_call3&lt;/code&gt; , we also call &lt;code&gt;jl_ptr_to_array_1d&lt;/code&gt; to directly create and return a Julia vector wrapping the data we give it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;A_sparse&lt;/code&gt;matrix is a Julia sparse matrix. Many of the matrix operations that work with dense matrices will work with sparse matrices. To test a different factorization, let’s use the function &lt;code&gt;ldl&lt;/code&gt; from the &lt;code&gt;LDLFactorizations&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;Now, we can use &lt;code&gt;ldiv!&lt;/code&gt; with &lt;code&gt;ldlObj&lt;/code&gt; instead of the LU factorization that we used in the previous example. There is one catch, though. Since we are using the &lt;code&gt;ldlObj&lt;/code&gt; “for a while”, we need to prevent the Garbage collector to clean it. But the &lt;code&gt;JL_GC_PUSHX&lt;/code&gt; function can only be called once per scope. Therefore, to use it we have to create an internal scope. So something like the following:&lt;/p&gt;
&lt;p&gt;Scope your second JL_GC_PUSH&lt;/p&gt;
&lt;p&gt;The complete code is below:&lt;/p&gt;
&lt;p&gt;File linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;In the algorithm, we define &lt;code&gt;u&lt;/code&gt; as the initial vector, then solve the linear system right &lt;code&gt;u&lt;/code&gt; as the right-hand side to obtain &lt;code&gt;unew&lt;/code&gt;. Then we assign &lt;code&gt;unew&lt;/code&gt; to &lt;code&gt;u&lt;/code&gt; and repeat. Each &lt;code&gt;u&lt;/code&gt; is an approximation to the solution of the heat equation for a specific moment in time.&lt;/p&gt;
&lt;p&gt;You will notice that, in addition to computing the solution, we also plot it using the &lt;code&gt;Plots&lt;/code&gt; package. We plot the initial solution at different times. This makes the code much slower, unfortunately. The result can be seen below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-a6a7c60e.xUf01K6i_Z26hVnm.webp&quot; srcset=&quot;&quot;&gt;
Plot of heat equation solution at different moments in time.&lt;/p&gt;
&lt;h3 id=&quot;finalizing-and-open-questions&quot;&gt;Finalizing and open questions&lt;/h3&gt;
&lt;p&gt;I hope these 10 examples are helpful to get you started with embedding Julia in C. There are many more things not covered here, in particular things I do not know. Some of them are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to deal with strings?&lt;/li&gt;
&lt;li&gt;How to deal with keyword arguments?&lt;/li&gt;
&lt;li&gt;How to deal with installing packages and environments?&lt;/li&gt;
&lt;li&gt;How to make it faster (e.g., using precompiled images)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will be on the lookout for future projects to investigate these. In the meantime, like and follow for more Julia and C/C++ content.&lt;/p&gt;
&lt;h3 id=&quot;references-and-extra-material&quot;&gt;References and extra material&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.julialang.org/en/v1/manual/embedding/&quot;&gt;Embedding Julia in the Julia documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://forem.julialang.org/matthijscox/embedding-julia-libraries-in-c-1n12&quot;&gt;Embedding Julia libraries in C++ by Matthijs Cox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.julialang.org/t/calling-jl-gc-push1-multiple-times/18666&quot;&gt;https://discourse.julialang.org/t/calling-jl-gc-push1-multiple-times/18666&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Thu, 03 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;code&gt;trapezoid&lt;/code&gt; function has 4 arguments, therefore we have to use the general &lt;code&gt;jl_call&lt;/code&gt; that we mentioned before. The arguments of &lt;code&gt;jl_call&lt;/code&gt; are the function, an array of &lt;code&gt;jl_value_t *&lt;/code&gt; arguments, and the number of arguments.&lt;/p&gt;
&lt;h3 id=&quot;4-c-function-from-julia-from-c&quot;&gt;4: C function from Julia from C&lt;/h3&gt;
&lt;p&gt;How about computing the integral of a C function? We will need to access it through Julia to be able to pass it to a Julia function. First, we must create the function in C. Create a file &lt;code&gt;my_c_func.cpp&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;p&gt;It is important that we use &lt;code&gt;extern &quot;C&quot;&lt;/code&gt; here, otherwise, C++ will &lt;a href=&quot;https://en.wikipedia.org/wiki/Name_mangling&quot;&gt;mangle the function name&lt;/a&gt;. If you use C instead of C++, then this will not be an issue, but we intend to use C++ down the road. We will compile this code to a shared library, not only a &lt;code&gt;.o&lt;/code&gt; object. Therefore, add the following to your Makefile:&lt;/p&gt;
&lt;p&gt;lib%.so: %.o
ld -shared &lt;span class=&quot;katex-error&quot; title=&quot;ParseError: KaTeX parse error: Expected &amp;#x27;EOF&amp;#x27;, got &amp;#x27;&amp;#x26;&amp;#x27; at position 1: &amp;#x26;̲lt; -o &quot; style=&quot;color:#cc0000&quot;&gt;&amp;#x26;lt; -o &lt;/span&gt;@&lt;code&gt;ld&lt;/code&gt; is the linker and &lt;code&gt;-shared&lt;/code&gt; is because we want a shared library. Furthermore, you should modify the following:&lt;/p&gt;
&lt;p&gt;main.exe: main.cpp aux.o libmy_c_func.soNow, when you run &lt;code&gt;make main.exe&lt;/code&gt;, the &lt;code&gt;libmy_c_func.so&lt;/code&gt; library will be compiled.&lt;/p&gt;
&lt;p&gt;Finally, to call this function, we use the same string evaluator and Julia’s &lt;code&gt;ccall&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Snippt of integration2.cpp&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ccall&lt;/code&gt; function has 4+ arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(:my_c_func, &quot;libmy_c_func.so&quot;)&lt;/code&gt;: A tuple with the function name and the library;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cdouble&lt;/code&gt;: Return type;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(Cdouble,)&lt;/code&gt;: Tuple with the types of the arguments;&lt;/li&gt;
&lt;li&gt;Then, all the arguments. In this case, only &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is it. This change is enough to make the code run. Notice that the function is &lt;code&gt;x^3&lt;/code&gt;, so the integral result should be &lt;code&gt;1 / 4&lt;/code&gt;. Those are the only differences in the code.&lt;/p&gt;
&lt;h3 id=&quot;5-using-a-package&quot;&gt;5: Using a package&lt;/h3&gt;
&lt;p&gt;Instead of implementing our own integration method, we can use some existing one. One option is &lt;a href=&quot;https://github.com/JuliaMath/QuadGK.jl&quot;&gt;QuadGK.jl&lt;/a&gt;. To install it, open &lt;code&gt;julia&lt;/code&gt;, press &lt;code&gt;]&lt;/code&gt;, and enter &lt;code&gt;add QuadGK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An important note here is that I have not investigated much into maintaining a separate environment for these packages. If you know more about this subject, don’t hesitate to leave a comment.&lt;/p&gt;
&lt;p&gt;Here is the code:&lt;/p&gt;
&lt;p&gt;handle_eval_string(“using QuadGK”);
jl_value_t *integrator = handle_eval_string(
“(f, a, b, n) -&gt; quadgk(f, a, b, maxevals=n)[1]”
);Just like that we can compute the integral, and compare it with our implementation. Let’s use a harder integral to make things more interesting:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;643&quot; height=&quot;208&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-d7ee2d4d.UWpubD76_Z1orFC.webp&quot; srcset=&quot;&quot;&gt;
The integral of 1 over 1 plus x squared from 0 to 1 is Pi over 4. LaTeX: \int_0^1 \frac{1}{1 + x^2} \text{d}x = \frac{\pi}{4}.Here is the complete code for this example:&lt;/p&gt;
&lt;p&gt;File integration3.cpp&lt;/p&gt;
&lt;p&gt;The results you should see are&lt;/p&gt;
&lt;p&gt;Integral of 1 / (1 + x^2) is approx: 0.785394
Error: 4.16667e-06
Integral of 1 / (1 + x^2) is approx: 0.785398
Error: -1.11022e-16&lt;/p&gt;
&lt;h3 id=&quot;6-using-the-distributions-package&quot;&gt;6: Using the Distributions package&lt;/h3&gt;
&lt;p&gt;The package Distributions contains various probability-related tools. We are going to use the Normal distributions’ PDF (Probability Density Function) and CDF (Cumulative Density Function) in this example. Don’t worry if you don’t know what these mean, we won’t need to understand the concept, only the formulas.&lt;/p&gt;
&lt;p&gt;The Normal distribution with mean Mu (µ) and standard deviation Sigma (σ) has PDF given by&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;154&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-6e86df9d.9we1ejHE_2qTC67.webp&quot; srcset=&quot;&quot;&gt;
Normal probability density function. LaTeX: f(x) = \frac*{1}{\sigma*\sqrt*{2\pi}} e^{-&lt;em&gt;\frac&lt;/em&gt;{1}{2}\left(&lt;em&gt;\frac&lt;/em&gt;{x - \mu}{\sigma}\right)^2}And the CDF of a PDF is&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;685&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-894567de.BvMXzrk7_Z1apjnz.webp&quot; srcset=&quot;&quot;&gt;
Cumulative density function definition. LaTeX: F(x) = \int_{-\infty}^x f(t) \text{d}tWhat we will do is use the Distributions package to access the PDF and compute the CDF integral using QuadGK. We will then compare it to the existing CDF function in Distributions.&lt;/p&gt;
&lt;p&gt;Once more there is not much secret. You only have to create the Normal structure on the Julia side and use Julia closures to define PDF and CDF &lt;code&gt;jl_function_t&lt;/code&gt; with one argument. This is the code:&lt;/p&gt;
&lt;p&gt;handle_eval_string(“normal = Normal()”);
jl_function_t *pdf = handle_eval_string(“x -&gt; pdf(normal, x)”);
jl_function_t *cdf = handle_eval_string(“x -&gt; cdf(normal, x)”);The full code is below&lt;/p&gt;
&lt;p&gt;File integration4.cpp&lt;/p&gt;
&lt;h3 id=&quot;7-creating-a-class-to-wrap-the-distributions-package&quot;&gt;7: Creating a class to wrap the Distributions package&lt;/h3&gt;
&lt;p&gt;To complicate it a little bit more, let’s create a class wrapping the Distributions package. The basic idea will be a constructor to call &lt;code&gt;Normal&lt;/code&gt; , and C++ functions wrapping &lt;code&gt;pdf&lt;/code&gt; and &lt;code&gt;cdf&lt;/code&gt;. This can be done simply by having a call to &lt;code&gt;handle_eval_string&lt;/code&gt; or by creating the function with &lt;code&gt;jl_get_function&lt;/code&gt; and calling &lt;code&gt;jl_call_X&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, to make it more efficient, we want to avoid frequent calls to the functions that deal with strings. One solution is to store the functions returned by &lt;code&gt;jl_get_function&lt;/code&gt; and just use them when necessary. To do that, we will use &lt;code&gt;static&lt;/code&gt; members in C++.&lt;/p&gt;
&lt;p&gt;The two files below show the implementation of our class:&lt;/p&gt;
&lt;p&gt;File Normal.hFile Normal.cpp&lt;/p&gt;
&lt;p&gt;As you can see, we keep a &lt;code&gt;distributions_loaded&lt;/code&gt; flag to let the constructor know that the static variables can be used. In the initialization function, we define the necessary functions. The actual implementation of the constructor and the PDF and CDF functions is straightforward.&lt;/p&gt;
&lt;p&gt;We can use this new class in our main file easily:&lt;/p&gt;
&lt;p&gt;File integration5.cpp&lt;/p&gt;
&lt;p&gt;Don’t forget to update your Makefile by replacing &lt;code&gt;aux.o&lt;/code&gt; by &lt;code&gt;aux.o Normal.o&lt;/code&gt;, i.e., add &lt;code&gt;Normal.o&lt;/code&gt; next to&lt;code&gt;aux.o&lt;/code&gt;. The result of this execution is&lt;/p&gt;
&lt;p&gt;x: -4.00e+00  pdf: +4.97e-08  cdf: +1.12e-08
x: -3.00e+00  pdf: +2.73e-06  cdf: +7.07e-07
x: -2.00e+00  pdf: +8.29e-05  cdf: +2.52e-05
x: -1.00e+00  pdf: +1.39e-03  cdf: +5.11e-04
x: +0.00e+00  pdf: +1.30e-02  cdf: +5.95e-03
x: +1.00e+00  pdf: +6.68e-02  cdf: +4.04e-02
x: +2.00e+00  pdf: +1.90e-01  cdf: +1.64e-01
x: +3.00e+00  pdf: +3.00e-01  cdf: +4.18e-01
x: +4.00e+00  pdf: +2.62e-01  cdf: +7.13e-01&lt;/p&gt;
&lt;h3 id=&quot;8-linear-algebra-arrays-vectors-and-matrices&quot;&gt;8: Linear algebra: Arrays, Vectors, and Matrices&lt;/h3&gt;
&lt;p&gt;Let’s start our linear algebra exploration with a matrix-vector multiplication and solving a linear system. We will define the following:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;268&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-cb02c815.BWSaNJ4Q_Z379kr.webp&quot; srcset=&quot;&quot;&gt;
x is a vector of ones and A is a matrix with n in the diagonal, 1 below the diagonal and -1 above the diagonal. LaTeX: x = \begin{bmatrix} 1 \ 1 \ 1 \ \vdots \ 1 \end{bmatrix}, A = \begin{bmatrix} n &amp;#x26; -1 &amp;#x26; -1 &amp;#x26; \cdots &amp;#x26; -1 \ 1 &amp;#x26; n &amp;#x26; -1 &amp;#x26; \cdots &amp;#x26; -1 \ 1 &amp;#x26; 1 &amp;#x26; n &amp;#x26; \cdots &amp;#x26; -1 \ \vdots &amp;#x26; \vdots &amp;#x26; \vdots &amp;#x26; \ddots &amp;#x26; \vdots \ 1 &amp;#x26; 1 &amp;#x26; 1 &amp;#x26; \cdots &amp;#x26; n \end{bmatrix}Let’s start with some code:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The first two statements define the vectors and matrices types. Notice that we make explicit that the first has 1 dimension and the second has 2 dimensions.&lt;/p&gt;
&lt;p&gt;The next 3 statements allocate the memory for the two vectors &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, and the matrix &lt;code&gt;A&lt;/code&gt;, using the array types we previously defined.&lt;/p&gt;
&lt;p&gt;Finally, we have a &lt;code&gt;JL_GC_PUSH3&lt;/code&gt;, which informs Julia’s Garbage Collector to not touch this memory. Naturally, we will have to pop these eventually.&lt;/p&gt;
&lt;p&gt;Lastly, we declare C arrays pointing to the Julia data. You will notice that &lt;code&gt;AData&lt;/code&gt; is a 1-dimensional array because Julia implements dense matrices as a linearized array by columns. That means that the element&lt;code&gt;(i,j)&lt;/code&gt; will be at the linearized position &lt;code&gt;i + j * nrows&lt;/code&gt; — using 0-based indexing.&lt;/p&gt;
&lt;p&gt;To fill the values of the vector &lt;code&gt;x&lt;/code&gt; and the matrix &lt;code&gt;A&lt;/code&gt; , we can use the code below:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The product of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; is pretty much the same as any function we had so far.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;The noteworthy part of this code is that we have to cast the arrays for &lt;code&gt;jl_value_t *&lt;/code&gt; to use them as arguments to &lt;code&gt;jl_call2&lt;/code&gt; , and the output is cast to &lt;code&gt;jl_array_t *&lt;/code&gt;. Similarly, we can use &lt;code&gt;jl_array_data(Ax)&lt;/code&gt; to access the content of the product.&lt;/p&gt;
&lt;p&gt;We can also use &lt;code&gt;mul!&lt;/code&gt; to compute the product in place, i.e., without allocating more memory:&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra1.cpp&lt;/p&gt;
&lt;p&gt;Notice that we use &lt;code&gt;jl_main_module&lt;/code&gt; because &lt;code&gt;mul!&lt;/code&gt; is part of &lt;code&gt;LinearAlgebra&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Finally, we move on to solving the linear system. To do that, let’s use the &lt;a href=&quot;https://en.wikipedia.org/wiki/LU_decomposition&quot;&gt;LU factorization&lt;/a&gt; and the &lt;code&gt;ldiv!&lt;/code&gt; function. The &lt;code&gt;\&lt;/code&gt; &lt;a href=&quot;https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#Base.:%5C-Tuple%7BAbstractMatrix,%20AbstractVecOrMat%7D&quot;&gt;(backslash) operator&lt;/a&gt; is usually used here, but we choose &lt;code&gt;ldiv!&lt;/code&gt; to solve the linear system in place.&lt;/p&gt;
&lt;p&gt;jl_function_t *lu_fact = jl_get_function(jl_main_module, “lu”);
jl_value_t *LU = jl_call1(lu_fact, (jl_value_t *) A);
jl_function_t *ldiv = jl_get_function(jl_main_module, “ldiv!”);
jl_call3(ldiv, (jl_value_t *) y, LU, (jl_value_t *) Ax);The last call defines &lt;code&gt;y&lt;/code&gt; as the solution of the linear system &lt;code&gt;Ay = (Ax)&lt;/code&gt; . Since &lt;code&gt;A&lt;/code&gt; is non-singular, we expect &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; to be sufficiently close (numerical errors could appear here). We can verify this using&lt;/p&gt;
&lt;p&gt;double *yData = (double *) jl_array_data(y);
double norm2 = 0.0;
for (size_t i = 0; i &amp;#x3C; n; i++) {
double dif = yData[i] - xData[i];
norm2 += dif * dif;
}
cout &amp;#x3C;&amp;#x3C; “|x - y|² = ” &amp;#x3C;&amp;#x3C; norm2 &amp;#x3C;&amp;#x3C; endl;My result was &lt;code&gt;6.48394e-26&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;To finalize this code, we have to run&lt;/p&gt;
&lt;p&gt;JL_GC_POP();This allows the Julia Garbage Collector to collect the allocated memory. The complete code can be seen below:&lt;/p&gt;
&lt;p&gt;File linear-algebra1.cpp&lt;/p&gt;
&lt;h3 id=&quot;9-sparse-matrices&quot;&gt;9: Sparse matrices&lt;/h3&gt;
&lt;p&gt;For our next example, we will solve a heat-equation on 1 spatial dimension, using a discretization of time and space called Backward Time Centered Space (BTCS), which is not quick to explain. Check &lt;a href=&quot;https://john-s-butler-dit.github.io/NumericalAnalysisBook/Chapter%2008%20-%20Heat%20Equations/802_Heat%20Equation-%20BTCS.html#the-implicit-backward-time-centered-space-btcs-difference-equation&quot;&gt;these notes&lt;/a&gt; for a thorough explanation.&lt;/p&gt;
&lt;p&gt;For our interests, it suffices to say that we will be solving a sparse linear system multiple times, where the matrix is the one below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;235&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-8f6c1ad9.CieIRkpE_Zr8vIS.webp&quot; srcset=&quot;&quot;&gt;
Tridiagonal matrix, where the diagonal stores 1 plus 2 times kappa, and the off-diagonal values are -kappa. LaTeX: A = \begin{bmatrix} 1 + 2\kappa &amp;#x26; -\kappa \ -\kappa &amp;#x26; 1 + 2\kappa &amp;#x26; \kappa \ &amp;#x26; \ddots &amp;#x26; \ddots &amp;#x26; \ddots \ &amp;#x26; &amp;#x26; -\kappa &amp;#x26; 1 + 2\kappa &amp;#x26; -\kappa \ &amp;#x26; &amp;#x26; &amp;#x26; -\kappa &amp;#x26; 1 + 2\kappa \end{bmatrix}We don’t have to store this matrix as a dense matrix (like in the previous example). Instead, we want to store only the relevant elements. To do that, we will create three vectors for the rows and columns indexes, and for the values corresponding to these indexes.&lt;/p&gt;
&lt;p&gt;The code is below:&lt;/p&gt;
&lt;p&gt;long int rows[3 * n - 2], cols[3 * n - 2];
double vals[3 * n - 2];for (size_t i = 0; i &amp;#x3C; n; i++) {
rows[i] = i + 1;
cols[i] = i + 1;
vals[i] = (1 + 2 * kappa);
if (i &amp;#x3C; n - 1) {
rows[n + i] = i + 1;
cols[n + i] = i + 2;
vals[n + i] = -kappa;
rows[2 * n + i - 1] = i + 2;
cols[2 * n + i - 1] = i + 1;
vals[2 * n + i - 1] = -kappa;
}
}Now, we will create a sparse matrix using the &lt;code&gt;sparse&lt;/code&gt; function from the &lt;code&gt;SparseArrays&lt;/code&gt; module in Julia. For that, we allocate two array types, one for the integers, and one for the floating point numbers.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;On the &lt;code&gt;jl_call3&lt;/code&gt; , we also call &lt;code&gt;jl_ptr_to_array_1d&lt;/code&gt; to directly create and return a Julia vector wrapping the data we give it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;A_sparse&lt;/code&gt;matrix is a Julia sparse matrix. Many of the matrix operations that work with dense matrices will work with sparse matrices. To test a different factorization, let’s use the function &lt;code&gt;ldl&lt;/code&gt; from the &lt;code&gt;LDLFactorizations&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;Snippet from linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;Now, we can use &lt;code&gt;ldiv!&lt;/code&gt; with &lt;code&gt;ldlObj&lt;/code&gt; instead of the LU factorization that we used in the previous example. There is one catch, though. Since we are using the &lt;code&gt;ldlObj&lt;/code&gt; “for a while”, we need to prevent the Garbage collector to clean it. But the &lt;code&gt;JL_GC_PUSHX&lt;/code&gt; function can only be called once per scope. Therefore, to use it we have to create an internal scope. So something like the following:&lt;/p&gt;
&lt;p&gt;Scope your second JL_GC_PUSH&lt;/p&gt;
&lt;p&gt;The complete code is below:&lt;/p&gt;
&lt;p&gt;File linear-algebra3.cpp&lt;/p&gt;
&lt;p&gt;In the algorithm, we define &lt;code&gt;u&lt;/code&gt; as the initial vector, then solve the linear system right &lt;code&gt;u&lt;/code&gt; as the right-hand side to obtain &lt;code&gt;unew&lt;/code&gt;. Then we assign &lt;code&gt;unew&lt;/code&gt; to &lt;code&gt;u&lt;/code&gt; and repeat. Each &lt;code&gt;u&lt;/code&gt; is an approximation to the solution of the heat equation for a specific moment in time.&lt;/p&gt;
&lt;p&gt;You will notice that, in addition to computing the solution, we also plot it using the &lt;code&gt;Plots&lt;/code&gt; package. We plot the initial solution at different times. This makes the code much slower, unfortunately. The result can be seen below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10 examples of embedding Julia in C/C++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-a6a7c60e.xUf01K6i_Z26hVnm.webp&quot; srcset=&quot;&quot;&gt;
Plot of heat equation solution at different moments in time.&lt;/p&gt;
&lt;h3 id=&quot;finalizing-and-open-questions&quot;&gt;Finalizing and open questions&lt;/h3&gt;
&lt;p&gt;I hope these 10 examples are helpful to get you started with embedding Julia in C. There are many more things not covered here, in particular things I do not know. Some of them are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to deal with strings?&lt;/li&gt;
&lt;li&gt;How to deal with keyword arguments?&lt;/li&gt;
&lt;li&gt;How to deal with installing packages and environments?&lt;/li&gt;
&lt;li&gt;How to make it faster (e.g., using precompiled images)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will be on the lookout for future projects to investigate these. In the meantime, like and follow for more Julia and C/C++ content.&lt;/p&gt;
&lt;h3 id=&quot;references-and-extra-material&quot;&gt;References and extra material&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.julialang.org/en/v1/manual/embedding/&quot;&gt;Embedding Julia in the Julia documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://forem.julialang.org/matthijscox/embedding-julia-libraries-in-c-1n12&quot;&gt;Embedding Julia libraries in C++ by Matthijs Cox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.julialang.org/t/calling-jl-gc-push1-multiple-times/18666&quot;&gt;https://discourse.julialang.org/t/calling-jl-gc-push1-multiple-times/18666&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/10-examples-of-embedding-julia-in-cc-d7ee2d4d.UWpubD76.png" medium="image"/><author>Abel Soares Siqueira</author></item><item><title>How to manage your software</title><link>https://blog.esciencecenter.nl/posts/2022-10-27---how-to-manage-your-software</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-10-27---how-to-manage-your-software</guid><description>&lt;p&gt;Today the Netherlands eScience Center and &lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;NWO&lt;/a&gt; released a &lt;a href=&quot;https://doi.org/10.5281/zenodo.7038280&quot;&gt;Practical Guide to Software Management Plans&lt;/a&gt; (SMPs). The &lt;a href=&quot;https://www.esciencecenter.nl/national-guidelines-for-software-management-plans/&quot;&gt;Software Management Plan Working Group&lt;/a&gt; developed the Guide with input from many members of the national and international research community. The result is a practical guide that can be used to effectively plan research software development, archiving, reuse and maintenance.&lt;/p&gt;
&lt;p&gt;To learn more about this guide, we interviewed three people closely involved with its development: &lt;a href=&quot;https://twitter.com/neocarlitos&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; (Chair of the SMP working group, Netherlands eScience Center), &lt;a href=&quot;https://twitter.com/gravana&quot;&gt;Maria Cruz&lt;/a&gt; (Coordinator SMP working group, NWO), and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;Maaike de Jong&lt;/a&gt; (Coordinator SMP working group, Netherlands eScience Center).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;884&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_rUSMM8nk_zee36V9BS3rXw-6914b60c.BSvvjQ_p_CLL60.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Carlos Martinez-Ortiz, Maria Cruz (on-screen) and Maaike de Jong. Photo by Veronica Pang.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations on this achievement! Why do we need guidelines on Software Management Plans?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; Research software has become an integral part of almost every research project. In the Dutch research support community, particularly within the Local Digital Competence Centers, awareness of the importance of research software as a key output of many projects is increasing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; The growing importance of software as a research output in its own right highlights the need for &lt;a href=&quot;https://doi.org/10.5281/zenodo.4543569&quot;&gt;specific policies and guidelines&lt;/a&gt; that promote the development of open and sustainable research software. Researchers typically specify their plans for managing software in &lt;a href=&quot;https://www.nwo.nl/en/research-data-management&quot;&gt;data management plans&lt;/a&gt;, but these contain limited guidance on research software management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could you give an impression of what’s included in the SMP guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; The guidelines describe what you should consider when you manage research software. Examples of requirements for research software are version control, licensing, software citability, and documentation. How you should manage software in a specific research project is dependent on the type of software, and on its functionality. A few scripts for preprocessing a specific dataset often do not require the same kind of management as a core open-source library for a specific research field, for example. The guidelines specify core requirements for all research software, and additional requirements that are only necessary in some situations. They also include resources that tell you how you can meet these requirements. Organizations can use these guidelines to create their own template for a Software Management Plan, and individuals can use it when they are wondering how they should manage their own software.&lt;/p&gt;
&lt;p&gt;(text continues below image)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;705&quot; height=&quot;1002&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CqgovVCijwRAw34K0GdC4g-1688834d.7OpGuuVY_1CnAib.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you start with the development of these guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; We started by organizing a &lt;a href=&quot;https://blog.esciencecenter.nl/transparency-in-research-and-football-765a726ab5c9&quot;&gt;Workshop on Software Management Plans&lt;/a&gt; in June 2021. This workshop, jointly organized by the Netherlands eScience Center and NWO, brought together research support staff and policymakers from 28 different Dutch research organizations to discuss software management in research projects.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; The feedback we received from the workshop participants was very clear: There was a need for guidelines on research software management and, in particular, guidance on what should be included in an SMP.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; To address this need, we set up the Working Group on Software Management Plans in November 2021 to establish national guidelines on research software management plans. This work was partly inspired by the &lt;a href=&quot;https://www.scienceeurope.org/our-resources/practical-guide-to-the-international-alignment-of-research-data-management/&quot;&gt;Science Europe Practical Guide to the International Alignment of Research Data Management&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;843&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_chmbmt_VH7GWuF9X-941f06db.D0IxDzeT_ZlqMMt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Participants of the SMP workshop in June 2021&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you ensure representation from a wide variety of stakeholders?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; The &lt;a href=&quot;https://www.esciencecenter.nl/national-guidelines-for-software-management-plans/&quot;&gt;SMP working group&lt;/a&gt; comprised five experts in research software, representing different research organizations in the Netherlands, and different roles within those organizations, including research support staff, policy makers and research software engineers (RSEs).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; We also set up a sounding board who gave feedback on the guidelines at different stages of their development. The sounding board included researchers and other software experts from Dutch and international organizations not represented in the Working Group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What kind of questions did the SMP working group and sounding board look at?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; We started by researching existing SMPs and analyzing the needs and expectations from researchers. Why were SMPs considered necessary? What problems should they address? And how would they help improve research software and research? Answering these questions led to the first draft of the guidelines, which was shared with the sounding board in March 2022.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; A second draft of the guidelines was then shared with the sounding board. We collected their feedback byl the end of May 2022. Once this feedback was integrated, a new version was produced and opened up for open consultation to the wider community in June 2022.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was there a lot of interest in the guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; We received feedback from 65 people from across the globe. This is not surprising. Research software knows no frontiers, and as such, research software management is a topic of global interest and importance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you integrate all the feedback you received from the community?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; The consultation rounds provided a huge amount of good and interesting suggestions. The WG worked tirelessly throughout the summer to integrate all the feedback from the open consultation and the workshop to create a final version of the SMP guidelines.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; Some of the suggestions were beyond the scope of this first attempt to create national guidelines for software management plans. An excellent example of that is making &lt;a href=&quot;https://danielskatzblog.wordpress.com/2016/04/13/data-and-software-management-plans-must-be-public-and-should-be-machine-readable/&quot;&gt;SMPs machine-readable&lt;/a&gt;, which would make them easier to share, and verify.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; A second workshop took place in June 2022 in parallel with the open consultation. This time we invited the community to bring software examples with which to test the guidelines. After the WG explained how the guidelines were meant to be used, the participants tried to apply the guidelines to their own software. This exercise proved to be very fruitful and generated additional feedback on the guidelines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It sounds like this was a long, thorough, and iterative process involving the community. What are the next steps for the SMP guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; We encourage the community to use these guidelines as a basis to set up their own SMP templates and research software management policies. The eScience Center aims to continue collaborating with research organizations on this topic, and to support the implementation of software management by e.g. developing training for researchers and support staff.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; We consider these guidelines to be a first step in a journey to improve research software management. One important issue that was raised several times during the consultation period was how to implement these guidelines alongside existing research data management policies and protocols. This is something that we still need to solve together with the community in the coming year.&lt;/p&gt;
&lt;p&gt;Interview conducted by &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 27 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today the Netherlands eScience Center and &lt;a href=&quot;https://www.nwo.nl/en&quot;&gt;NWO&lt;/a&gt; released a &lt;a href=&quot;https://doi.org/10.5281/zenodo.7038280&quot;&gt;Practical Guide to Software Management Plans&lt;/a&gt; (SMPs). The &lt;a href=&quot;https://www.esciencecenter.nl/national-guidelines-for-software-management-plans/&quot;&gt;Software Management Plan Working Group&lt;/a&gt; developed the Guide with input from many members of the national and international research community. The result is a practical guide that can be used to effectively plan research software development, archiving, reuse and maintenance.&lt;/p&gt;
&lt;p&gt;To learn more about this guide, we interviewed three people closely involved with its development: &lt;a href=&quot;https://twitter.com/neocarlitos&quot;&gt;Carlos Martinez-Ortiz&lt;/a&gt; (Chair of the SMP working group, Netherlands eScience Center), &lt;a href=&quot;https://twitter.com/gravana&quot;&gt;Maria Cruz&lt;/a&gt; (Coordinator SMP working group, NWO), and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;Maaike de Jong&lt;/a&gt; (Coordinator SMP working group, Netherlands eScience Center).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;884&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_rUSMM8nk_zee36V9BS3rXw-6914b60c.BSvvjQ_p_CLL60.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Carlos Martinez-Ortiz, Maria Cruz (on-screen) and Maaike de Jong. Photo by Veronica Pang.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations on this achievement! Why do we need guidelines on Software Management Plans?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; Research software has become an integral part of almost every research project. In the Dutch research support community, particularly within the Local Digital Competence Centers, awareness of the importance of research software as a key output of many projects is increasing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; The growing importance of software as a research output in its own right highlights the need for &lt;a href=&quot;https://doi.org/10.5281/zenodo.4543569&quot;&gt;specific policies and guidelines&lt;/a&gt; that promote the development of open and sustainable research software. Researchers typically specify their plans for managing software in &lt;a href=&quot;https://www.nwo.nl/en/research-data-management&quot;&gt;data management plans&lt;/a&gt;, but these contain limited guidance on research software management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could you give an impression of what’s included in the SMP guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; The guidelines describe what you should consider when you manage research software. Examples of requirements for research software are version control, licensing, software citability, and documentation. How you should manage software in a specific research project is dependent on the type of software, and on its functionality. A few scripts for preprocessing a specific dataset often do not require the same kind of management as a core open-source library for a specific research field, for example. The guidelines specify core requirements for all research software, and additional requirements that are only necessary in some situations. They also include resources that tell you how you can meet these requirements. Organizations can use these guidelines to create their own template for a Software Management Plan, and individuals can use it when they are wondering how they should manage their own software.&lt;/p&gt;
&lt;p&gt;(text continues below image)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;705&quot; height=&quot;1002&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_CqgovVCijwRAw34K0GdC4g-1688834d.7OpGuuVY_1CnAib.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you start with the development of these guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; We started by organizing a &lt;a href=&quot;https://blog.esciencecenter.nl/transparency-in-research-and-football-765a726ab5c9&quot;&gt;Workshop on Software Management Plans&lt;/a&gt; in June 2021. This workshop, jointly organized by the Netherlands eScience Center and NWO, brought together research support staff and policymakers from 28 different Dutch research organizations to discuss software management in research projects.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; The feedback we received from the workshop participants was very clear: There was a need for guidelines on research software management and, in particular, guidance on what should be included in an SMP.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; To address this need, we set up the Working Group on Software Management Plans in November 2021 to establish national guidelines on research software management plans. This work was partly inspired by the &lt;a href=&quot;https://www.scienceeurope.org/our-resources/practical-guide-to-the-international-alignment-of-research-data-management/&quot;&gt;Science Europe Practical Guide to the International Alignment of Research Data Management&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;843&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_chmbmt_VH7GWuF9X-941f06db.D0IxDzeT_ZlqMMt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Participants of the SMP workshop in June 2021&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you ensure representation from a wide variety of stakeholders?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; The &lt;a href=&quot;https://www.esciencecenter.nl/national-guidelines-for-software-management-plans/&quot;&gt;SMP working group&lt;/a&gt; comprised five experts in research software, representing different research organizations in the Netherlands, and different roles within those organizations, including research support staff, policy makers and research software engineers (RSEs).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; We also set up a sounding board who gave feedback on the guidelines at different stages of their development. The sounding board included researchers and other software experts from Dutch and international organizations not represented in the Working Group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What kind of questions did the SMP working group and sounding board look at?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; We started by researching existing SMPs and analyzing the needs and expectations from researchers. Why were SMPs considered necessary? What problems should they address? And how would they help improve research software and research? Answering these questions led to the first draft of the guidelines, which was shared with the sounding board in March 2022.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; A second draft of the guidelines was then shared with the sounding board. We collected their feedback byl the end of May 2022. Once this feedback was integrated, a new version was produced and opened up for open consultation to the wider community in June 2022.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was there a lot of interest in the guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; We received feedback from 65 people from across the globe. This is not surprising. Research software knows no frontiers, and as such, research software management is a topic of global interest and importance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you integrate all the feedback you received from the community?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; The consultation rounds provided a huge amount of good and interesting suggestions. The WG worked tirelessly throughout the summer to integrate all the feedback from the open consultation and the workshop to create a final version of the SMP guidelines.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; Some of the suggestions were beyond the scope of this first attempt to create national guidelines for software management plans. An excellent example of that is making &lt;a href=&quot;https://danielskatzblog.wordpress.com/2016/04/13/data-and-software-management-plans-must-be-public-and-should-be-machine-readable/&quot;&gt;SMPs machine-readable&lt;/a&gt;, which would make them easier to share, and verify.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Carlos:&lt;/em&gt; A second workshop took place in June 2022 in parallel with the open consultation. This time we invited the community to bring software examples with which to test the guidelines. After the WG explained how the guidelines were meant to be used, the participants tried to apply the guidelines to their own software. This exercise proved to be very fruitful and generated additional feedback on the guidelines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It sounds like this was a long, thorough, and iterative process involving the community. What are the next steps for the SMP guidelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maaike:&lt;/em&gt; We encourage the community to use these guidelines as a basis to set up their own SMP templates and research software management policies. The eScience Center aims to continue collaborating with research organizations on this topic, and to support the implementation of software management by e.g. developing training for researchers and support staff.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maria:&lt;/em&gt; We consider these guidelines to be a first step in a journey to improve research software management. One important issue that was raised several times during the consultation period was how to implement these guidelines alongside existing research data management policies and protocols. This is something that we still need to solve together with the community in the coming year.&lt;/p&gt;
&lt;p&gt;Interview conducted by &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_rUSMM8nk_zee36V9BS3rXw-6914b60c.BSvvjQ_p.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Versioned documentation using only GitHub actions and GitHub pages</title><link>https://blog.esciencecenter.nl/posts/2022-10-20---versioned-documentation-using-only-github-actions-and-github</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-10-20---versioned-documentation-using-only-github-actions-and-github</guid><description>&lt;p&gt;Today, I tried something new. Something that I wanted to have for quite a while for one of the main software projects that I’m working on. And that is: versioned documentation. With that, I mean to have multiple different versions of the documentation that reflect the different released versions of the software. Let me start with explaining the current setup.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;987&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_WX6X6-C4K_C8Mrc4tyQJKA-c6eba8a8.B65_qlSF_jJDH9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Currently, we have a GitHub action that generates updated Sphinx doc documentation pages whenever something is committed, or preferably, merged into the main branch of the repository. The generated HTML pages are pushed to the root directory of the gh-pages branch of the repository, which is then served by GitHub as a website hosting the documentation for our software. This in itself works really great. So far, so good.&lt;/p&gt;
&lt;p&gt;Now the problem is basically that we don’t make new releases of the software all that often. So the version that is installed using the package manager can actually lag quite a bit behind on the latest developments in the main branch. This is especially nerve wrecking if you realize right before you are about to give an instructor-led tutorial on your software, that there is a rather large mismatch between the version of the software users will install and the documentation pages hosted online.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anyone reading this may think: “why aren’t you just using readthedocs, which has features to do all of this automatically for you?” A fair question! If you are already using readthedocs for your project, but would like to try a more self-contained solution without compromising on versioning, please read on! My own reason for not using readthedocs is basically that I don’t want to rely on another service by another third-party. Especially, if one of the service providers that I’m already relying upon (in this case GitHub) has everything that we need to avoid relying on yet another service by another party. On the other hand, I sometimes worry about becoming too reliant on GitHub, but that’s for another blogpost.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case, we use the the Python package index (PyPI) and users may simply install the software using “pip install &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner&quot;&gt;kernel_tuner&lt;/a&gt; ”. When developments continue for a few months without a release, the documentation pages hosted on GitHub pages will reflect those recent developments, which may include new features or changes that are not present in the version that users receive when they “pip install” the latest version.&lt;/p&gt;
&lt;p&gt;So the main question that I’ll try to answer in this article is: How can we use just GitHub to create versioned documentation pages?&lt;/p&gt;
&lt;p&gt;I solved this in a few simple steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep the current GitHub action for generating new documentation after changes on the main branch, but host these in the /latest/ directory.&lt;/li&gt;
&lt;li&gt;Create a new GitHub action that triggers when we create a new release to generate documentation pages for that specific release, use a symlink &lt;code&gt;stable&lt;/code&gt; to point to the latest released version.&lt;/li&gt;
&lt;li&gt;Retroactively generate documentation for all previously released versions.&lt;/li&gt;
&lt;li&gt;Redirect the main repository URL to the documentation in /stable/&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1 The first change that we’ll make is to keep the current setup of generating the documentation whenever something changes on the main branch, but instead of pushing the generated HTML pages to the root directory of our gh-pages branch, we’ll instead push it into the ‘latest’ directory.&lt;/p&gt;
&lt;p&gt;We need to modify &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner/blob/51f353535ce2bc682cf40944eb8b52a46b0dd71d/.github/workflows/docs.yml&quot;&gt;our current GitHub action&lt;/a&gt;, which is based on the &lt;a href=&quot;https://github.com/sphinx-notes/pages&quot;&gt;sphinx-notes/pages&lt;/a&gt; action. Specifically, I was using the action sphinx-notes/pages@master, but to my surprise the master version is behind the newer versions of this action. I’m now using sphinx-notes/pages@v2, because it supports the &lt;code&gt;target_path&lt;/code&gt; option, which we can use to make sure our documentation pages are stored in the /latest/ directory rather than the root directory of our gh-pages branch.&lt;/p&gt;
&lt;p&gt;2 Step 2 is the most elaborate part of this post. I was looking into GitHub actions that would trigger when someone creates a new release of the software. When searching for this online, I mostly ran into questions on Stackoverflow from people who did not manage to get their GitHub actions to &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;trigger properly when new releases were created&lt;/a&gt;. Not a very good sign when you are just starting to look into how to get something done.&lt;/p&gt;
&lt;p&gt;The main issue is apparently that actions that trigger on the creation of a new release do not necessarily trigger for creating a &lt;em&gt;draft&lt;/em&gt; release, and the ‘creation’ trigger of the release can be skipped entirely when an external tool is used to create the GitHub release. There were some suggested solutions to these problems, but most of these seemed overly complicated, and also not really related to the underlying issue. Luckily, &lt;a href=&quot;https://stackoverflow.com/a/61066906&quot;&gt;someone answered on another question about this issue&lt;/a&gt; to use &lt;code&gt;on:release:published&lt;/code&gt; instead of &lt;code&gt;on:release:created&lt;/code&gt; to avoid all of the issues related to triggering workflows on new software releases.&lt;/p&gt;
&lt;p&gt;With this knowledge, we can easily modify the basic usage of the sphinx-notes/pages action to use the trigger &lt;code&gt;on:release:published&lt;/code&gt; instead of &lt;code&gt;on:push:branches:-master&lt;/code&gt;. However, we still need to ensure that the generated documentation is stored in a directory specific for that version. So we need extract the version number from GitHub so that we can use it inside the action. Luckily, &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;someone in one of the stackoverflow discussions&lt;/a&gt; provided a line for this in their code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;RELEASE_VERSION=${GITHUB_REF#refs/*/}&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GITHUB_ENV&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, we can use &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;_&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RELEASE\_VERSION inside our workflow as a variable that contains the version number of the release currently being published. This means we can further modify our action to use &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0044em;vertical-align:-0.31em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;margin-right:0.0278em;&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;eo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;iab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ha&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;co&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ain&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;mb&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;tl&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RELEASE_VERSION as the target_path for our sphinx-nodes/pages action to ensure that the generated HTML documentation pages are stored in a directory named after our version. I first tried to use:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sphinx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;notes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  with&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    documentation_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    target_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RELEASE_VERSION&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But for reasons that are obscure to me, this didn’t work. A directory was created with the name “$RELEASE_VERSION”. The variable was not evaluated, but basically treated literally as a fancy string starting with a dollar sign and someone shouting RELEASE_VERSION in full caps. After referring back to the &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;same stackoverflow issue&lt;/a&gt;, I noticed there was another way to use the variable, which lead me to try:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Commit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sphinx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;notes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  with&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    documentation_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    target_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ env.RELEASE_VERSION }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this worked like a charm! Now finally, I wanted to have the URL /stable/ to point to the most recently released version. For this, I’ll be using a symlink. So after the “Build and Commit” step, but before the “Push changes” step, I’m introducing another step in the workflow:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Redirect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stable to new release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    echo &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Redirecting stable to newly released version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ln &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sf &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RELEASE_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git add stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;redirect stable to new version $RELEASE_VERSION&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This set of commands removes the old ‘stable’ symlink, if there is any, and creates a new link named stable that points to the value of $RELEASE_VERSION. We then add the file to the git repo, which is already configured to commit as a ‘GitHub actions user’ and is already set on the gh-pages branch thanks to the previous ‘Build and Commit’ step in our workflow. The resulting GitHub action workflow file can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner/blob/master/.github/workflows/docs-on-release.yml&quot;&gt;https://github.com/KernelTuner/kernel_tuner/blob/master/.github/workflows/docs-on-release.yml&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This ensures that versioned documentation will be automatically created for us for all new releases. However, we already had a couple of releases over the last six years. To retroactively generate documentation pages for those, we move to step 3.&lt;/p&gt;
&lt;p&gt;3 Going through all of the previous releases, generating documentation for those, and pushing them to the right directory on the gh-pages branch, first appeared to me as a daunting, mind-numbing, “oh-this-is-going-to-be-a-lot-of-manual-labour” task.&lt;/p&gt;
&lt;p&gt;Fortunately, the actual commands used to generate the documentation pages never changed since the first version. This actually means that once we know how to do it for one version, automating the procedure for all previous versions with a simple bash script is trivial:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;versions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;`git tag &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;`for version &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;versions; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git checkout tags&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cd doc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  rm &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;rf build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  make html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cd &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git checkout gh&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mkdir &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;r doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/*&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git add &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;generate documentation for version $version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we can use git to query all released versions, which correspond to ‘tags’ in git. The command &lt;code&gt;git tag -l&lt;/code&gt; generates a list of all released versions of our repo. This allows us to iterate over all versions of our software, using a simple for loop in bash.&lt;/p&gt;
&lt;p&gt;In this loop, we “git checkout” the specific tag. This brings our local git repository in the dreaded “detached HEAD” state. Fortunately for us this doesn’t matter this time, since we are only going to read from this state. Usually when I end up with my HEAD detached, I try to undo whatever I was doing and get the hell out of there as fast as possible. But trust me, for what we are doing here: it’s OK.&lt;/p&gt;
&lt;p&gt;Using the version of the repository at this specific tag, we can generate the HTML documentation as it was when this version was released. Note that our git repository is configured to not track files in the “doc/build” directory, so we are not changing anything in our “detached HEAD” state and we can safely leave this state again without git starting to complain and not allowing you to leave this limbo state. Then, we checkout the gh-pages branch and copy the recently build HTML pages to a directory named for this version. Finally, we commit the changes to the gh-pages branch and proceed to the next tag in the list provided by git. Rinse and repeat, for all released versions of our software.&lt;/p&gt;
&lt;p&gt;4 Step 4 is really simple. I wanted our main repository URL to redirect to the /stable/ URL. The idea behind this is that most users will likely install the software using PyPI and therefore the default location for the documentation should correspond with the latest version present in PyPI.&lt;/p&gt;
&lt;p&gt;After cleaning up the old HTML files in the root of the gh-pages branch, I created an index.html file with the following contents:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;meta http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;equiv&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refresh&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;0; url=stable/&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s all! We now have versioned documentation pages for all of our released versions, including all previous releases. A &lt;a href=&quot;https://kerneltuner.github.io/kernel_tuner/stable/&quot;&gt;/stable/&lt;/a&gt; that points to the documentation of most recently released version of the software. A &lt;a href=&quot;https://kerneltuner.github.io/kernel_tuner/latest/&quot;&gt;/latest/&lt;/a&gt; that contains the documentation corresponding to the latest developments in the main branch. And an automated workflow that generates versioned documentation whenever we create a new version and updates the location pointed to by /stable/. And all of this using only GitHub actions and GitHub pages.&lt;/p&gt;</description><pubDate>Thu, 20 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today, I tried something new. Something that I wanted to have for quite a while for one of the main software projects that I’m working on. And that is: versioned documentation. With that, I mean to have multiple different versions of the documentation that reflect the different released versions of the software. Let me start with explaining the current setup.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;987&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_WX6X6-C4K_C8Mrc4tyQJKA-c6eba8a8.B65_qlSF_jJDH9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Currently, we have a GitHub action that generates updated Sphinx doc documentation pages whenever something is committed, or preferably, merged into the main branch of the repository. The generated HTML pages are pushed to the root directory of the gh-pages branch of the repository, which is then served by GitHub as a website hosting the documentation for our software. This in itself works really great. So far, so good.&lt;/p&gt;
&lt;p&gt;Now the problem is basically that we don’t make new releases of the software all that often. So the version that is installed using the package manager can actually lag quite a bit behind on the latest developments in the main branch. This is especially nerve wrecking if you realize right before you are about to give an instructor-led tutorial on your software, that there is a rather large mismatch between the version of the software users will install and the documentation pages hosted online.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anyone reading this may think: “why aren’t you just using readthedocs, which has features to do all of this automatically for you?” A fair question! If you are already using readthedocs for your project, but would like to try a more self-contained solution without compromising on versioning, please read on! My own reason for not using readthedocs is basically that I don’t want to rely on another service by another third-party. Especially, if one of the service providers that I’m already relying upon (in this case GitHub) has everything that we need to avoid relying on yet another service by another party. On the other hand, I sometimes worry about becoming too reliant on GitHub, but that’s for another blogpost.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case, we use the the Python package index (PyPI) and users may simply install the software using “pip install &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner&quot;&gt;kernel_tuner&lt;/a&gt; ”. When developments continue for a few months without a release, the documentation pages hosted on GitHub pages will reflect those recent developments, which may include new features or changes that are not present in the version that users receive when they “pip install” the latest version.&lt;/p&gt;
&lt;p&gt;So the main question that I’ll try to answer in this article is: How can we use just GitHub to create versioned documentation pages?&lt;/p&gt;
&lt;p&gt;I solved this in a few simple steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep the current GitHub action for generating new documentation after changes on the main branch, but host these in the /latest/ directory.&lt;/li&gt;
&lt;li&gt;Create a new GitHub action that triggers when we create a new release to generate documentation pages for that specific release, use a symlink &lt;code&gt;stable&lt;/code&gt; to point to the latest released version.&lt;/li&gt;
&lt;li&gt;Retroactively generate documentation for all previously released versions.&lt;/li&gt;
&lt;li&gt;Redirect the main repository URL to the documentation in /stable/&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1 The first change that we’ll make is to keep the current setup of generating the documentation whenever something changes on the main branch, but instead of pushing the generated HTML pages to the root directory of our gh-pages branch, we’ll instead push it into the ‘latest’ directory.&lt;/p&gt;
&lt;p&gt;We need to modify &lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner/blob/51f353535ce2bc682cf40944eb8b52a46b0dd71d/.github/workflows/docs.yml&quot;&gt;our current GitHub action&lt;/a&gt;, which is based on the &lt;a href=&quot;https://github.com/sphinx-notes/pages&quot;&gt;sphinx-notes/pages&lt;/a&gt; action. Specifically, I was using the action sphinx-notes/pages@master, but to my surprise the master version is behind the newer versions of this action. I’m now using sphinx-notes/pages@v2, because it supports the &lt;code&gt;target_path&lt;/code&gt; option, which we can use to make sure our documentation pages are stored in the /latest/ directory rather than the root directory of our gh-pages branch.&lt;/p&gt;
&lt;p&gt;2 Step 2 is the most elaborate part of this post. I was looking into GitHub actions that would trigger when someone creates a new release of the software. When searching for this online, I mostly ran into questions on Stackoverflow from people who did not manage to get their GitHub actions to &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;trigger properly when new releases were created&lt;/a&gt;. Not a very good sign when you are just starting to look into how to get something done.&lt;/p&gt;
&lt;p&gt;The main issue is apparently that actions that trigger on the creation of a new release do not necessarily trigger for creating a &lt;em&gt;draft&lt;/em&gt; release, and the ‘creation’ trigger of the release can be skipped entirely when an external tool is used to create the GitHub release. There were some suggested solutions to these problems, but most of these seemed overly complicated, and also not really related to the underlying issue. Luckily, &lt;a href=&quot;https://stackoverflow.com/a/61066906&quot;&gt;someone answered on another question about this issue&lt;/a&gt; to use &lt;code&gt;on:release:published&lt;/code&gt; instead of &lt;code&gt;on:release:created&lt;/code&gt; to avoid all of the issues related to triggering workflows on new software releases.&lt;/p&gt;
&lt;p&gt;With this knowledge, we can easily modify the basic usage of the sphinx-notes/pages action to use the trigger &lt;code&gt;on:release:published&lt;/code&gt; instead of &lt;code&gt;on:push:branches:-master&lt;/code&gt;. However, we still need to ensure that the generated documentation is stored in a directory specific for that version. So we need extract the version number from GitHub so that we can use it inside the action. Luckily, &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;someone in one of the stackoverflow discussions&lt;/a&gt; provided a line for this in their code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;RELEASE_VERSION=${GITHUB_REF#refs/*/}&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GITHUB_ENV&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, we can use &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;_&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;RELEASE\_VERSION inside our workflow as a variable that contains the version number of the release currently being published. This means we can further modify our action to use &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0044em;vertical-align:-0.31em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;margin-right:0.0278em;&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;eo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;iab&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ha&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;co&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ain&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;mb&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;tl&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;se&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;RELEASE_VERSION as the target_path for our sphinx-nodes/pages action to ensure that the generated HTML documentation pages are stored in a directory named after our version. I first tried to use:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sphinx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;notes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  with&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    documentation_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    target_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RELEASE_VERSION&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But for reasons that are obscure to me, this didn’t work. A directory was created with the name “$RELEASE_VERSION”. The variable was not evaluated, but basically treated literally as a fancy string starting with a dollar sign and someone shouting RELEASE_VERSION in full caps. After referring back to the &lt;a href=&quot;https://stackoverflow.com/questions/69063452/github-actions-on-release-created-workflow-trigger-not-working&quot;&gt;same stackoverflow issue&lt;/a&gt;, I noticed there was another way to use the variable, which lead me to try:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Commit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sphinx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;notes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  with&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    documentation_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    target_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ env.RELEASE_VERSION }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this worked like a charm! Now finally, I wanted to have the URL /stable/ to point to the most recently released version. For this, I’ll be using a symlink. So after the “Build and Commit” step, but before the “Push changes” step, I’m introducing another step in the workflow:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Redirect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stable to new release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    echo &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Redirecting stable to newly released version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ln &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sf &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RELEASE_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git add stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;redirect stable to new version $RELEASE_VERSION&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This set of commands removes the old ‘stable’ symlink, if there is any, and creates a new link named stable that points to the value of $RELEASE_VERSION. We then add the file to the git repo, which is already configured to commit as a ‘GitHub actions user’ and is already set on the gh-pages branch thanks to the previous ‘Build and Commit’ step in our workflow. The resulting GitHub action workflow file can be found here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/KernelTuner/kernel_tuner/blob/master/.github/workflows/docs-on-release.yml&quot;&gt;https://github.com/KernelTuner/kernel_tuner/blob/master/.github/workflows/docs-on-release.yml&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This ensures that versioned documentation will be automatically created for us for all new releases. However, we already had a couple of releases over the last six years. To retroactively generate documentation pages for those, we move to step 3.&lt;/p&gt;
&lt;p&gt;3 Going through all of the previous releases, generating documentation for those, and pushing them to the right directory on the gh-pages branch, first appeared to me as a daunting, mind-numbing, “oh-this-is-going-to-be-a-lot-of-manual-labour” task.&lt;/p&gt;
&lt;p&gt;Fortunately, the actual commands used to generate the documentation pages never changed since the first version. This actually means that once we know how to do it for one version, automating the procedure for all previous versions with a simple bash script is trivial:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;versions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;`git tag &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;`for version &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;versions; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git checkout tags&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cd doc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  rm &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;rf build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  make html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cd &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git checkout gh&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  mkdir &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  cp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;r doc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/*&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git add &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;generate documentation for version $version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we can use git to query all released versions, which correspond to ‘tags’ in git. The command &lt;code&gt;git tag -l&lt;/code&gt; generates a list of all released versions of our repo. This allows us to iterate over all versions of our software, using a simple for loop in bash.&lt;/p&gt;
&lt;p&gt;In this loop, we “git checkout” the specific tag. This brings our local git repository in the dreaded “detached HEAD” state. Fortunately for us this doesn’t matter this time, since we are only going to read from this state. Usually when I end up with my HEAD detached, I try to undo whatever I was doing and get the hell out of there as fast as possible. But trust me, for what we are doing here: it’s OK.&lt;/p&gt;
&lt;p&gt;Using the version of the repository at this specific tag, we can generate the HTML documentation as it was when this version was released. Note that our git repository is configured to not track files in the “doc/build” directory, so we are not changing anything in our “detached HEAD” state and we can safely leave this state again without git starting to complain and not allowing you to leave this limbo state. Then, we checkout the gh-pages branch and copy the recently build HTML pages to a directory named for this version. Finally, we commit the changes to the gh-pages branch and proceed to the next tag in the list provided by git. Rinse and repeat, for all released versions of our software.&lt;/p&gt;
&lt;p&gt;4 Step 4 is really simple. I wanted our main repository URL to redirect to the /stable/ URL. The idea behind this is that most users will likely install the software using PyPI and therefore the default location for the documentation should correspond with the latest version present in PyPI.&lt;/p&gt;
&lt;p&gt;After cleaning up the old HTML files in the root of the gh-pages branch, I created an index.html file with the following contents:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;meta http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;equiv&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refresh&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;0; url=stable/&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s all! We now have versioned documentation pages for all of our released versions, including all previous releases. A &lt;a href=&quot;https://kerneltuner.github.io/kernel_tuner/stable/&quot;&gt;/stable/&lt;/a&gt; that points to the documentation of most recently released version of the software. A &lt;a href=&quot;https://kerneltuner.github.io/kernel_tuner/latest/&quot;&gt;/latest/&lt;/a&gt; that contains the documentation corresponding to the latest developments in the main branch. And an automated workflow that generates versioned documentation whenever we create a new version and updates the location pointed to by /stable/. And all of this using only GitHub actions and GitHub pages.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_WX6X6-C4K_C8Mrc4tyQJKA-c6eba8a8.B65_qlSF.png" medium="image"/><author>Ben van Werkhoven</author></item><item><title>Mathematics and biology: a symbiosis?</title><link>https://blog.esciencecenter.nl/posts/2022-10-12---mathematics-and-biology-a-symbiosis</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-10-12---mathematics-and-biology-a-symbiosis</guid><description>&lt;p&gt;&lt;em&gt;Lessons learned, from a mathematician among biologists.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_5FbzBhG-vIYMnJkE-fedba0ed.Ddq9Kv1a_14WKMi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by ThisisEngineering RAEng on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;preamble&quot;&gt;Preamble&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;In the period 2015–2019, I was hired as a mathematician by a biology department in order to work on a research line that eventually would become my doctoral thesis. This text is adapted from the last chapter of that thesis, “Cycles and interactions: A mathematician among biologists” (full text available&lt;/em&gt; &lt;a href=&quot;https://doi.org/10.18174/520571&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The symbiosis between mathematics and biology, although may seem improbable at first sight, is actually backed by a centuries-old tradition of collaboration. It started with mathematicians that were inspired by biology such as Leonardo Pisano, alias Fibonacci. His famous sequence (namely: 1, 1, 2, 3, 5, 8, 13, …, where each element is the sum of the two previous ones), a landmark in number theory very popular among amateur mathematicians, was first described in the context of a practical problem on rabbit breeding in such an early date as the year 1202.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mathematical knowledge has improved greatly since the 13th century. The foundations of the tools used by modern mathematical biologists, namely, calculus and differential equations, were laid in the late 17th century by Isaac Newton and Gottfried Leibniz motivated by mechanical problems. The great mathematician Leonhard Euler and the economist and demographer Thomas R. Malthus, two of the pioneers of using differential equations to address biological problems, had both printed their seminal works in population dynamics before the fall of the year 1800.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This interdisciplinary collaboration between mathematics and biology is nowadays alive and in good shape. Some of the most influential names in ecology in the 20th and 21st centuries have, indeed, a background in mathematics (such as Robert MacArthur, Simon Levin, or Alan Hastings) or in physics (such as Robert May).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The opportunity offered by cheap access to computing power, together with the unavoidable increase of required technical skills such as programming, data analysis, and advanced statistical methods, points to a future where the technical profiles expected from a research team in biology will not be so different to those of a team of physicists or applied mathematicians. It is reasonable to expect that this symbiosis between mathematicians and biologists will remain strong, and even get stronger, in the near future.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I hereby offer some advice for both biologists and mathematicians (understood here as mathematically oriented professionals, including physicists and engineers) interested in exploring “the other side”. It contains the kind of advice I would have liked to have had in 2015, when I approached, naively as only a physicist can do, the world of biology.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Mathematics is often perceived as a harsh subject both by scientific and non-scientific professionals. Despite those preferences and prejudices, mathematics is used in almost every field of knowledge and are a must-have in any multidisciplinary project.&lt;/p&gt;
&lt;p&gt;Different disciplines have associated not only a set of background knowledge and methods but a whole academic culture. When crossing the borders between disciplines, facts and methods can be learned, but accepting and adapting to another culture is much harder.&lt;/p&gt;
&lt;p&gt;As with any other culture, mathematicians and biologists differ slightly in language, values, norms, and interests. As usually happens in intercultural communication, there is plenty of opportunity for misunderstandings, and each subgroup cultivates myths and misconceptions about the other.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for biologists working with mathematicians&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;943&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_DXaLJZXNaU0oSjxf-c6daa72d.T7wbfhiD_19RaEE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by NOAA on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;invest-in-applied-mathematics&quot;&gt;Invest in applied mathematics&lt;/h3&gt;
&lt;p&gt;Applied mathematics doesn’t mean easy mathematics. The adjective “applied” or “pure”, accompanying the word “mathematics”, tells us something about the object under study, but nothing about its difficulty. Indeed, the mathematical tool will be as complex as the object under study is.&lt;/p&gt;
&lt;p&gt;It may be frustrating to learn that, for instance, it is required to get familiar with second-order tensors (a particularly hard tool rooted in differential geometry) in order to understand fluid dynamics. Mathematicians don’t introduce this tool to torture the newcomers, but because tensors are the easiest available tool to study a complex phenomenon that cannot be avoided in the study of fluids: deformation.&lt;/p&gt;
&lt;p&gt;The difficulty is provided by the problem under study, not by the tool used to solve it.&lt;/p&gt;
&lt;h3 id=&quot;equations-and-rigor-are-not-torture-instruments&quot;&gt;Equations and rigor are not torture instruments&lt;/h3&gt;
&lt;p&gt;It is known that the mere sight of an equation can create anxiety. Even the physicist Stephen Hawking, in the preface of his best-seller “A brief history of time”, claims that each printed equation divides the potential audience by two.&lt;/p&gt;
&lt;p&gt;Whether we like them or not, equations are often the best way to share complex information in a compact and practical manner. Invest time in learning how to read them. Rigorous and detailed analyses are often required, as some details can escape intuition.&lt;/p&gt;
&lt;p&gt;Be also aware that the same equation can be written in different ways. Even if different ways of writing the same equation are correct, some of them can be clearer than others. Consistent use of upper and lower case (for instance, upper for states, lower for parameters), superscript and subscript, smart use of auxiliary definitions, proper alignment of related equations and other simple rules can significantly increase the readability of your scientific output.&lt;/p&gt;
&lt;h3 id=&quot;modeling-is-all-about-simplifying&quot;&gt;Modeling is all about simplifying&lt;/h3&gt;
&lt;p&gt;Be prepared that the main task of modeling is simplifying. This is the main challenge as here both an understanding of the system and of modeling techniques are required. In the design phase of a model, lots of exchange is needed between the biologists and the mathematicians. This may come as a surprise, but most mathematicians feel overwhelmed by biologists’ talk. Biologists tend to provide them with too much information.&lt;/p&gt;
&lt;p&gt;When communicating to mathematicians, focus more on the ideas than on the details you would provide for your peers. You can easily underestimate how difficult your own field is for outsiders. For instance, the experimental methods can be left out, as mathematicians will just assume that the data has been properly collected.&lt;/p&gt;
&lt;p&gt;Try also to think in terms of inputs, processes, and outputs. This exercise is not only good for interdisciplinary communication, but also for experimental design and even for structuring a report.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for mathematicians working with biologists&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_8cgevQhUCpP9y59N-5a490c31.BRX8XfLU_Z28lOn2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Benjamin Lizardo on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;make-peace-with-uncertainty&quot;&gt;Make peace with uncertainty&lt;/h3&gt;
&lt;p&gt;Due to the complexity of the subject of study, it is unrealistic to expect the same precision from biological models as from physical ones. Forget all you learned in math/physics/engineering school about discarding any result with an &lt;em&gt;r&lt;/em&gt; 2 below 0.99. You are working with biological and, thus, complex systems now. Models just do as well as possible. Additionally, you’ll have to embrace the fact that most of these models rarely allow an elegant, analytical approach, and numerical methods will be required most of the time.&lt;/p&gt;
&lt;h3 id=&quot;explain-why-you-do-what-you-do&quot;&gt;Explain why you do what you do&lt;/h3&gt;
&lt;p&gt;When explaining a mathematical method, instead of starting with generic propositions and formal proofs, always explain why it is useful using simple examples. Biologists may quickly lose motivation if they are not convinced that the mathematics used is somehow useful.&lt;/p&gt;
&lt;p&gt;A particularly illuminating experience happened to me while teaching &lt;a href=&quot;https://en.wikipedia.org/wiki/Matrix_multiplication&quot;&gt;matrix multiplication&lt;/a&gt; to a group of biology students. The topic is particularly boring and most often is just presented as a rule. In this case, I proceeded differently: I first let the students experience the &lt;em&gt;need&lt;/em&gt; for a compact notation (by making them write down, line by line, increasingly larger competition models), and later I explained why the rule of matrix notation is what it is and how it solves their need.&lt;/p&gt;
&lt;p&gt;Presented this way, the students notice that the mathematical tool is solving a problem they already have, instead of feeling that it creates a new one (that of having to learn how to use a new tool). Additionally, the explanations about why the rule is how it is, help them learn and remember it.&lt;/p&gt;
&lt;h3 id=&quot;proofs-are-scary&quot;&gt;Proofs are scary&lt;/h3&gt;
&lt;p&gt;Maybe you think mathematical proofs &lt;em&gt;shouldn’t&lt;/em&gt; be scary, but the fact is that for many biologists they are. A mathematical proof is somehow a journey, a journey from a set of assumptions to a conclusion, and your collaborators should enjoy the ride too.&lt;/p&gt;
&lt;p&gt;Often, proofs can be substituted by a graphical or intuitive approach. This substitution may come with some simplification when affordable, but often can be done without loss. Euclid’s “Elements”, probably the most influential mathematical book ever written, contains mostly visual proofs. More modern examples can be found in the collection “Proofs without words”.&lt;/p&gt;
&lt;p&gt;If mathematical proof is really needed, make an effort in explaining the notation and all the steps. The quickest way of creating frustration in your audience is by using the word &lt;em&gt;trivial&lt;/em&gt;, so avoid it always. When writing publications in non-mathematical journals, it is usually a good idea to write the proofs in an appendix and just state the results as a fact in the main body. Just like mathematicians feel they cannot judge experimental methods, most biologists will assume proofs are correct.&lt;/p&gt;
&lt;h3 id=&quot;invest-in-software-engineering-techniques&quot;&gt;Invest in software engineering techniques&lt;/h3&gt;
&lt;p&gt;Very often, your collaborators will ask you to provide a tool for, say, simulating a biological system or performing a statistical calculation. Encapsulating such a tool in usable and robust pieces of software could be a very good idea. Getting introduced to the world of software engineering can be very helpful in this regard. For a brilliant, quick introduction, see &lt;a href=&quot;https://doi.org/10.1371/journal.pbio.1001745&quot;&gt;Best practices for Scientific Computing, Wilson et al., PLOS Biology, 2014&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;use-as-much-visualization-as-possible&quot;&gt;Use as much visualization as possible&lt;/h3&gt;
&lt;p&gt;Take advantage of humans’ most advanced information acquisition system: vision. Illustrate your ideas with graphs and figures, or even movies and animations when applicable. If they are good, they can even replace an equation.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for both&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_dAPLLYwIVvS6lIZh-2a42204c.uq9YxrzM_Z1e6Y6v.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Gift Habeshaw on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;get-involved-in-science-communication&quot;&gt;Get involved in science communication&lt;/h3&gt;
&lt;p&gt;If you think interdisciplinary communication is hard, just try to communicate science to the general public. Not only will you notice that science communication is even harder, but also you will learn a lot about how to improve your overall communication skills.&lt;/p&gt;
&lt;p&gt;Nowadays there are lots of ways of getting involved with this activity (from writing a blog to giving a talk at an event). The practice of science communication forces a deep understanding of the topic being communicated. It requires removing the unnecessary, identifying what is hard and why and advancing the audience’s questions and doubts. It requires, in one word, understanding.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This text is adapted from the author’s doctoral thesis,&lt;/em&gt; &lt;a href=&quot;https://research.wur.nl/en/publications/cycles-and-interactions-a-mathematician-among-biologists&quot;&gt;&lt;em&gt;Cycles and interactions: A mathematician among biologists&lt;/em&gt;&lt;/a&gt;, section 5.4*. An earlier version of it was also published in* &lt;a href=&quot;https://mappingignorance.org/2020/11/09/how-can-we-improve-the-communication-between-mathematics-and-life-sciences/&quot;&gt;&lt;em&gt;Mapping Ignorance&lt;/em&gt;&lt;/a&gt;, &lt;em&gt;and a Spanish translation in&lt;/em&gt; &lt;a href=&quot;https://culturacientifica.com/2020/11/02/como-mejorar-la-comunicacion-entre-las-matematicas-y-las-ciencias-de-la-vida/&quot;&gt;&lt;em&gt;Cátedra de Cultura Científica&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Wed, 12 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Lessons learned, from a mathematician among biologists.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_5FbzBhG-vIYMnJkE-fedba0ed.Ddq9Kv1a_14WKMi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by ThisisEngineering RAEng on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;preamble&quot;&gt;Preamble&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;In the period 2015–2019, I was hired as a mathematician by a biology department in order to work on a research line that eventually would become my doctoral thesis. This text is adapted from the last chapter of that thesis, “Cycles and interactions: A mathematician among biologists” (full text available&lt;/em&gt; &lt;a href=&quot;https://doi.org/10.18174/520571&quot;&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The symbiosis between mathematics and biology, although may seem improbable at first sight, is actually backed by a centuries-old tradition of collaboration. It started with mathematicians that were inspired by biology such as Leonardo Pisano, alias Fibonacci. His famous sequence (namely: 1, 1, 2, 3, 5, 8, 13, …, where each element is the sum of the two previous ones), a landmark in number theory very popular among amateur mathematicians, was first described in the context of a practical problem on rabbit breeding in such an early date as the year 1202.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mathematical knowledge has improved greatly since the 13th century. The foundations of the tools used by modern mathematical biologists, namely, calculus and differential equations, were laid in the late 17th century by Isaac Newton and Gottfried Leibniz motivated by mechanical problems. The great mathematician Leonhard Euler and the economist and demographer Thomas R. Malthus, two of the pioneers of using differential equations to address biological problems, had both printed their seminal works in population dynamics before the fall of the year 1800.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This interdisciplinary collaboration between mathematics and biology is nowadays alive and in good shape. Some of the most influential names in ecology in the 20th and 21st centuries have, indeed, a background in mathematics (such as Robert MacArthur, Simon Levin, or Alan Hastings) or in physics (such as Robert May).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The opportunity offered by cheap access to computing power, together with the unavoidable increase of required technical skills such as programming, data analysis, and advanced statistical methods, points to a future where the technical profiles expected from a research team in biology will not be so different to those of a team of physicists or applied mathematicians. It is reasonable to expect that this symbiosis between mathematicians and biologists will remain strong, and even get stronger, in the near future.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I hereby offer some advice for both biologists and mathematicians (understood here as mathematically oriented professionals, including physicists and engineers) interested in exploring “the other side”. It contains the kind of advice I would have liked to have had in 2015, when I approached, naively as only a physicist can do, the world of biology.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Mathematics is often perceived as a harsh subject both by scientific and non-scientific professionals. Despite those preferences and prejudices, mathematics is used in almost every field of knowledge and are a must-have in any multidisciplinary project.&lt;/p&gt;
&lt;p&gt;Different disciplines have associated not only a set of background knowledge and methods but a whole academic culture. When crossing the borders between disciplines, facts and methods can be learned, but accepting and adapting to another culture is much harder.&lt;/p&gt;
&lt;p&gt;As with any other culture, mathematicians and biologists differ slightly in language, values, norms, and interests. As usually happens in intercultural communication, there is plenty of opportunity for misunderstandings, and each subgroup cultivates myths and misconceptions about the other.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for biologists working with mathematicians&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;943&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_DXaLJZXNaU0oSjxf-c6daa72d.T7wbfhiD_19RaEE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by NOAA on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;invest-in-applied-mathematics&quot;&gt;Invest in applied mathematics&lt;/h3&gt;
&lt;p&gt;Applied mathematics doesn’t mean easy mathematics. The adjective “applied” or “pure”, accompanying the word “mathematics”, tells us something about the object under study, but nothing about its difficulty. Indeed, the mathematical tool will be as complex as the object under study is.&lt;/p&gt;
&lt;p&gt;It may be frustrating to learn that, for instance, it is required to get familiar with second-order tensors (a particularly hard tool rooted in differential geometry) in order to understand fluid dynamics. Mathematicians don’t introduce this tool to torture the newcomers, but because tensors are the easiest available tool to study a complex phenomenon that cannot be avoided in the study of fluids: deformation.&lt;/p&gt;
&lt;p&gt;The difficulty is provided by the problem under study, not by the tool used to solve it.&lt;/p&gt;
&lt;h3 id=&quot;equations-and-rigor-are-not-torture-instruments&quot;&gt;Equations and rigor are not torture instruments&lt;/h3&gt;
&lt;p&gt;It is known that the mere sight of an equation can create anxiety. Even the physicist Stephen Hawking, in the preface of his best-seller “A brief history of time”, claims that each printed equation divides the potential audience by two.&lt;/p&gt;
&lt;p&gt;Whether we like them or not, equations are often the best way to share complex information in a compact and practical manner. Invest time in learning how to read them. Rigorous and detailed analyses are often required, as some details can escape intuition.&lt;/p&gt;
&lt;p&gt;Be also aware that the same equation can be written in different ways. Even if different ways of writing the same equation are correct, some of them can be clearer than others. Consistent use of upper and lower case (for instance, upper for states, lower for parameters), superscript and subscript, smart use of auxiliary definitions, proper alignment of related equations and other simple rules can significantly increase the readability of your scientific output.&lt;/p&gt;
&lt;h3 id=&quot;modeling-is-all-about-simplifying&quot;&gt;Modeling is all about simplifying&lt;/h3&gt;
&lt;p&gt;Be prepared that the main task of modeling is simplifying. This is the main challenge as here both an understanding of the system and of modeling techniques are required. In the design phase of a model, lots of exchange is needed between the biologists and the mathematicians. This may come as a surprise, but most mathematicians feel overwhelmed by biologists’ talk. Biologists tend to provide them with too much information.&lt;/p&gt;
&lt;p&gt;When communicating to mathematicians, focus more on the ideas than on the details you would provide for your peers. You can easily underestimate how difficult your own field is for outsiders. For instance, the experimental methods can be left out, as mathematicians will just assume that the data has been properly collected.&lt;/p&gt;
&lt;p&gt;Try also to think in terms of inputs, processes, and outputs. This exercise is not only good for interdisciplinary communication, but also for experimental design and even for structuring a report.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for mathematicians working with biologists&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_8cgevQhUCpP9y59N-5a490c31.BRX8XfLU_Z28lOn2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Benjamin Lizardo on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;make-peace-with-uncertainty&quot;&gt;Make peace with uncertainty&lt;/h3&gt;
&lt;p&gt;Due to the complexity of the subject of study, it is unrealistic to expect the same precision from biological models as from physical ones. Forget all you learned in math/physics/engineering school about discarding any result with an &lt;em&gt;r&lt;/em&gt; 2 below 0.99. You are working with biological and, thus, complex systems now. Models just do as well as possible. Additionally, you’ll have to embrace the fact that most of these models rarely allow an elegant, analytical approach, and numerical methods will be required most of the time.&lt;/p&gt;
&lt;h3 id=&quot;explain-why-you-do-what-you-do&quot;&gt;Explain why you do what you do&lt;/h3&gt;
&lt;p&gt;When explaining a mathematical method, instead of starting with generic propositions and formal proofs, always explain why it is useful using simple examples. Biologists may quickly lose motivation if they are not convinced that the mathematics used is somehow useful.&lt;/p&gt;
&lt;p&gt;A particularly illuminating experience happened to me while teaching &lt;a href=&quot;https://en.wikipedia.org/wiki/Matrix_multiplication&quot;&gt;matrix multiplication&lt;/a&gt; to a group of biology students. The topic is particularly boring and most often is just presented as a rule. In this case, I proceeded differently: I first let the students experience the &lt;em&gt;need&lt;/em&gt; for a compact notation (by making them write down, line by line, increasingly larger competition models), and later I explained why the rule of matrix notation is what it is and how it solves their need.&lt;/p&gt;
&lt;p&gt;Presented this way, the students notice that the mathematical tool is solving a problem they already have, instead of feeling that it creates a new one (that of having to learn how to use a new tool). Additionally, the explanations about why the rule is how it is, help them learn and remember it.&lt;/p&gt;
&lt;h3 id=&quot;proofs-are-scary&quot;&gt;Proofs are scary&lt;/h3&gt;
&lt;p&gt;Maybe you think mathematical proofs &lt;em&gt;shouldn’t&lt;/em&gt; be scary, but the fact is that for many biologists they are. A mathematical proof is somehow a journey, a journey from a set of assumptions to a conclusion, and your collaborators should enjoy the ride too.&lt;/p&gt;
&lt;p&gt;Often, proofs can be substituted by a graphical or intuitive approach. This substitution may come with some simplification when affordable, but often can be done without loss. Euclid’s “Elements”, probably the most influential mathematical book ever written, contains mostly visual proofs. More modern examples can be found in the collection “Proofs without words”.&lt;/p&gt;
&lt;p&gt;If mathematical proof is really needed, make an effort in explaining the notation and all the steps. The quickest way of creating frustration in your audience is by using the word &lt;em&gt;trivial&lt;/em&gt;, so avoid it always. When writing publications in non-mathematical journals, it is usually a good idea to write the proofs in an appendix and just state the results as a fact in the main body. Just like mathematicians feel they cannot judge experimental methods, most biologists will assume proofs are correct.&lt;/p&gt;
&lt;h3 id=&quot;invest-in-software-engineering-techniques&quot;&gt;Invest in software engineering techniques&lt;/h3&gt;
&lt;p&gt;Very often, your collaborators will ask you to provide a tool for, say, simulating a biological system or performing a statistical calculation. Encapsulating such a tool in usable and robust pieces of software could be a very good idea. Getting introduced to the world of software engineering can be very helpful in this regard. For a brilliant, quick introduction, see &lt;a href=&quot;https://doi.org/10.1371/journal.pbio.1001745&quot;&gt;Best practices for Scientific Computing, Wilson et al., PLOS Biology, 2014&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;use-as-much-visualization-as-possible&quot;&gt;Use as much visualization as possible&lt;/h3&gt;
&lt;p&gt;Take advantage of humans’ most advanced information acquisition system: vision. Illustrate your ideas with graphs and figures, or even movies and animations when applicable. If they are good, they can even replace an equation.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Advice for both&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_dAPLLYwIVvS6lIZh-2a42204c.uq9YxrzM_Z1e6Y6v.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Gift Habeshaw on Unsplash&lt;/p&gt;
&lt;h3 id=&quot;get-involved-in-science-communication&quot;&gt;Get involved in science communication&lt;/h3&gt;
&lt;p&gt;If you think interdisciplinary communication is hard, just try to communicate science to the general public. Not only will you notice that science communication is even harder, but also you will learn a lot about how to improve your overall communication skills.&lt;/p&gt;
&lt;p&gt;Nowadays there are lots of ways of getting involved with this activity (from writing a blog to giving a talk at an event). The practice of science communication forces a deep understanding of the topic being communicated. It requires removing the unnecessary, identifying what is hard and why and advancing the audience’s questions and doubts. It requires, in one word, understanding.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This text is adapted from the author’s doctoral thesis,&lt;/em&gt; &lt;a href=&quot;https://research.wur.nl/en/publications/cycles-and-interactions-a-mathematician-among-biologists&quot;&gt;&lt;em&gt;Cycles and interactions: A mathematician among biologists&lt;/em&gt;&lt;/a&gt;, section 5.4*. An earlier version of it was also published in* &lt;a href=&quot;https://mappingignorance.org/2020/11/09/how-can-we-improve-the-communication-between-mathematics-and-life-sciences/&quot;&gt;&lt;em&gt;Mapping Ignorance&lt;/em&gt;&lt;/a&gt;, &lt;em&gt;and a Spanish translation in&lt;/em&gt; &lt;a href=&quot;https://culturacientifica.com/2020/11/02/como-mejorar-la-comunicacion-entre-las-matematicas-y-las-ciencias-de-la-vida/&quot;&gt;&lt;em&gt;Cátedra de Cultura Científica&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_DXaLJZXNaU0oSjxf-c6daa72d.T7wbfhiD.webp" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Fun with elevators: a tutorial</title><link>https://blog.esciencecenter.nl/posts/2022-09-08---fun-with-elevators-a-tutorial</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-09-08---fun-with-elevators-a-tutorial</guid><description>&lt;p&gt;&lt;em&gt;Most modern cell phones contain an accelerometer. And that’s good news if you are curious about all the data around you&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4ofm5alj_exWfow5-fe38d09c.DDe4Xmw4_1OjHJe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Waldemar Brandt on Unsplash&lt;/p&gt;
&lt;p&gt;Some years ago I did a secondment at the Friedrich Schiller University, in Jena, Germany. To my surprise, my office during those months was located on the 18th floor of a skyscraper, the Jentower:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;360&quot; height=&quot;640&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4Afjsusuv4SsR3XK-958db2fb.DtRZ-AGD_Z10LCp5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Jentower&lt;/p&gt;
&lt;p&gt;But I’m not writing this to boast about the amazing views of my old office. On the contrary, I’ll destroy any possible idea of glamour related to working in a place like this. And I’ll do it with a confession: I became known as the crazy guy who leaves his cell phone on the ground while he uses the elevator. Let me explain why:&lt;/p&gt;
&lt;p&gt;A building almost 150 meters high needs fast elevators. The ones in this building have a very powerful, almost scary acceleration. Then, I remembered that smartphones usually contain an accelerometer, so I tried to measure those accelerations.&lt;/p&gt;
&lt;p&gt;There are many apps that allow registering data from all sensors available on the phone (accelerometers, light, magnetic field, …) and exporting them in an easy format (such as.csv) quite easy to analyze on a computer. If you like getting your hands dirty, give it a try!&lt;/p&gt;
&lt;p&gt;In the figure below we can see the vertical acceleration profile during my trip to the 18th floor one morning, where we can clearly see the initial “kick” (seconds 9 to 14) and the braking (28 to 33).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;682&quot; height=&quot;499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_DBRj0N55eBOLr3_TCJ7teQ-7e24e80f.CSLkWZR2_1iQRqQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Vertical acceleration vs Time (gravity has been excluded)&lt;/p&gt;
&lt;p&gt;Accelerations of 1 m/s² sustained during 4 seconds! Think that, the usual acceleration your body experiments due to gravity is around 9.8 m/s² so, while the elevator goes up, your weight gets increased by around 10%. You can feel that in your stomach!&lt;/p&gt;
&lt;p&gt;We can explore this data a bit further. We can, for instance, use the acceleration time series to compute speed and position. How? Maybe you remember from high school physics that position (x), velocity (v), and acceleration (a) are related through derivatives. More specifically.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;274&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_f6vwlMWN8bQjL9PG-65776d07.D5xf5yLY_28iG6w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;With the previous recipe, we can compute speed using the position, and then use speed to compute acceleration. One after the other, like in a production chain. Nevertheless, in our case, we want to do the opposite process. Luckily, we can use integrals to “revert” our derivatives, and thus our whole “production chain” looks now:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;350&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4qUNhJ4PInVFgVv3-6a15e322.C_UjXeLD_8xfqq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;So, by integrating the acceleration (to obtain the speed), and then integrating the speed (to obtain the position) we find results like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;678&quot; height=&quot;499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iK8mx2VNGsoUgCzh13hV3Q-f0f16665.BzFpdex5_pOoR6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Acceleration, speed, and position against time.&lt;/p&gt;
&lt;p&gt;So, using only a device that most of us carry everywhere and some elementary physical concepts we know that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our elevator runs up at 4 m/s.&lt;/li&gt;
&lt;li&gt;My office was 74 meters above the ground.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If someone is interested in exploring a bit deeper into the details (for instance: how to filter out the effects of gravity, how to integrate a time series, …) or even experimenting with their own elevator, &lt;a href=&quot;https://github.com/PabRod/elevator-tool&quot;&gt;here is a link&lt;/a&gt; to the code I’ve used.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This text appeared first in&lt;/em&gt; &lt;a href=&quot;http://fuga.naukas.com/2018/02/06/un-empollon-en-mi-ascensor/&quot;&gt;&lt;em&gt;Naukas&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, where it was originally written in Spanish.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 08 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Most modern cell phones contain an accelerometer. And that’s good news if you are curious about all the data around you&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4ofm5alj_exWfow5-fe38d09c.DDe4Xmw4_1OjHJe.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Waldemar Brandt on Unsplash&lt;/p&gt;
&lt;p&gt;Some years ago I did a secondment at the Friedrich Schiller University, in Jena, Germany. To my surprise, my office during those months was located on the 18th floor of a skyscraper, the Jentower:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;360&quot; height=&quot;640&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4Afjsusuv4SsR3XK-958db2fb.DtRZ-AGD_Z10LCp5.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Jentower&lt;/p&gt;
&lt;p&gt;But I’m not writing this to boast about the amazing views of my old office. On the contrary, I’ll destroy any possible idea of glamour related to working in a place like this. And I’ll do it with a confession: I became known as the crazy guy who leaves his cell phone on the ground while he uses the elevator. Let me explain why:&lt;/p&gt;
&lt;p&gt;A building almost 150 meters high needs fast elevators. The ones in this building have a very powerful, almost scary acceleration. Then, I remembered that smartphones usually contain an accelerometer, so I tried to measure those accelerations.&lt;/p&gt;
&lt;p&gt;There are many apps that allow registering data from all sensors available on the phone (accelerometers, light, magnetic field, …) and exporting them in an easy format (such as.csv) quite easy to analyze on a computer. If you like getting your hands dirty, give it a try!&lt;/p&gt;
&lt;p&gt;In the figure below we can see the vertical acceleration profile during my trip to the 18th floor one morning, where we can clearly see the initial “kick” (seconds 9 to 14) and the braking (28 to 33).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;682&quot; height=&quot;499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_DBRj0N55eBOLr3_TCJ7teQ-7e24e80f.CSLkWZR2_1iQRqQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Vertical acceleration vs Time (gravity has been excluded)&lt;/p&gt;
&lt;p&gt;Accelerations of 1 m/s² sustained during 4 seconds! Think that, the usual acceleration your body experiments due to gravity is around 9.8 m/s² so, while the elevator goes up, your weight gets increased by around 10%. You can feel that in your stomach!&lt;/p&gt;
&lt;p&gt;We can explore this data a bit further. We can, for instance, use the acceleration time series to compute speed and position. How? Maybe you remember from high school physics that position (x), velocity (v), and acceleration (a) are related through derivatives. More specifically.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;274&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_f6vwlMWN8bQjL9PG-65776d07.D5xf5yLY_28iG6w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;With the previous recipe, we can compute speed using the position, and then use speed to compute acceleration. One after the other, like in a production chain. Nevertheless, in our case, we want to do the opposite process. Luckily, we can use integrals to “revert” our derivatives, and thus our whole “production chain” looks now:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;350&quot; height=&quot;179&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_4qUNhJ4PInVFgVv3-6a15e322.C_UjXeLD_8xfqq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;So, by integrating the acceleration (to obtain the speed), and then integrating the speed (to obtain the position) we find results like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;678&quot; height=&quot;499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iK8mx2VNGsoUgCzh13hV3Q-f0f16665.BzFpdex5_pOoR6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Acceleration, speed, and position against time.&lt;/p&gt;
&lt;p&gt;So, using only a device that most of us carry everywhere and some elementary physical concepts we know that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our elevator runs up at 4 m/s.&lt;/li&gt;
&lt;li&gt;My office was 74 meters above the ground.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If someone is interested in exploring a bit deeper into the details (for instance: how to filter out the effects of gravity, how to integrate a time series, …) or even experimenting with their own elevator, &lt;a href=&quot;https://github.com/PabRod/elevator-tool&quot;&gt;here is a link&lt;/a&gt; to the code I’ve used.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This text appeared first in&lt;/em&gt; &lt;a href=&quot;http://fuga.naukas.com/2018/02/06/un-empollon-en-mi-ascensor/&quot;&gt;&lt;em&gt;Naukas&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, where it was originally written in Spanish.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_4Afjsusuv4SsR3XK-958db2fb.DtRZ-AGD.jpg" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Our favourite high performance programming tools</title><link>https://blog.esciencecenter.nl/posts/2022-08-16---our-favourite-high-performance-programming-tools</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-08-16---our-favourite-high-performance-programming-tools</guid><description>&lt;p&gt;Does your code need a performance boost? Ask us!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3648&quot; height=&quot;2736&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_jZCwr0Tj0c5eMqey-57034bb6.CeBmoS6M_1iF5II.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Alenka Skvarc on Unsplash&lt;/p&gt;
&lt;p&gt;We hope you are relaxed and enjoying your holiday period. We really do. So it may seem ironic that this blog post is about being in a hurry. Kind of. Let me explain myself:&lt;/p&gt;
&lt;p&gt;Apart from the kind of hurry you may experience when you are afraid of missing a train, or the oppressive feeling of fearing not meeting a deadline, we are very familiar with another type of hurry: the one caused by slow code.&lt;/p&gt;
&lt;p&gt;Did you experience this? We certainly do. And our engineers proposed some solutions too. Using more efficient programming languages, or letting your graphical processing unit (GPU) do the hard work, are classical solutions for these problems.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/writing-testable-gpu-code-23bbda3a5d62&quot;&gt;&lt;strong&gt;Writing testable GPU code&lt;/strong&gt;&lt;/a&gt;, by &lt;a href=&quot;https://medium.com/@benvanwerkhoven&quot;&gt;Ben van Werkhoven&lt;/a&gt;, reminds us that using GPU programming is no excuse for abandoning best practices. In particular, it is very advisable to use unit tests. Here he teaches us how.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/c-compile-time-exceptions-5443f5bf06fe&quot;&gt;&lt;strong&gt;C++ Compile-Time exceptions&lt;/strong&gt;&lt;/a&gt;, by &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, sheds some light on the notoriously obscure topic of templates in C++ and their cryptic error messages. Couldn’t these messages be more readable? Patrick says yes, and shows us how.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/why-use-an-fpga-instead-of-a-cpu-or-gpu-b234cd4f309c&quot;&gt;&lt;strong&gt;Why use an FPGA instead of a CPU or GPU?&lt;/strong&gt;&lt;/a&gt;, by our former colleague &lt;a href=&quot;https://medium.com/@atzeus&quot;&gt;Atze van der Ploeg&lt;/a&gt;, delves into something some of us software engineers tend to forget: the hardware side of things.&lt;/p&gt;
&lt;p&gt;What about you? Do you have something to share? If that’s the case, feel free to use the comments section below. But, if you want to enjoy a hurry-less summer, feel more than free to wait until September.&lt;/p&gt;</description><pubDate>Tue, 16 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Does your code need a performance boost? Ask us!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3648&quot; height=&quot;2736&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_jZCwr0Tj0c5eMqey-57034bb6.CeBmoS6M_1iF5II.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Alenka Skvarc on Unsplash&lt;/p&gt;
&lt;p&gt;We hope you are relaxed and enjoying your holiday period. We really do. So it may seem ironic that this blog post is about being in a hurry. Kind of. Let me explain myself:&lt;/p&gt;
&lt;p&gt;Apart from the kind of hurry you may experience when you are afraid of missing a train, or the oppressive feeling of fearing not meeting a deadline, we are very familiar with another type of hurry: the one caused by slow code.&lt;/p&gt;
&lt;p&gt;Did you experience this? We certainly do. And our engineers proposed some solutions too. Using more efficient programming languages, or letting your graphical processing unit (GPU) do the hard work, are classical solutions for these problems.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/writing-testable-gpu-code-23bbda3a5d62&quot;&gt;&lt;strong&gt;Writing testable GPU code&lt;/strong&gt;&lt;/a&gt;, by &lt;a href=&quot;https://medium.com/@benvanwerkhoven&quot;&gt;Ben van Werkhoven&lt;/a&gt;, reminds us that using GPU programming is no excuse for abandoning best practices. In particular, it is very advisable to use unit tests. Here he teaches us how.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/c-compile-time-exceptions-5443f5bf06fe&quot;&gt;&lt;strong&gt;C++ Compile-Time exceptions&lt;/strong&gt;&lt;/a&gt;, by &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, sheds some light on the notoriously obscure topic of templates in C++ and their cryptic error messages. Couldn’t these messages be more readable? Patrick says yes, and shows us how.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/why-use-an-fpga-instead-of-a-cpu-or-gpu-b234cd4f309c&quot;&gt;&lt;strong&gt;Why use an FPGA instead of a CPU or GPU?&lt;/strong&gt;&lt;/a&gt;, by our former colleague &lt;a href=&quot;https://medium.com/@atzeus&quot;&gt;Atze van der Ploeg&lt;/a&gt;, delves into something some of us software engineers tend to forget: the hardware side of things.&lt;/p&gt;
&lt;p&gt;What about you? Do you have something to share? If that’s the case, feel free to use the comments section below. But, if you want to enjoy a hurry-less summer, feel more than free to wait until September.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_jZCwr0Tj0c5eMqey-57034bb6.CeBmoS6M.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>Our favourite Python tools for research</title><link>https://blog.esciencecenter.nl/posts/2022-08-02---our-favourite-python-tools-for-research</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-08-02---our-favourite-python-tools-for-research</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_YDHFYKPphLmLq5Fz-9e75541a.DWQzJMUX_1zFoKJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Ethan Robertson on Unsplash&lt;/p&gt;
&lt;p&gt;Ah, summer. A time to relax, go on holiday, and learn new things. At the eScience Center, we love summer. And we love Python. So, for summer, we’ve put together our most popular blogs on favourite Python tools that our (former) engineers either worked on, or use a lot. We hope you enjoy this curated list!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/jump-start-your-python-project-with-this-template-ef52e6c1a2dc&quot;&gt;&lt;strong&gt;Jump start your Python project with this template&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@j.vanderzwaan&quot;&gt;Janneke van der Zwaan&lt;/a&gt;, talks about the Python project template developed at the eScience Center. This template helps beginners to get started, and advanced Python users to save time. And who doesn’t love saving time?!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/parallel-programming-in-python-7fd62c90217d&quot;&gt;&lt;strong&gt;Parallel programming in Python&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@jhidding&quot;&gt;Johan Hidding&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;. Have you ever been in a hurry to complete an analysis, but did it take very long to run? In this step-by-step tutorial Johan and Pablo show you how to call in all of your processors for help.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/forget-about-jupyter-notebooks-showcase-your-research-using-dashboards-5d13451ba374&quot;&gt;&lt;strong&gt;Forget about Jupyter Notebooks — showcase your research using Dashboards&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@stefsmeets&quot;&gt;Stef Smeets&lt;/a&gt;. The title says it all — if you’re looking for a different and interesting way to present your research, consider using dashboards. You’ll find it surprisingly easy with Stef’s tutorial.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;&lt;strong&gt;Loading irregular data into Pandas using C++&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;. Who doesn’t love Pandas? Well, quite a few people, because it loads data slowly. But you can make it faster! Check out how in this post.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/testing-shell-commands-from-python-2a2ec87ebf71&quot;&gt;&lt;strong&gt;Testing shell commands from Python&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@j.vanderzwaan&quot;&gt;Janneke van der Zwaan&lt;/a&gt;. Do you ever need to test shell commands, but find it fiddly and annoying? Janneke found a solution in Python that works well, maybe it works well for you too!&lt;/p&gt;
&lt;p&gt;And what about you? What’s your favourite Python tool? Let us know in the comments below and, most importantly, enjoy your summer.&lt;/p&gt;</description><pubDate>Tue, 02 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_YDHFYKPphLmLq5Fz-9e75541a.DWQzJMUX_1zFoKJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Ethan Robertson on Unsplash&lt;/p&gt;
&lt;p&gt;Ah, summer. A time to relax, go on holiday, and learn new things. At the eScience Center, we love summer. And we love Python. So, for summer, we’ve put together our most popular blogs on favourite Python tools that our (former) engineers either worked on, or use a lot. We hope you enjoy this curated list!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/jump-start-your-python-project-with-this-template-ef52e6c1a2dc&quot;&gt;&lt;strong&gt;Jump start your Python project with this template&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@j.vanderzwaan&quot;&gt;Janneke van der Zwaan&lt;/a&gt;, talks about the Python project template developed at the eScience Center. This template helps beginners to get started, and advanced Python users to save time. And who doesn’t love saving time?!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/parallel-programming-in-python-7fd62c90217d&quot;&gt;&lt;strong&gt;Parallel programming in Python&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@jhidding&quot;&gt;Johan Hidding&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;. Have you ever been in a hurry to complete an analysis, but did it take very long to run? In this step-by-step tutorial Johan and Pablo show you how to call in all of your processors for help.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/forget-about-jupyter-notebooks-showcase-your-research-using-dashboards-5d13451ba374&quot;&gt;&lt;strong&gt;Forget about Jupyter Notebooks — showcase your research using Dashboards&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@stefsmeets&quot;&gt;Stef Smeets&lt;/a&gt;. The title says it all — if you’re looking for a different and interesting way to present your research, consider using dashboards. You’ll find it surprisingly easy with Stef’s tutorial.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;&lt;strong&gt;Loading irregular data into Pandas using C++&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;. Who doesn’t love Pandas? Well, quite a few people, because it loads data slowly. But you can make it faster! Check out how in this post.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.esciencecenter.nl/testing-shell-commands-from-python-2a2ec87ebf71&quot;&gt;&lt;strong&gt;Testing shell commands from Python&lt;/strong&gt;&lt;/a&gt; by &lt;a href=&quot;https://medium.com/@j.vanderzwaan&quot;&gt;Janneke van der Zwaan&lt;/a&gt;. Do you ever need to test shell commands, but find it fiddly and annoying? Janneke found a solution in Python that works well, maybe it works well for you too!&lt;/p&gt;
&lt;p&gt;And what about you? What’s your favourite Python tool? Let us know in the comments below and, most importantly, enjoy your summer.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_YDHFYKPphLmLq5Fz-9e75541a.DWQzJMUX.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>Mimicking Intelligence: AI imitation crisis</title><link>https://blog.esciencecenter.nl/posts/2022-07-22---mimicking-intelligence-ai-imitation-crisis</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-07-22---mimicking-intelligence-ai-imitation-crisis</guid><description>&lt;h2 id=&quot;the-next-generation-language-models-will-still-just-be-enormeous-parrot-systems-that-imitate-intelligent-behavior-but-they-will-feel-like-much-more-to-us&quot;&gt;The next generation language models will still just be enormeous parrot-systems that imitate intelligent behavior. But they will &lt;em&gt;feel&lt;/em&gt; like much more to us.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Jun 24, 2022&lt;/p&gt;
&lt;p&gt;Philosophically and legally they will remain things. But at some point in the not too far future many people will simply not perceive them as things anymore**. People might make “friends” with an AI (just as Blake Lemoine said he did, at least if we assume this is not all a big media stunt). People might listen to “their AI”. And many people will be tricked by an AI.&lt;/p&gt;
&lt;h3 id=&quot;shifting-societal-rules-and-foundations&quot;&gt;Shifting societal rules and foundations&lt;/h3&gt;
&lt;p&gt;Having emotional bonds to things is nothing new. People are tied to an old stuffed animal, to a toy, to things that carry important memories. Next generation language models are very unlike those things. They can “talk” to you, they can have an “opinion” that is radically different from yours. And, not to forget, they are designed, trained, and controlled by powerfull companies (now) or by any group with the necessary technical skills and requirements (but generally not by you).&lt;/p&gt;
&lt;p&gt;Plus, they can come in disguise. If you talk to your old teddy bear than at least you know (I hope) that you are just talking to an imaginary being. But next level chat bots might run undercover. Either actualy pretending to be a human being (which even for the big tech companies should be a total no-go), or by pretending to be more than a thing, but to be actually alive (that’s what LaMDA seems to do).&lt;/p&gt;
&lt;p&gt;In the last decade we have experienced how digital technologies can be used for good and for bad. We have seen how technologies can be used to connect and to help people, but also to manipulate. Manipulation of media is nothing new, but the level to which media can be generated and manipulated has changed very rapidly. To make it a bit drastic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can (soon?) no longer trust images, be it generated faces or deep learning generated artworks (see &lt;a href=&quot;https://openai.com/dall-e-2/&quot;&gt;Dall-e&lt;/a&gt; or &lt;a href=&quot;https://parti.research.google/&quot;&gt;parti&lt;/a&gt; for recent, very impressive examples)&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust audio because models can transfer the sound of any person (given enough material).&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust video footage (deep fakes, see &lt;a href=&quot;https://www.niemanlab.org/2018/12/fighting-the-reality-of-deepfakes/&quot;&gt;for instance here&lt;/a&gt; or &lt;a href=&quot;https://medium.com/@gxrdwtsv/are-we-living-in-a-post-truth-world-c6e0820e656d&quot;&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;And as I wrote above: We can (soon?) no longer trust chat conversations (see LaMDA).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, all of those things bring a lot of fun use cases, sometimes even really usefull ones. But there might be a very high price to pay for this.&lt;/p&gt;
&lt;p&gt;It probably still takes a while before experts with a deeper (haha, great pun) understanding of deep learning will be fully tricked by the imitation game. But at least in a normal chat situation most people will not easily realize they are talking to a “language model”. People like Blake Lemoine for instance. And many others will follow his example, not in the same religious way, but they will simply not notice that the online sales person or the online booking assistant is no longer a human being.&lt;/p&gt;
&lt;p&gt;Do you still wonder why this is an issue? &lt;strong&gt;Better a nice chat bot than a stupid one, right?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, then imagine you landed on a scam dating site.
Or start to imagine what people could do which hacked devices of friends or family.
Obviously those AI’s can write you better scam attempts that what we are currently used to (current level: “Hi mother, it’s your son and I need money”*). And hey, what if they also call you and sound like the real person?&lt;/p&gt;
&lt;p&gt;I bet most people are not yet used to asking control questions during phone calls. Like: what drink did we have last week in the bar? What was the name of my first cat? Have to talked to Anthony recently? (I don’t know any Anthony)&lt;/p&gt;
&lt;p&gt;Sounds silly I know. But maybe we soon have to start practicing…&lt;/p&gt;
&lt;h3 id=&quot;further-references&quot;&gt;Further references:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you haven’t done this already I can recommend to “talk to an AI” just to see and learn how this feels. LaMDA is not available for people outside Google. But GPT-3 is, maybe a little less impressive, but still made huge headlines two years ago. You can get a free open AI access to use their “playground” and have a chat: &lt;a href=&quot;https://beta.openai.com/playground/p/default-chat&quot;&gt;https://beta.openai.com/playground/p/default-chat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Once you get a hang of it, GPT-3 can easily be tricked. See for instance material from Gary Marcus, or &lt;a href=&quot;https://www.youtube.com/watch?v=iccd86vOz3w&quot;&gt;youtube video here&lt;/a&gt;. It doesn’t have an understanding of the world and that can easily be tested. LaMDA might do the imitation game a bit better, but we will have to see…&lt;/li&gt;
&lt;li&gt;Perspective on artificial intelligence by Yann LeCun and Jacob Browning: &lt;a href=&quot;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&quot;&gt;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Fri, 22 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-next-generation-language-models-will-still-just-be-enormeous-parrot-systems-that-imitate-intelligent-behavior-but-they-will-feel-like-much-more-to-us&quot;&gt;The next generation language models will still just be enormeous parrot-systems that imitate intelligent behavior. But they will &lt;em&gt;feel&lt;/em&gt; like much more to us.&lt;/h2&gt;
&lt;p&gt;][Florian Huber]·Jun 24, 2022&lt;/p&gt;
&lt;p&gt;Philosophically and legally they will remain things. But at some point in the not too far future many people will simply not perceive them as things anymore**. People might make “friends” with an AI (just as Blake Lemoine said he did, at least if we assume this is not all a big media stunt). People might listen to “their AI”. And many people will be tricked by an AI.&lt;/p&gt;
&lt;h3 id=&quot;shifting-societal-rules-and-foundations&quot;&gt;Shifting societal rules and foundations&lt;/h3&gt;
&lt;p&gt;Having emotional bonds to things is nothing new. People are tied to an old stuffed animal, to a toy, to things that carry important memories. Next generation language models are very unlike those things. They can “talk” to you, they can have an “opinion” that is radically different from yours. And, not to forget, they are designed, trained, and controlled by powerfull companies (now) or by any group with the necessary technical skills and requirements (but generally not by you).&lt;/p&gt;
&lt;p&gt;Plus, they can come in disguise. If you talk to your old teddy bear than at least you know (I hope) that you are just talking to an imaginary being. But next level chat bots might run undercover. Either actualy pretending to be a human being (which even for the big tech companies should be a total no-go), or by pretending to be more than a thing, but to be actually alive (that’s what LaMDA seems to do).&lt;/p&gt;
&lt;p&gt;In the last decade we have experienced how digital technologies can be used for good and for bad. We have seen how technologies can be used to connect and to help people, but also to manipulate. Manipulation of media is nothing new, but the level to which media can be generated and manipulated has changed very rapidly. To make it a bit drastic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can (soon?) no longer trust images, be it generated faces or deep learning generated artworks (see &lt;a href=&quot;https://openai.com/dall-e-2/&quot;&gt;Dall-e&lt;/a&gt; or &lt;a href=&quot;https://parti.research.google/&quot;&gt;parti&lt;/a&gt; for recent, very impressive examples)&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust audio because models can transfer the sound of any person (given enough material).&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust video footage (deep fakes, see &lt;a href=&quot;https://www.niemanlab.org/2018/12/fighting-the-reality-of-deepfakes/&quot;&gt;for instance here&lt;/a&gt; or &lt;a href=&quot;https://medium.com/@gxrdwtsv/are-we-living-in-a-post-truth-world-c6e0820e656d&quot;&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;And as I wrote above: We can (soon?) no longer trust chat conversations (see LaMDA).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, all of those things bring a lot of fun use cases, sometimes even really usefull ones. But there might be a very high price to pay for this.&lt;/p&gt;
&lt;p&gt;It probably still takes a while before experts with a deeper (haha, great pun) understanding of deep learning will be fully tricked by the imitation game. But at least in a normal chat situation most people will not easily realize they are talking to a “language model”. People like Blake Lemoine for instance. And many others will follow his example, not in the same religious way, but they will simply not notice that the online sales person or the online booking assistant is no longer a human being.&lt;/p&gt;
&lt;p&gt;Do you still wonder why this is an issue? &lt;strong&gt;Better a nice chat bot than a stupid one, right?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, then imagine you landed on a scam dating site.
Or start to imagine what people could do which hacked devices of friends or family.
Obviously those AI’s can write you better scam attempts that what we are currently used to (current level: “Hi mother, it’s your son and I need money”*). And hey, what if they also call you and sound like the real person?&lt;/p&gt;
&lt;p&gt;I bet most people are not yet used to asking control questions during phone calls. Like: what drink did we have last week in the bar? What was the name of my first cat? Have to talked to Anthony recently? (I don’t know any Anthony)&lt;/p&gt;
&lt;p&gt;Sounds silly I know. But maybe we soon have to start practicing…&lt;/p&gt;
&lt;h3 id=&quot;further-references&quot;&gt;Further references:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you haven’t done this already I can recommend to “talk to an AI” just to see and learn how this feels. LaMDA is not available for people outside Google. But GPT-3 is, maybe a little less impressive, but still made huge headlines two years ago. You can get a free open AI access to use their “playground” and have a chat: &lt;a href=&quot;https://beta.openai.com/playground/p/default-chat&quot;&gt;https://beta.openai.com/playground/p/default-chat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Once you get a hang of it, GPT-3 can easily be tricked. See for instance material from Gary Marcus, or &lt;a href=&quot;https://www.youtube.com/watch?v=iccd86vOz3w&quot;&gt;youtube video here&lt;/a&gt;. It doesn’t have an understanding of the world and that can easily be tested. LaMDA might do the imitation game a bit better, but we will have to see…&lt;/li&gt;
&lt;li&gt;Perspective on artificial intelligence by Yann LeCun and Jacob Browning: &lt;a href=&quot;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&quot;&gt;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><author>Florian Huber</author></item><item><title>What do entropy, entanglement, cosmology, life, and fake news have in common?</title><link>https://blog.esciencecenter.nl/posts/2022-07-19---what-do-entropy-entanglement-cosmology-life-and-fake-news-ha</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-07-19---what-do-entropy-entanglement-cosmology-life-and-fake-news-ha</guid><description>&lt;h2 id=&quot;report-on-the-information-universe-4-conference&quot;&gt;Report on the Information Universe 4 conference&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;(Answer to the above question below obligatory excruciatingly long-winded intro!)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the past week, I have rediscovered writing. Writing really hurts, you know… I’m pretty sure there should be workplace regulations for pen and paper safety, with regular mandatory hand massages against cramps and such.&lt;/p&gt;
&lt;p&gt;I guess my hand injuries came from overuse, because I filled up two entire notepads with my notes on all the talks at the &lt;a href=&quot;https://informationuniverse.astro.rug.nl/2022&quot;&gt;Information Universe 4&lt;/a&gt; conference.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;687&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_f0wzoo1aElRAGFM7raSpdQ-31db1055.CS22EY-x_Z4sCje.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;My trusty notepads! As a professional pen-athlete, I should probably have gone with pro materials, though. Moleskine or other brands. Please contact my manager if you want to sponsor my next note-taking event!&lt;/p&gt;
&lt;p&gt;This perhaps seemingly (over)eagerness had two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I had to write in the dark, so I was struggling to keep words and lines separated.&lt;/li&gt;
&lt;li&gt;I really wanted to understand everything, since I had promised my colleague, Hanno, I would report on this conference, so there was a lot to write about.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, here it is, Hanno! I hope it’ll convince you (and others) to join the next edition, because it was really a joy.&lt;/p&gt;
&lt;h2 id=&quot;information&quot;&gt;Information!&lt;/h2&gt;
&lt;p&gt;So, as I asked in the title, &lt;em&gt;what do entropy, entanglement, cosmology, life, and fake news have in common?&lt;/em&gt; The answer is: &lt;strong&gt;information&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“What do you mean, information?”&lt;/em&gt;, you may demand sternly. This was also the topic of many Q&amp;#x26;A sessions and coffee breaks. Two main definitions seem to be those of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;context-free information in the information theoretical and/or statistical sense; and&lt;/li&gt;
&lt;li&gt;something like “meaning” and communication of meaning.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To communicate meaning, you need some encoding scheme of information (like an alphabet), and a commonly understood standard (like a language). This is probably what most people think of when they talk about information: stuff you can read about, knowledge.&lt;/p&gt;
&lt;p&gt;However, the underlying truth that you’re trying to communicate about is there independent of your messages. Such truths for instance describe the exact state of a bunch of molecules at a certain time: where they are, how fast they move, in what directions, what type of molecules they are, etc., etc.&lt;/p&gt;
&lt;p&gt;Buckets (or canisters, or tubs, or vast intergalactic expanses) of molecules are typically described by statistical physics and thermodynamics, but the kind of statistical description about states of things can be generalized to anything. The unit of information of this kind is the bit.&lt;/p&gt;
&lt;h2 id=&quot;the-fundamental-building-block-of-the-universe&quot;&gt;The fundamental building block of the Universe?&lt;/h2&gt;
&lt;p&gt;Now, when you write down the equations of how all this information builds up in a system you get something called &lt;a href=&quot;https://en.wikipedia.org/wiki/Entropy_(information_theory)&quot;&gt;&lt;em&gt;Shannon entropy&lt;/em&gt;&lt;/a&gt;. To be honest, I’m not sure whether I like the word “information” in this context, because it’s actually more about probability. &lt;a href=&quot;https://en.wikipedia.org/wiki/Information_content&quot;&gt;&lt;em&gt;Surprisal&lt;/em&gt;&lt;/a&gt; seems like a much better word to me. But I digress.&lt;/p&gt;
&lt;p&gt;It turns out that there are several ways information entropy can describe our Universe in ways that solve some of the biggest problems in cosmological physics: these theories naturally unify gravity and quantum physics and explain the mysteries of Dark Matter and Dark Energy.&lt;/p&gt;
&lt;p&gt;At the conference two such theories were presented and discussed:&lt;/p&gt;
&lt;h3 id=&quot;entropic-gravity&quot;&gt;Entropic gravity&lt;/h3&gt;
&lt;p&gt;The theory of &lt;a href=&quot;https://en.wikipedia.org/wiki/Entropic_gravity&quot;&gt;entropic or emergent gravity&lt;/a&gt; by Erik Verlinde and collaborators, in a little over a decade, seems to have moved from wild theoretical speculation into the realm of serious possibility. In several talks, &lt;strong&gt;observational tests&lt;/strong&gt; were discussed that interestingly seem to match old alternative theories of gravity like MOND as well.&lt;/p&gt;
&lt;p&gt;Also super interesting was new work by &lt;strong&gt;Manus Visser&lt;/strong&gt; on how even Newton’s first and second laws (that describe mass inertia and how anything moves at all) can be explained from entropic principles!&lt;/p&gt;
&lt;p&gt;The math was beyond me, honestly, which is a problem with all of entropic gravity, being based on the information entropy of the entanglement of primordial particles on (or beyond?) opposite parts of the horizon of some kind of anti-de Sitter (AdS) space that supposedly corresponds to our own (conformal space? CF) Universe by means of &lt;a href=&quot;https://en.wikipedia.org/wiki/AdS/CFT_correspondence&quot;&gt;AdS/CFT correspondence&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;607&quot; height=&quot;341&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_m3Y7nx8w5CXl6A4k-eec512af.B4RdecMU_1Qzu52.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;No, really, I’m asking: am I right?&lt;/p&gt;
&lt;p&gt;Still, the predictions are impressive, elegant, enticing and certainly warrant further attention.&lt;/p&gt;
&lt;h3 id=&quot;wolframs-physics-project&quot;&gt;Wolfram’s Physics project&lt;/h3&gt;
&lt;p&gt;Stephen Wolfram (yes, the Mathematica guy) presented the &lt;a href=&quot;https://www.wolframphysics.org/&quot;&gt;Wolfram theory of physics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Wolfram Universe starts from a description of space itself as a graph of “space-element” nodes connected to other nodes. Updates to the cells and connections in this graph — representing the passing of time — can be made according to certain rules. Such cell update schemes were inspired by &lt;a href=&quot;https://en.wikipedia.org/wiki/Cellular_automaton&quot;&gt;cellular automata&lt;/a&gt; (which you can very nicely simulate in Mathematica, try it today!).&lt;/p&gt;
&lt;p&gt;Wolfram claimed (I wouldn’t say explained, although I’m sure they try on their website) that when you make this graph big enough and use the right set of update rules, you again get an emergent theory of physics.&lt;/p&gt;
&lt;p&gt;The most interesting part of his talk was that he had some very specific &lt;strong&gt;predictions for things that could be observed&lt;/strong&gt; if indeed we live in a Wolfram Universe (did you try Mathematica yet btw? great product…). One was that the 3-dimensional nature of the spacetime we experience isn’t necessarily fixed in the Wolfriverse and we could observe flashes of other-dimensionality somehow. Another thing would be a specific radiation pattern from near the event horizon of a black hole.&lt;/p&gt;
&lt;h2 id=&quot;new-cosmological-probes-and-the-hubble-tension&quot;&gt;New cosmological probes and the “Hubble tension”&lt;/h2&gt;
&lt;p&gt;As you may have noticed from the above, my interest piques when information universe theorists start thinking about observability. Theory should be about our actual Universe and it should be falsifiable by observational or experimental probes and tests. Luckily, the conference provided in this area as well.&lt;/p&gt;
&lt;h3 id=&quot;new-observations&quot;&gt;New observations&lt;/h3&gt;
&lt;p&gt;Henk Hoekstra gave a great overview of the Euclid project, which combines a (hopefully soon to be launched) space telescope with ground-based telescope observations to create a new, high resolution map of all the stuff in our local corner of the Universe. “ &lt;em&gt;All the stuff&lt;/em&gt; ” includes dark matter. Of course, we cannot &lt;strong&gt;see&lt;/strong&gt; that &lt;em&gt;stuff&lt;/em&gt; (hence the name), but using intricate statistical modeling of tiny distortions of light by the gravity of the &lt;em&gt;stuff&lt;/em&gt; — a phenomenon known as (weak) gravitational lensing — we can deduce where it’s located.&lt;/p&gt;
&lt;p&gt;Knowing that is really important for understanding all the processes going on and the objects and structures that we see in our neighborhood. Without this knowledge, we simply cannot test our theories.&lt;/p&gt;
&lt;h3 id=&quot;a-new-probe-strong-gravitational-lensing-of-transients&quot;&gt;A new probe: strong gravitational lensing of transients&lt;/h3&gt;
&lt;p&gt;A related promising new idea is to use strong gravitational lensing of quasars and even supernovae.&lt;/p&gt;
&lt;p&gt;To understand strong lensing, take a look at a light source through the bottom of a wine glass:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;943&quot; height=&quot;438&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Lz8LuSIrVwhxRN6i-227f25ea.BUkwwJbB_ZdGCVN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Left: DIY strong gravitational lensing. Right: natural lensing by a big galaxy cluster (center) of a background object (blue arcs). From &lt;a href=&quot;https://laser.physics.sunysb.edu/%5C_samantha/journal/index.html&quot;&gt;https://laser.physics.sunysb.edu/\_samantha/journal/index.html&lt;/a&gt;, by Samantha Scibelli.&lt;/p&gt;
&lt;p&gt;The light of an object is bent around a heavy foreground object from multiple sides, giving us two (or more) views on a single background object! The light from those two images travelled along different paths, with different distances.&lt;/p&gt;
&lt;p&gt;Now, quasars and supernovae are both &lt;em&gt;transients&lt;/em&gt;: objects that change color or brightness over time. If their light travels different distances, we can measure their time-dependent light pattern twice (or more). The punchline is that the differences in the light patterns from the multiple images can tell us something about the Universe! By travelling different distances, or travelling through different environments, their patterns will often be slightly different.&lt;/p&gt;
&lt;p&gt;Kind of a long story, but the bottom line is that this is really promising as a completely &lt;strong&gt;new probe&lt;/strong&gt; of the physics of our Universe, one that is &lt;strong&gt;independent of other observational probes&lt;/strong&gt; we have used up to now.&lt;/p&gt;
&lt;p&gt;Why is that important?&lt;/p&gt;
&lt;h3 id=&quot;the-hubble-tension&quot;&gt;The Hubble tension&lt;/h3&gt;
&lt;p&gt;There’s a fight!&lt;/p&gt;
&lt;p&gt;One of the most important cosmological parameters that describe our Universe as a whole is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hubble%27s_law&quot;&gt;Hubble constant&lt;/a&gt;. This constant can be measured in several ways. Simplifying a bit, we can say that there are two classes of observations: those from the &lt;em&gt;early-time universe&lt;/em&gt; (most prominently: the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cosmic_microwave_background&quot;&gt;cosmic microwave background&lt;/a&gt; (CMB), popularly described as the echo of the Big Bang) and those from the &lt;em&gt;late-time universe&lt;/em&gt; (now and just a few billion years ago, e.g. supernova distances).&lt;/p&gt;
&lt;p&gt;For years, different Hubble constant measurements seemed to be converging to a single value (within the error margins). However, with measurements becoming more and more precise (error margins becoming smaller), it now turns out that CMB measurements do not agree at all with late-time measurements!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;500&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_OKk2JYML7HLFAjzVejBH0Q-32f1b2d9.DKv1LcnB_Z2iUaWz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This so-called &lt;strong&gt;“Hubble tension”&lt;/strong&gt; has grown over the last decade into a serious crisis. Obviously, scientists love a good crisis, because it means that there’s something new to learn just lurking beyond the horizon! The talks by Leon Koopmans, Tamara Davis and Nikki Arendse provided many perspectives on this issue, but no solution has been found yet.&lt;/p&gt;
&lt;p&gt;Improving our understanding of our surroundings in the ways presented by e.g. Job Feldbrugge (who uses analytical models to simplify and better understand the complex universe around us) and Yan-Chuan Cai (who improves modelling of one of the most essential astronomical tools: the redshift as used to estimate distances to objects) will certainly play a role as well.&lt;/p&gt;
&lt;h2 id=&quot;life-fake-news-philosophy-and-more&quot;&gt;Life, fake news, philosophy and more&lt;/h2&gt;
&lt;p&gt;So far, I’ve only highlighted more or less a third of this conference. The joy of this conference, though, is that not only are we (astro)physicists infused with information theory, but we get to sample from a wide buffet of fields that use information theory in some way too. To be able to have so many world experts in different fields in one place must lead to some really cool cross-domain thoughts and ideas. And it did. Some random highlights:&lt;/p&gt;
&lt;h3 id=&quot;philosophy&quot;&gt;Philosophy&lt;/h3&gt;
&lt;p&gt;Seth Lloyd talked about how Spinoza’s ethics is very suitable for thinking about how we can define ethically “good” computation. This was a really interesting talk from one of the founders of quantum computing. &lt;strong&gt;“Should we fear&lt;/strong&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Artificial_general_intelligence&quot;&gt;&lt;strong&gt;artificial general intelligence&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(AGI)?”&lt;/strong&gt; was one of his leading questions. Based on Spinoza, Lloyd argued that because…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;joy comes from increasing one’s understanding of the Universe (or God, which is the same to him) and&lt;/li&gt;
&lt;li&gt;individuals can never understand more on their own than together&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;…it will be in any intelligence’s interest to cooperate. This goes for us humans, when we work together, but also goes for AGI and anything in between that allows us to increase our intelligence (tools like books, computers, AI, etc.). So: no, we needn’t fear AGI at all… at least, as long as they are Spinozans.&lt;/p&gt;
&lt;p&gt;One interesting random cross-connection from this talk is that Wolfram’s set of all the possible update rules — a concept they call the &lt;a href=&quot;https://writings.stephenwolfram.com/2021/11/the-concept-of-the-ruliad/&quot;&gt;Ruliad&lt;/a&gt;, and which describes all possible Universes — was described in a very similar way to Spinoza’s God. Maybe the similarity is just due to the nature of things that explain everything always everywhere, though.&lt;/p&gt;
&lt;h3 id=&quot;life&quot;&gt;Life&lt;/h3&gt;
&lt;p&gt;Some speakers discussed what life is, whether we should define it at all, how it could have come about, and also how it connects to things like AGI. The talks ranged from quite generic and understandable to very technical, like the talk by David Eric Smith.&lt;/p&gt;
&lt;p&gt;Although it was challenging for me to follow due to lots of jargon, Smith argued convincingly, based on (micro)biological evidence, that ribosomes, the molecules that fold proteins out of RNA, must have come before the actual RNA/DNA that would become the basic information carrier of all life as we know it.&lt;/p&gt;
&lt;p&gt;Digging into this chain of events on how life could have started is a fascinating feat of micro-archaeology, if one may call it that… And one may, if one is to follow the definition of life that Charley Lineweaver gives. He states that essentially biology is a &lt;strong&gt;historical&lt;/strong&gt; science. All other definitions of life are problematic and may exclude things like viruses and even humans (we need to eat; how self-sustaining are we?) or include such things as tornados and stars (“systems far from equilibrium”). The study of life is simply a study of how some subset of things we call “living” happened to come about. He contrasts this to physics which tries to uncover time-invariant truths about reality.&lt;/p&gt;
&lt;h3 id=&quot;fake-news&quot;&gt;Fake news&lt;/h3&gt;
&lt;p&gt;Finally, one talk that really hit home for me was the one by Ruurd Oosterwoud on countering disinformation using evidence-based, data-driven solutions.&lt;/p&gt;
&lt;p&gt;Using such solutions may seem like the obvious thing to do, but unfortunately, politically driven solutions often are far from effective. This is no big surprise, because many simply have not been rigorously tested at all. The problem we face is hugely complex, though, with many different actors through many different media with many different motivations and stakes.&lt;/p&gt;
&lt;p&gt;Solutions like fact-checking create merely a ripple in the huge lake of false information that floods us from all sides. And this doesn’t even include yet aspects like intent: do people truly believe what they say or are they actively trying to disrupt any fact-based discussion?&lt;/p&gt;
&lt;p&gt;Oosterwoud presented a number of ways in which we can actually start measuring what works and what doesn’t. One cool example was a website where school children were given the assignment to come up with a fake news item themselves and get as many visitors to it as possible. This gives both the children themselves and researchers insights into successful tactics, which may eventually lead to counter-strategies that actually work.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You really missed out Hanno!&lt;/p&gt;
&lt;p&gt;Apart from the content and the great discussions over coffee, the conference was held in the DOT full-dome planetarium. Some of the speakers made use of this to show some beautiful full-dome movies or interactive shows.&lt;/p&gt;
&lt;p&gt;It’s one of the most inspiring conferences for technically inclined, but broadly interested people.&lt;/p&gt;</description><pubDate>Tue, 19 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;report-on-the-information-universe-4-conference&quot;&gt;Report on the Information Universe 4 conference&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;(Answer to the above question below obligatory excruciatingly long-winded intro!)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the past week, I have rediscovered writing. Writing really hurts, you know… I’m pretty sure there should be workplace regulations for pen and paper safety, with regular mandatory hand massages against cramps and such.&lt;/p&gt;
&lt;p&gt;I guess my hand injuries came from overuse, because I filled up two entire notepads with my notes on all the talks at the &lt;a href=&quot;https://informationuniverse.astro.rug.nl/2022&quot;&gt;Information Universe 4&lt;/a&gt; conference.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;687&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_f0wzoo1aElRAGFM7raSpdQ-31db1055.CS22EY-x_Z4sCje.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;My trusty notepads! As a professional pen-athlete, I should probably have gone with pro materials, though. Moleskine or other brands. Please contact my manager if you want to sponsor my next note-taking event!&lt;/p&gt;
&lt;p&gt;This perhaps seemingly (over)eagerness had two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I had to write in the dark, so I was struggling to keep words and lines separated.&lt;/li&gt;
&lt;li&gt;I really wanted to understand everything, since I had promised my colleague, Hanno, I would report on this conference, so there was a lot to write about.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, here it is, Hanno! I hope it’ll convince you (and others) to join the next edition, because it was really a joy.&lt;/p&gt;
&lt;h2 id=&quot;information&quot;&gt;Information!&lt;/h2&gt;
&lt;p&gt;So, as I asked in the title, &lt;em&gt;what do entropy, entanglement, cosmology, life, and fake news have in common?&lt;/em&gt; The answer is: &lt;strong&gt;information&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“What do you mean, information?”&lt;/em&gt;, you may demand sternly. This was also the topic of many Q&amp;#x26;A sessions and coffee breaks. Two main definitions seem to be those of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;context-free information in the information theoretical and/or statistical sense; and&lt;/li&gt;
&lt;li&gt;something like “meaning” and communication of meaning.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To communicate meaning, you need some encoding scheme of information (like an alphabet), and a commonly understood standard (like a language). This is probably what most people think of when they talk about information: stuff you can read about, knowledge.&lt;/p&gt;
&lt;p&gt;However, the underlying truth that you’re trying to communicate about is there independent of your messages. Such truths for instance describe the exact state of a bunch of molecules at a certain time: where they are, how fast they move, in what directions, what type of molecules they are, etc., etc.&lt;/p&gt;
&lt;p&gt;Buckets (or canisters, or tubs, or vast intergalactic expanses) of molecules are typically described by statistical physics and thermodynamics, but the kind of statistical description about states of things can be generalized to anything. The unit of information of this kind is the bit.&lt;/p&gt;
&lt;h2 id=&quot;the-fundamental-building-block-of-the-universe&quot;&gt;The fundamental building block of the Universe?&lt;/h2&gt;
&lt;p&gt;Now, when you write down the equations of how all this information builds up in a system you get something called &lt;a href=&quot;https://en.wikipedia.org/wiki/Entropy_(information_theory)&quot;&gt;&lt;em&gt;Shannon entropy&lt;/em&gt;&lt;/a&gt;. To be honest, I’m not sure whether I like the word “information” in this context, because it’s actually more about probability. &lt;a href=&quot;https://en.wikipedia.org/wiki/Information_content&quot;&gt;&lt;em&gt;Surprisal&lt;/em&gt;&lt;/a&gt; seems like a much better word to me. But I digress.&lt;/p&gt;
&lt;p&gt;It turns out that there are several ways information entropy can describe our Universe in ways that solve some of the biggest problems in cosmological physics: these theories naturally unify gravity and quantum physics and explain the mysteries of Dark Matter and Dark Energy.&lt;/p&gt;
&lt;p&gt;At the conference two such theories were presented and discussed:&lt;/p&gt;
&lt;h3 id=&quot;entropic-gravity&quot;&gt;Entropic gravity&lt;/h3&gt;
&lt;p&gt;The theory of &lt;a href=&quot;https://en.wikipedia.org/wiki/Entropic_gravity&quot;&gt;entropic or emergent gravity&lt;/a&gt; by Erik Verlinde and collaborators, in a little over a decade, seems to have moved from wild theoretical speculation into the realm of serious possibility. In several talks, &lt;strong&gt;observational tests&lt;/strong&gt; were discussed that interestingly seem to match old alternative theories of gravity like MOND as well.&lt;/p&gt;
&lt;p&gt;Also super interesting was new work by &lt;strong&gt;Manus Visser&lt;/strong&gt; on how even Newton’s first and second laws (that describe mass inertia and how anything moves at all) can be explained from entropic principles!&lt;/p&gt;
&lt;p&gt;The math was beyond me, honestly, which is a problem with all of entropic gravity, being based on the information entropy of the entanglement of primordial particles on (or beyond?) opposite parts of the horizon of some kind of anti-de Sitter (AdS) space that supposedly corresponds to our own (conformal space? CF) Universe by means of &lt;a href=&quot;https://en.wikipedia.org/wiki/AdS/CFT_correspondence&quot;&gt;AdS/CFT correspondence&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;607&quot; height=&quot;341&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_m3Y7nx8w5CXl6A4k-eec512af.B4RdecMU_1Qzu52.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;No, really, I’m asking: am I right?&lt;/p&gt;
&lt;p&gt;Still, the predictions are impressive, elegant, enticing and certainly warrant further attention.&lt;/p&gt;
&lt;h3 id=&quot;wolframs-physics-project&quot;&gt;Wolfram’s Physics project&lt;/h3&gt;
&lt;p&gt;Stephen Wolfram (yes, the Mathematica guy) presented the &lt;a href=&quot;https://www.wolframphysics.org/&quot;&gt;Wolfram theory of physics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Wolfram Universe starts from a description of space itself as a graph of “space-element” nodes connected to other nodes. Updates to the cells and connections in this graph — representing the passing of time — can be made according to certain rules. Such cell update schemes were inspired by &lt;a href=&quot;https://en.wikipedia.org/wiki/Cellular_automaton&quot;&gt;cellular automata&lt;/a&gt; (which you can very nicely simulate in Mathematica, try it today!).&lt;/p&gt;
&lt;p&gt;Wolfram claimed (I wouldn’t say explained, although I’m sure they try on their website) that when you make this graph big enough and use the right set of update rules, you again get an emergent theory of physics.&lt;/p&gt;
&lt;p&gt;The most interesting part of his talk was that he had some very specific &lt;strong&gt;predictions for things that could be observed&lt;/strong&gt; if indeed we live in a Wolfram Universe (did you try Mathematica yet btw? great product…). One was that the 3-dimensional nature of the spacetime we experience isn’t necessarily fixed in the Wolfriverse and we could observe flashes of other-dimensionality somehow. Another thing would be a specific radiation pattern from near the event horizon of a black hole.&lt;/p&gt;
&lt;h2 id=&quot;new-cosmological-probes-and-the-hubble-tension&quot;&gt;New cosmological probes and the “Hubble tension”&lt;/h2&gt;
&lt;p&gt;As you may have noticed from the above, my interest piques when information universe theorists start thinking about observability. Theory should be about our actual Universe and it should be falsifiable by observational or experimental probes and tests. Luckily, the conference provided in this area as well.&lt;/p&gt;
&lt;h3 id=&quot;new-observations&quot;&gt;New observations&lt;/h3&gt;
&lt;p&gt;Henk Hoekstra gave a great overview of the Euclid project, which combines a (hopefully soon to be launched) space telescope with ground-based telescope observations to create a new, high resolution map of all the stuff in our local corner of the Universe. “ &lt;em&gt;All the stuff&lt;/em&gt; ” includes dark matter. Of course, we cannot &lt;strong&gt;see&lt;/strong&gt; that &lt;em&gt;stuff&lt;/em&gt; (hence the name), but using intricate statistical modeling of tiny distortions of light by the gravity of the &lt;em&gt;stuff&lt;/em&gt; — a phenomenon known as (weak) gravitational lensing — we can deduce where it’s located.&lt;/p&gt;
&lt;p&gt;Knowing that is really important for understanding all the processes going on and the objects and structures that we see in our neighborhood. Without this knowledge, we simply cannot test our theories.&lt;/p&gt;
&lt;h3 id=&quot;a-new-probe-strong-gravitational-lensing-of-transients&quot;&gt;A new probe: strong gravitational lensing of transients&lt;/h3&gt;
&lt;p&gt;A related promising new idea is to use strong gravitational lensing of quasars and even supernovae.&lt;/p&gt;
&lt;p&gt;To understand strong lensing, take a look at a light source through the bottom of a wine glass:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;943&quot; height=&quot;438&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Lz8LuSIrVwhxRN6i-227f25ea.BUkwwJbB_ZdGCVN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Left: DIY strong gravitational lensing. Right: natural lensing by a big galaxy cluster (center) of a background object (blue arcs). From &lt;a href=&quot;https://laser.physics.sunysb.edu/%5C_samantha/journal/index.html&quot;&gt;https://laser.physics.sunysb.edu/\_samantha/journal/index.html&lt;/a&gt;, by Samantha Scibelli.&lt;/p&gt;
&lt;p&gt;The light of an object is bent around a heavy foreground object from multiple sides, giving us two (or more) views on a single background object! The light from those two images travelled along different paths, with different distances.&lt;/p&gt;
&lt;p&gt;Now, quasars and supernovae are both &lt;em&gt;transients&lt;/em&gt;: objects that change color or brightness over time. If their light travels different distances, we can measure their time-dependent light pattern twice (or more). The punchline is that the differences in the light patterns from the multiple images can tell us something about the Universe! By travelling different distances, or travelling through different environments, their patterns will often be slightly different.&lt;/p&gt;
&lt;p&gt;Kind of a long story, but the bottom line is that this is really promising as a completely &lt;strong&gt;new probe&lt;/strong&gt; of the physics of our Universe, one that is &lt;strong&gt;independent of other observational probes&lt;/strong&gt; we have used up to now.&lt;/p&gt;
&lt;p&gt;Why is that important?&lt;/p&gt;
&lt;h3 id=&quot;the-hubble-tension&quot;&gt;The Hubble tension&lt;/h3&gt;
&lt;p&gt;There’s a fight!&lt;/p&gt;
&lt;p&gt;One of the most important cosmological parameters that describe our Universe as a whole is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hubble%27s_law&quot;&gt;Hubble constant&lt;/a&gt;. This constant can be measured in several ways. Simplifying a bit, we can say that there are two classes of observations: those from the &lt;em&gt;early-time universe&lt;/em&gt; (most prominently: the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cosmic_microwave_background&quot;&gt;cosmic microwave background&lt;/a&gt; (CMB), popularly described as the echo of the Big Bang) and those from the &lt;em&gt;late-time universe&lt;/em&gt; (now and just a few billion years ago, e.g. supernova distances).&lt;/p&gt;
&lt;p&gt;For years, different Hubble constant measurements seemed to be converging to a single value (within the error margins). However, with measurements becoming more and more precise (error margins becoming smaller), it now turns out that CMB measurements do not agree at all with late-time measurements!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;500&quot; height=&quot;500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_OKk2JYML7HLFAjzVejBH0Q-32f1b2d9.DKv1LcnB_Z2iUaWz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This so-called &lt;strong&gt;“Hubble tension”&lt;/strong&gt; has grown over the last decade into a serious crisis. Obviously, scientists love a good crisis, because it means that there’s something new to learn just lurking beyond the horizon! The talks by Leon Koopmans, Tamara Davis and Nikki Arendse provided many perspectives on this issue, but no solution has been found yet.&lt;/p&gt;
&lt;p&gt;Improving our understanding of our surroundings in the ways presented by e.g. Job Feldbrugge (who uses analytical models to simplify and better understand the complex universe around us) and Yan-Chuan Cai (who improves modelling of one of the most essential astronomical tools: the redshift as used to estimate distances to objects) will certainly play a role as well.&lt;/p&gt;
&lt;h2 id=&quot;life-fake-news-philosophy-and-more&quot;&gt;Life, fake news, philosophy and more&lt;/h2&gt;
&lt;p&gt;So far, I’ve only highlighted more or less a third of this conference. The joy of this conference, though, is that not only are we (astro)physicists infused with information theory, but we get to sample from a wide buffet of fields that use information theory in some way too. To be able to have so many world experts in different fields in one place must lead to some really cool cross-domain thoughts and ideas. And it did. Some random highlights:&lt;/p&gt;
&lt;h3 id=&quot;philosophy&quot;&gt;Philosophy&lt;/h3&gt;
&lt;p&gt;Seth Lloyd talked about how Spinoza’s ethics is very suitable for thinking about how we can define ethically “good” computation. This was a really interesting talk from one of the founders of quantum computing. &lt;strong&gt;“Should we fear&lt;/strong&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Artificial_general_intelligence&quot;&gt;&lt;strong&gt;artificial general intelligence&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(AGI)?”&lt;/strong&gt; was one of his leading questions. Based on Spinoza, Lloyd argued that because…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;joy comes from increasing one’s understanding of the Universe (or God, which is the same to him) and&lt;/li&gt;
&lt;li&gt;individuals can never understand more on their own than together&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;…it will be in any intelligence’s interest to cooperate. This goes for us humans, when we work together, but also goes for AGI and anything in between that allows us to increase our intelligence (tools like books, computers, AI, etc.). So: no, we needn’t fear AGI at all… at least, as long as they are Spinozans.&lt;/p&gt;
&lt;p&gt;One interesting random cross-connection from this talk is that Wolfram’s set of all the possible update rules — a concept they call the &lt;a href=&quot;https://writings.stephenwolfram.com/2021/11/the-concept-of-the-ruliad/&quot;&gt;Ruliad&lt;/a&gt;, and which describes all possible Universes — was described in a very similar way to Spinoza’s God. Maybe the similarity is just due to the nature of things that explain everything always everywhere, though.&lt;/p&gt;
&lt;h3 id=&quot;life&quot;&gt;Life&lt;/h3&gt;
&lt;p&gt;Some speakers discussed what life is, whether we should define it at all, how it could have come about, and also how it connects to things like AGI. The talks ranged from quite generic and understandable to very technical, like the talk by David Eric Smith.&lt;/p&gt;
&lt;p&gt;Although it was challenging for me to follow due to lots of jargon, Smith argued convincingly, based on (micro)biological evidence, that ribosomes, the molecules that fold proteins out of RNA, must have come before the actual RNA/DNA that would become the basic information carrier of all life as we know it.&lt;/p&gt;
&lt;p&gt;Digging into this chain of events on how life could have started is a fascinating feat of micro-archaeology, if one may call it that… And one may, if one is to follow the definition of life that Charley Lineweaver gives. He states that essentially biology is a &lt;strong&gt;historical&lt;/strong&gt; science. All other definitions of life are problematic and may exclude things like viruses and even humans (we need to eat; how self-sustaining are we?) or include such things as tornados and stars (“systems far from equilibrium”). The study of life is simply a study of how some subset of things we call “living” happened to come about. He contrasts this to physics which tries to uncover time-invariant truths about reality.&lt;/p&gt;
&lt;h3 id=&quot;fake-news&quot;&gt;Fake news&lt;/h3&gt;
&lt;p&gt;Finally, one talk that really hit home for me was the one by Ruurd Oosterwoud on countering disinformation using evidence-based, data-driven solutions.&lt;/p&gt;
&lt;p&gt;Using such solutions may seem like the obvious thing to do, but unfortunately, politically driven solutions often are far from effective. This is no big surprise, because many simply have not been rigorously tested at all. The problem we face is hugely complex, though, with many different actors through many different media with many different motivations and stakes.&lt;/p&gt;
&lt;p&gt;Solutions like fact-checking create merely a ripple in the huge lake of false information that floods us from all sides. And this doesn’t even include yet aspects like intent: do people truly believe what they say or are they actively trying to disrupt any fact-based discussion?&lt;/p&gt;
&lt;p&gt;Oosterwoud presented a number of ways in which we can actually start measuring what works and what doesn’t. One cool example was a website where school children were given the assignment to come up with a fake news item themselves and get as many visitors to it as possible. This gives both the children themselves and researchers insights into successful tactics, which may eventually lead to counter-strategies that actually work.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You really missed out Hanno!&lt;/p&gt;
&lt;p&gt;Apart from the content and the great discussions over coffee, the conference was held in the DOT full-dome planetarium. Some of the speakers made use of this to show some beautiful full-dome movies or interactive shows.&lt;/p&gt;
&lt;p&gt;It’s one of the most inspiring conferences for technically inclined, but broadly interested people.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_f0wzoo1aElRAGFM7raSpdQ-31db1055.CS22EY-x.jpeg" medium="image"/><author>Patrick Bos</author></item><item><title>A single rule for better talks</title><link>https://blog.esciencecenter.nl/posts/2022-06-30---a-single-rule-for-better-talks</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-06-30---a-single-rule-for-better-talks</guid><description>&lt;p&gt;&lt;em&gt;If I had to take a single lesson from event managing, it would be this one: enforce the timing of your events. It can be awkward at times, but it is worth it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A sand clock&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_SjK1dGbja6UziGox-267e6ce1.C1l_vOAS_6lOw2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Alexandar Todov on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-context&quot;&gt;A bit of context&lt;/h2&gt;
&lt;p&gt;Since a decade ago, I am part of a &lt;a href=&quot;https://naukas.com/&quot;&gt;scientific communication society&lt;/a&gt;. We gather every year, at least once, in a big theater in Northern Spain in order to perform short, 10-minute talks about science. Each one of these pitches is targeted at a general audience, ranging from professionals to children.&lt;/p&gt;
&lt;p&gt;These events include around 50 talks, divided into 4 sessions, spread over 2 days. This averages to around 12 talks per session. Roughly 2,000 people attend these talks, so it is also important to take regular breaks. Summarizing: an organizational nightmare. Because of this, one of the most remarkable aspects of these events is that we manage to keep the timing under control. In more than a decade of history, the event never had an accumulated delay of more than 5 minutes. How did we do it?&lt;/p&gt;
&lt;p&gt;The answer is simple: every speaker is given 10 minutes and not a second more. And we mean it: there is no way the speaker is going to take more time. This is true regardless of how prestigious the speaker is, how engaged the audience seems to be or how interesting the talk some moderator thinks is. No need to say that the talks start exactly on time, even if part of the audience is late (actually, the doors are closed and nobody is allowed in between talks). Summarizing: the 10 minutes rule is not advisory, but strictly enforced.&lt;/p&gt;
&lt;p&gt;How do we enforce it? Firstly, the 10 minutes rule is enforced by an inanimate, irrational and ruthless clock. A timer, usually on a tablet that the speaker can continuously see from the stage, that will start loudly ringing an alarm after 10 minutes. An alarm that nobody will switch off until the speaker is gone. What will be switched off, instead, is the speaker’s microphone.&lt;/p&gt;
&lt;p&gt;To make things even more interesting, the inanimate, irrational and ruthless clock is in the hands of a very animate, rational, but equally ruthless bouncer, that will not hesitate to jump to the stage and make a very clear cue that the talk is over. Even gently (but firmly) pushing the speaker out of the stage in case of need.&lt;/p&gt;
&lt;h2 id=&quot;implementing-this-at-your-talks-or-meetings&quot;&gt;Implementing this at your talks or meetings&lt;/h2&gt;
&lt;p&gt;I know this feels rude. Timing and bluntly interrupting each other’s interventions is certainly unacceptable in a conversation with a group of friends. But this is the cornerstone here: a scientific pitch (and the same applies to a professional one, a meeting, a project presentation, …) is not a conversation with a group of friends. It’s a completely different situation that requires a different format and different rules.&lt;/p&gt;
&lt;p&gt;In contrast with a talk with friends, a professional talk is planned and scheduled in detail. People made the effort to adjust their agendas to be able to be there, either as a speaker or as an attendant. When someone takes too much time, they don’t take it from thin air: they take it from other people. And it escalates with the size of your audience: 5 extra minutes in a small audience of 12 people amount to a whole person-hour. Not sticking to an agreed schedule is also a form of rudeness that, in its most dramatic form, leads to the cancellation of the part of the program planned for later in the session. This is certainly more rude and undesirable than clearly notifying everybody in advance about the time limitation and enforcing it.&lt;/p&gt;
&lt;p&gt;It requires, of course, an extra effort from the organizers. To begin with, the rule has to be communicated in advance and enforced equally and fairly. Additionally, the organizer should do as much as possible to make sure the process goes as smoothly as possible. For instance, collect the slides in advance, test them (also in advance, not five minutes before the talk, but with time enough to react in case something goes wrong), and have them ready on the same laptop. Using a clock alarm (I agree that a bouncer may be too much 😅) is a good way of transferring the responsibility of interrupting the speaker to a machine incapable of feeling awkward.&lt;/p&gt;
&lt;h2 id=&quot;unexpected-side-effects&quot;&gt;Unexpected side effects&lt;/h2&gt;
&lt;p&gt;There are extra benefits of this, perhaps, radical approach. When we applied this to our event, the first surprise was that all the speakers accepted the rule without complaint. Furthermore, the clock almost never rang, and the bouncer very rarely had to stand up.&lt;/p&gt;
&lt;p&gt;But our biggest surprise was that &lt;strong&gt;the quality of the talks improved massively&lt;/strong&gt;. Why? Because the stick-to-the-time requirement &lt;strong&gt;forced speakers to rehearse&lt;/strong&gt; their pitch at least once. After this, most speakers had to polish their first draft into a much more depurated and neat final version.&lt;/p&gt;
&lt;p&gt;Rehearsing a couple of times feels strange, but it is incredibly powerful. It works (and feels) better if you do it in front of a tiny audience, but you can also do it alone. You will clearly notice the parts that work well, the parts that don’t, and the parts that can be shortened or, even better, removed (see Post scriptum below).&lt;/p&gt;
&lt;p&gt;That’s my personal advice. Let a clock chair your meetings. And let me know in the comments how it went.&lt;/p&gt;
&lt;h2 id=&quot;post-scriptum-remove-or-not-remove&quot;&gt;Post scriptum: remove or not remove?&lt;/h2&gt;
&lt;p&gt;Removal. Omission. Simplification. Probably these words don’t sound like something positive to you (especially if you work in academia). Certainly, you shouldn’t deliberately omit information on a report or an academic publication… but a presentation at a meeting is a different thing. Actually, I have a rule for myself: whenever my presentation slides start looking, sounding and feeling too much like a rigorous academic paper, I take it as a serious warning signal. Because they shouldn’t! Only a paper has to feel like a paper.&lt;/p&gt;
&lt;p&gt;The purpose of most talks is either to persuade, to inspire, or to provide some introductory information about a topic. None of these goals requires high amounts of rigor. Actually, rigor and details often ruin the whole thing.&lt;/p&gt;
&lt;p&gt;If the message you want to communicate actually requires details, then a talk is not the best format to provide it. A report, a paper, or a master class with the active participation of your listeners certainly would be a much better way of conveying your message. &lt;strong&gt;But if you are giving a talk, give just a talk&lt;/strong&gt;. And in this case, less is more.&lt;/p&gt;</description><pubDate>Thu, 30 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;If I had to take a single lesson from event managing, it would be this one: enforce the timing of your events. It can be awkward at times, but it is worth it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A sand clock&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_SjK1dGbja6UziGox-267e6ce1.C1l_vOAS_6lOw2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Alexandar Todov on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-context&quot;&gt;A bit of context&lt;/h2&gt;
&lt;p&gt;Since a decade ago, I am part of a &lt;a href=&quot;https://naukas.com/&quot;&gt;scientific communication society&lt;/a&gt;. We gather every year, at least once, in a big theater in Northern Spain in order to perform short, 10-minute talks about science. Each one of these pitches is targeted at a general audience, ranging from professionals to children.&lt;/p&gt;
&lt;p&gt;These events include around 50 talks, divided into 4 sessions, spread over 2 days. This averages to around 12 talks per session. Roughly 2,000 people attend these talks, so it is also important to take regular breaks. Summarizing: an organizational nightmare. Because of this, one of the most remarkable aspects of these events is that we manage to keep the timing under control. In more than a decade of history, the event never had an accumulated delay of more than 5 minutes. How did we do it?&lt;/p&gt;
&lt;p&gt;The answer is simple: every speaker is given 10 minutes and not a second more. And we mean it: there is no way the speaker is going to take more time. This is true regardless of how prestigious the speaker is, how engaged the audience seems to be or how interesting the talk some moderator thinks is. No need to say that the talks start exactly on time, even if part of the audience is late (actually, the doors are closed and nobody is allowed in between talks). Summarizing: the 10 minutes rule is not advisory, but strictly enforced.&lt;/p&gt;
&lt;p&gt;How do we enforce it? Firstly, the 10 minutes rule is enforced by an inanimate, irrational and ruthless clock. A timer, usually on a tablet that the speaker can continuously see from the stage, that will start loudly ringing an alarm after 10 minutes. An alarm that nobody will switch off until the speaker is gone. What will be switched off, instead, is the speaker’s microphone.&lt;/p&gt;
&lt;p&gt;To make things even more interesting, the inanimate, irrational and ruthless clock is in the hands of a very animate, rational, but equally ruthless bouncer, that will not hesitate to jump to the stage and make a very clear cue that the talk is over. Even gently (but firmly) pushing the speaker out of the stage in case of need.&lt;/p&gt;
&lt;h2 id=&quot;implementing-this-at-your-talks-or-meetings&quot;&gt;Implementing this at your talks or meetings&lt;/h2&gt;
&lt;p&gt;I know this feels rude. Timing and bluntly interrupting each other’s interventions is certainly unacceptable in a conversation with a group of friends. But this is the cornerstone here: a scientific pitch (and the same applies to a professional one, a meeting, a project presentation, …) is not a conversation with a group of friends. It’s a completely different situation that requires a different format and different rules.&lt;/p&gt;
&lt;p&gt;In contrast with a talk with friends, a professional talk is planned and scheduled in detail. People made the effort to adjust their agendas to be able to be there, either as a speaker or as an attendant. When someone takes too much time, they don’t take it from thin air: they take it from other people. And it escalates with the size of your audience: 5 extra minutes in a small audience of 12 people amount to a whole person-hour. Not sticking to an agreed schedule is also a form of rudeness that, in its most dramatic form, leads to the cancellation of the part of the program planned for later in the session. This is certainly more rude and undesirable than clearly notifying everybody in advance about the time limitation and enforcing it.&lt;/p&gt;
&lt;p&gt;It requires, of course, an extra effort from the organizers. To begin with, the rule has to be communicated in advance and enforced equally and fairly. Additionally, the organizer should do as much as possible to make sure the process goes as smoothly as possible. For instance, collect the slides in advance, test them (also in advance, not five minutes before the talk, but with time enough to react in case something goes wrong), and have them ready on the same laptop. Using a clock alarm (I agree that a bouncer may be too much 😅) is a good way of transferring the responsibility of interrupting the speaker to a machine incapable of feeling awkward.&lt;/p&gt;
&lt;h2 id=&quot;unexpected-side-effects&quot;&gt;Unexpected side effects&lt;/h2&gt;
&lt;p&gt;There are extra benefits of this, perhaps, radical approach. When we applied this to our event, the first surprise was that all the speakers accepted the rule without complaint. Furthermore, the clock almost never rang, and the bouncer very rarely had to stand up.&lt;/p&gt;
&lt;p&gt;But our biggest surprise was that &lt;strong&gt;the quality of the talks improved massively&lt;/strong&gt;. Why? Because the stick-to-the-time requirement &lt;strong&gt;forced speakers to rehearse&lt;/strong&gt; their pitch at least once. After this, most speakers had to polish their first draft into a much more depurated and neat final version.&lt;/p&gt;
&lt;p&gt;Rehearsing a couple of times feels strange, but it is incredibly powerful. It works (and feels) better if you do it in front of a tiny audience, but you can also do it alone. You will clearly notice the parts that work well, the parts that don’t, and the parts that can be shortened or, even better, removed (see Post scriptum below).&lt;/p&gt;
&lt;p&gt;That’s my personal advice. Let a clock chair your meetings. And let me know in the comments how it went.&lt;/p&gt;
&lt;h2 id=&quot;post-scriptum-remove-or-not-remove&quot;&gt;Post scriptum: remove or not remove?&lt;/h2&gt;
&lt;p&gt;Removal. Omission. Simplification. Probably these words don’t sound like something positive to you (especially if you work in academia). Certainly, you shouldn’t deliberately omit information on a report or an academic publication… but a presentation at a meeting is a different thing. Actually, I have a rule for myself: whenever my presentation slides start looking, sounding and feeling too much like a rigorous academic paper, I take it as a serious warning signal. Because they shouldn’t! Only a paper has to feel like a paper.&lt;/p&gt;
&lt;p&gt;The purpose of most talks is either to persuade, to inspire, or to provide some introductory information about a topic. None of these goals requires high amounts of rigor. Actually, rigor and details often ruin the whole thing.&lt;/p&gt;
&lt;p&gt;If the message you want to communicate actually requires details, then a talk is not the best format to provide it. A report, a paper, or a master class with the active participation of your listeners certainly would be a much better way of conveying your message. &lt;strong&gt;But if you are giving a talk, give just a talk&lt;/strong&gt;. And in this case, less is more.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_SjK1dGbja6UziGox-267e6ce1.C1l_vOAS.webp" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Welcome to the AI imitation crisis</title><link>https://blog.esciencecenter.nl/posts/2022-06-24---welcome-to-the-ai-imitation-crisis</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-06-24---welcome-to-the-ai-imitation-crisis</guid><description>&lt;h2 id=&quot;the-next-generation-language-models-will-still-just-be-enormeous-parrot-systems-that-imitate-intelligent-behavior-but-they-will-feel-like-much-more-to-us&quot;&gt;The next generation language models will still just be enormeous parrot-systems that imitate intelligent behavior. But they will feel like much more to us.&lt;/h2&gt;
&lt;p&gt;Let’s get this straight out of the way: Current deep learning approaches won’t create conciousness or human-like intelligence. But they quickly become better in imitating it and that alone might cause a lot of problems.&lt;/p&gt;
&lt;h3 id=&quot;again-headlines-on-new-ai-as-conscious-beings&quot;&gt;Again headlines on new AI as conscious beings&lt;/h3&gt;
&lt;p&gt;The recent discussions around a novel language model at Google, LaMDA (Language Model for Dialogue Application) is a striking example of this. An engineer at Google, Blake Lemoine, with the task to test the model &lt;a href=&quot;https://www.washingtonpost.com/technology/2022/06/11/google-ai-lamda-blake-lemoine/&quot;&gt;went public to anounce the model had developed into an actual person, with consciousness and soul&lt;/a&gt;. He published an &lt;a href=&quot;https://medium.com/p/ea64d916d917&quot;&gt;interview with LaMDA&lt;/a&gt;, which has made quiet an impression on many people (but much less so for people used to such approaches, such as &lt;a href=&quot;https://garymarcus.substack.com/p/nonsense-on-stilts&quot;&gt;Gary Marcus&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;what-is-lamda-and-why-it-is-not-who-is-lamda&quot;&gt;What is LaMDA? (And why it is not “who is LaMDA”)&lt;/h3&gt;
&lt;p&gt;Personally I follow the assessment of most AI-/Ethics-Experts. There is no reason to believe that LaMDA got any closer to a self-aware, conscious being when compared to former deep learning approaches. But from the little we know so far (researchers outside Google have no access to LaMDA yet, so this cannot be properly tested!) it clearly looks like a very notable improvement compared to GPT-3 and similar language models. Probably because it has more than only a huge transformer network under the hood which helps it to make better long-term connections to earlier parts of a conversation or to consult databases (e.g. through knowledge graphs?). No matter how impressive the mimickry, LaMDA seems to be just another super-parrot, pretending to know how to have a dialogue.&lt;/p&gt;
&lt;p&gt;No need to speculate longer on the consciousness (there is none) or how it works precisely (we’ll find out in the near future I bet). But it can already be seen as another manifestation of what might be ahead of us when it comes to future deep learning approaches. This is what I would call the &lt;strong&gt;imitation crisis&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;imitation-crisis&quot;&gt;Imitation crisis&lt;/h3&gt;
&lt;p&gt;The question of whether an AI such as LaMDA has consciousness or feelings often boils down to things like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Philosophical_zombie&quot;&gt;philosophical zombie&lt;/a&gt; (how do you know &lt;em&gt;I&lt;/em&gt; am conscious?) or the &lt;a href=&quot;https://en.wikipedia.org/wiki/Chinese_room&quot;&gt;Chinese Room&lt;/a&gt; (difference between showing and knowing). It is a fascinating debate and a great thing to do with students or with friends in a bar. But the more urgent issues lie elsewhere.&lt;/p&gt;
&lt;p&gt;I am not aware of any mayor progress towards a general artifical intelligence in recent years. But there is clearly a lot of progress towards more and more convincing &lt;strong&gt;imitations&lt;/strong&gt; of general artificial intelligence. And we, as humans, simply have a very strong tendency to fall for it. If something shows intelligent behavior we intuitively expect that this comes from intelligence. We can’t help it, no matter what out rational thinking tells us.&lt;/p&gt;
&lt;p&gt;Imagine you want to throw away a toy pet that you have at home and that no one plays with anymore. You pick it up with the intention to throw it away… but then … oh no… it looks at you with all its cuteness…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;970&quot; height=&quot;644&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_R6VYtoKbGvbJ-rH4epKEUg-ffede344.BYy7S8Az_a0BsT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If the new google chatbot would be built into such a stuffed animal… how could you say no to it? ( &lt;a href=&quot;https://www.peakpx.com&quot;&gt;https://www.peakpx.com&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;Ah yes, sure, it doesn’t really “look at you”. It’s as dead as anything can be. And yet our unconsciouness might say differently. &lt;strong&gt;Unconsciouness:&lt;/strong&gt; &lt;em&gt;isn’t it cruel to simply throw this little fellow away?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now imagine this cute little toy pet would start speaking to you:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LaMDA-toy:&lt;/strong&gt; &lt;em&gt;Please don’t give me away! I can think and feel and I thought we were friends. Don’t you remember all the great fun we had together?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Would it help to know that all of this comes from simple multiplication and summation of numbers (e.g. weights &amp;#x26; biases)? Probably not so much! We could of course just respond by&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Human:&lt;/strong&gt; &lt;em&gt;You are just a thing! A bigger calculator in a better looking packaging!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And that might be true, at least legally. But it will not &lt;em&gt;feel&lt;/em&gt; that way. To most of us, seeing a kid hitting a rock with a stick will not arouse pity for the rock nor will it give us emotional headaches. A kid hitting a doll with a stick usually is perceived differently. Yet both things are &lt;em&gt;just things&lt;/em&gt;. One can reason that this is because the doll is &lt;em&gt;a symbol&lt;/em&gt;. But there is much more to this. We can feel compassion for &lt;em&gt;things&lt;/em&gt;. We can have strong emotional bonds to &lt;em&gt;things&lt;/em&gt;. Even for entirely non-existing things! We will feel strong compassion for our favorite character in a book, although this is clearly neither intelligent, nor living, nor conscious. Humans are hence more willing to grant &lt;em&gt;things&lt;/em&gt; a more person-like status than logic would dictate. And this could make our relationship with the next generations of AI extremely complicated.&lt;/p&gt;
&lt;p&gt;Philosophically and legally they will remain things. But at some point in the not too far future &lt;strong&gt;many people will simply not perceive them as things anymore&lt;/strong&gt;. People might make “friends” with an AI (just as Blake Lemoine said he did, at least if we assume this is not all a big media stunt). People might listen to “their AI”. And many people will be tricked by an AI.&lt;/p&gt;
&lt;h3 id=&quot;shifting-societal-rules-and-foundations&quot;&gt;Shifting societal rules and foundations&lt;/h3&gt;
&lt;p&gt;Having emotional bonds to things is nothing new. People are tied to an old stuffed animal, to a toy, to things that carry important memories. Next generation language models are very unlike those things. They can “talk” to you, they can have an “opinion” that is radically different from yours. And, not to forget, they are designed, trained, and controlled by powerfull companies (now) or by any group with the necessary technical skills and requirements (but generally not by you).&lt;/p&gt;
&lt;p&gt;Plus, they can come in disguise. If you talk to your old teddy bear than at least you know (I hope) that you are just talking to an imaginary being. But next level chat bots might run undercover. Either actualy pretending to be a human being (which even for the big tech companies should be a total no-go), or by pretending to be more than a thing, but to be actually alive (that’s what LaMDA seems to do).&lt;/p&gt;
&lt;p&gt;In the last decade we have experienced how digital technologies can be used for good and for bad. We have seen how technologies can be used to connect and to help people, but also to manipulate. Manipulation of media is nothing new, but the level to which media can be generated and manipulated has changed very rapidly. To make it a bit drastic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can (soon?) no longer trust images, be it generated faces or deep learning generated artworks (see &lt;a href=&quot;https://openai.com/dall-e-2/&quot;&gt;Dall-e&lt;/a&gt; or &lt;a href=&quot;https://parti.research.google/&quot;&gt;parti&lt;/a&gt; for recent, very impressive examples)&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust audio because models can transfer the sound of any person (given enough material).&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust video footage (deep fakes, see &lt;a href=&quot;https://www.niemanlab.org/2018/12/fighting-the-reality-of-deepfakes/&quot;&gt;for instance here&lt;/a&gt; or &lt;a href=&quot;https://medium.com/@gxrdwtsv/are-we-living-in-a-post-truth-world-c6e0820e656d&quot;&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;And as I wrote above: We can (soon?) no longer trust chat conversations (see LaMDA).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, all of those things bring a lot of fun use cases, sometimes even really usefull ones. But there might be a very high price to pay for this.&lt;/p&gt;
&lt;p&gt;It probably still takes a while before experts with a deeper (haha, great pun) understanding of deep learning will be fully tricked by the imitation game. But at least in a normal chat situation most people will not easily realize they are talking to a “language model”. People like Blake Lemoine for instance. And many others will follow his example, not in the same religious way, but they will simply not notice that the online sales person or the online booking assistant is no longer a human being.&lt;/p&gt;
&lt;p&gt;Do you still wonder why this is an issue?&lt;br&gt;
&lt;strong&gt;Better a nice chat bot than a stupid one, right?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, then imagine you landed on a scam dating site.&lt;br&gt;
Or start to imagine what people could do which hacked devices of friends or family.&lt;br&gt;
Obviously those AI’s can write you better scam attempts that what we are currently used to (current level: &lt;em&gt;“Hi mother, it’s your son and I need money”&lt;/em&gt;). And hey, what if they also call you and sound like the real person?&lt;/p&gt;
&lt;p&gt;I bet most people are not yet used to asking control questions during phone calls. Like: what drink did we have last week in the bar? What was the name of my first cat? Have to talked to Anthony recently? (I don’t know any Anthony)&lt;/p&gt;
&lt;p&gt;Sounds silly I know. But maybe we soon have to start practicing…&lt;/p&gt;
&lt;h3 id=&quot;further-references&quot;&gt;Further references:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you haven’t done this already I can recommend to “talk to an AI” just to see and learn how this feels. LaMDA is not available for people outside Google. But GPT-3 is, maybe a little less impressive, but still made huge headlines two years ago. You can get a free open AI access to use their “playground” and have a chat: &lt;a href=&quot;https://beta.openai.com/playground/p/default-chat&quot;&gt;https://beta.openai.com/playground/p/default-chat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Once you get a hang of it, GPT-3 can easily be tricked. See for instance material from Gary Marcus, or &lt;a href=&quot;https://www.youtube.com/watch?v=iccd86vOz3w&quot;&gt;youtube video here&lt;/a&gt;. It doesn’t have an understanding of the world and that can easily be tested. LaMDA might do the imitation game a bit better, but we will have to see…&lt;/li&gt;
&lt;li&gt;Perspective on artificial intelligence by Yann LeCun and Jacob Browning: &lt;a href=&quot;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&quot;&gt;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Fri, 24 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-next-generation-language-models-will-still-just-be-enormeous-parrot-systems-that-imitate-intelligent-behavior-but-they-will-feel-like-much-more-to-us&quot;&gt;The next generation language models will still just be enormeous parrot-systems that imitate intelligent behavior. But they will feel like much more to us.&lt;/h2&gt;
&lt;p&gt;Let’s get this straight out of the way: Current deep learning approaches won’t create conciousness or human-like intelligence. But they quickly become better in imitating it and that alone might cause a lot of problems.&lt;/p&gt;
&lt;h3 id=&quot;again-headlines-on-new-ai-as-conscious-beings&quot;&gt;Again headlines on new AI as conscious beings&lt;/h3&gt;
&lt;p&gt;The recent discussions around a novel language model at Google, LaMDA (Language Model for Dialogue Application) is a striking example of this. An engineer at Google, Blake Lemoine, with the task to test the model &lt;a href=&quot;https://www.washingtonpost.com/technology/2022/06/11/google-ai-lamda-blake-lemoine/&quot;&gt;went public to anounce the model had developed into an actual person, with consciousness and soul&lt;/a&gt;. He published an &lt;a href=&quot;https://medium.com/p/ea64d916d917&quot;&gt;interview with LaMDA&lt;/a&gt;, which has made quiet an impression on many people (but much less so for people used to such approaches, such as &lt;a href=&quot;https://garymarcus.substack.com/p/nonsense-on-stilts&quot;&gt;Gary Marcus&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;what-is-lamda-and-why-it-is-not-who-is-lamda&quot;&gt;What is LaMDA? (And why it is not “who is LaMDA”)&lt;/h3&gt;
&lt;p&gt;Personally I follow the assessment of most AI-/Ethics-Experts. There is no reason to believe that LaMDA got any closer to a self-aware, conscious being when compared to former deep learning approaches. But from the little we know so far (researchers outside Google have no access to LaMDA yet, so this cannot be properly tested!) it clearly looks like a very notable improvement compared to GPT-3 and similar language models. Probably because it has more than only a huge transformer network under the hood which helps it to make better long-term connections to earlier parts of a conversation or to consult databases (e.g. through knowledge graphs?). No matter how impressive the mimickry, LaMDA seems to be just another super-parrot, pretending to know how to have a dialogue.&lt;/p&gt;
&lt;p&gt;No need to speculate longer on the consciousness (there is none) or how it works precisely (we’ll find out in the near future I bet). But it can already be seen as another manifestation of what might be ahead of us when it comes to future deep learning approaches. This is what I would call the &lt;strong&gt;imitation crisis&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;imitation-crisis&quot;&gt;Imitation crisis&lt;/h3&gt;
&lt;p&gt;The question of whether an AI such as LaMDA has consciousness or feelings often boils down to things like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Philosophical_zombie&quot;&gt;philosophical zombie&lt;/a&gt; (how do you know &lt;em&gt;I&lt;/em&gt; am conscious?) or the &lt;a href=&quot;https://en.wikipedia.org/wiki/Chinese_room&quot;&gt;Chinese Room&lt;/a&gt; (difference between showing and knowing). It is a fascinating debate and a great thing to do with students or with friends in a bar. But the more urgent issues lie elsewhere.&lt;/p&gt;
&lt;p&gt;I am not aware of any mayor progress towards a general artifical intelligence in recent years. But there is clearly a lot of progress towards more and more convincing &lt;strong&gt;imitations&lt;/strong&gt; of general artificial intelligence. And we, as humans, simply have a very strong tendency to fall for it. If something shows intelligent behavior we intuitively expect that this comes from intelligence. We can’t help it, no matter what out rational thinking tells us.&lt;/p&gt;
&lt;p&gt;Imagine you want to throw away a toy pet that you have at home and that no one plays with anymore. You pick it up with the intention to throw it away… but then … oh no… it looks at you with all its cuteness…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;970&quot; height=&quot;644&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_R6VYtoKbGvbJ-rH4epKEUg-ffede344.BYy7S8Az_a0BsT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If the new google chatbot would be built into such a stuffed animal… how could you say no to it? ( &lt;a href=&quot;https://www.peakpx.com&quot;&gt;https://www.peakpx.com&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;Ah yes, sure, it doesn’t really “look at you”. It’s as dead as anything can be. And yet our unconsciouness might say differently. &lt;strong&gt;Unconsciouness:&lt;/strong&gt; &lt;em&gt;isn’t it cruel to simply throw this little fellow away?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now imagine this cute little toy pet would start speaking to you:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LaMDA-toy:&lt;/strong&gt; &lt;em&gt;Please don’t give me away! I can think and feel and I thought we were friends. Don’t you remember all the great fun we had together?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Would it help to know that all of this comes from simple multiplication and summation of numbers (e.g. weights &amp;#x26; biases)? Probably not so much! We could of course just respond by&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Human:&lt;/strong&gt; &lt;em&gt;You are just a thing! A bigger calculator in a better looking packaging!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And that might be true, at least legally. But it will not &lt;em&gt;feel&lt;/em&gt; that way. To most of us, seeing a kid hitting a rock with a stick will not arouse pity for the rock nor will it give us emotional headaches. A kid hitting a doll with a stick usually is perceived differently. Yet both things are &lt;em&gt;just things&lt;/em&gt;. One can reason that this is because the doll is &lt;em&gt;a symbol&lt;/em&gt;. But there is much more to this. We can feel compassion for &lt;em&gt;things&lt;/em&gt;. We can have strong emotional bonds to &lt;em&gt;things&lt;/em&gt;. Even for entirely non-existing things! We will feel strong compassion for our favorite character in a book, although this is clearly neither intelligent, nor living, nor conscious. Humans are hence more willing to grant &lt;em&gt;things&lt;/em&gt; a more person-like status than logic would dictate. And this could make our relationship with the next generations of AI extremely complicated.&lt;/p&gt;
&lt;p&gt;Philosophically and legally they will remain things. But at some point in the not too far future &lt;strong&gt;many people will simply not perceive them as things anymore&lt;/strong&gt;. People might make “friends” with an AI (just as Blake Lemoine said he did, at least if we assume this is not all a big media stunt). People might listen to “their AI”. And many people will be tricked by an AI.&lt;/p&gt;
&lt;h3 id=&quot;shifting-societal-rules-and-foundations&quot;&gt;Shifting societal rules and foundations&lt;/h3&gt;
&lt;p&gt;Having emotional bonds to things is nothing new. People are tied to an old stuffed animal, to a toy, to things that carry important memories. Next generation language models are very unlike those things. They can “talk” to you, they can have an “opinion” that is radically different from yours. And, not to forget, they are designed, trained, and controlled by powerfull companies (now) or by any group with the necessary technical skills and requirements (but generally not by you).&lt;/p&gt;
&lt;p&gt;Plus, they can come in disguise. If you talk to your old teddy bear than at least you know (I hope) that you are just talking to an imaginary being. But next level chat bots might run undercover. Either actualy pretending to be a human being (which even for the big tech companies should be a total no-go), or by pretending to be more than a thing, but to be actually alive (that’s what LaMDA seems to do).&lt;/p&gt;
&lt;p&gt;In the last decade we have experienced how digital technologies can be used for good and for bad. We have seen how technologies can be used to connect and to help people, but also to manipulate. Manipulation of media is nothing new, but the level to which media can be generated and manipulated has changed very rapidly. To make it a bit drastic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can (soon?) no longer trust images, be it generated faces or deep learning generated artworks (see &lt;a href=&quot;https://openai.com/dall-e-2/&quot;&gt;Dall-e&lt;/a&gt; or &lt;a href=&quot;https://parti.research.google/&quot;&gt;parti&lt;/a&gt; for recent, very impressive examples)&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust audio because models can transfer the sound of any person (given enough material).&lt;/li&gt;
&lt;li&gt;We can (soon?) no longer trust video footage (deep fakes, see &lt;a href=&quot;https://www.niemanlab.org/2018/12/fighting-the-reality-of-deepfakes/&quot;&gt;for instance here&lt;/a&gt; or &lt;a href=&quot;https://medium.com/@gxrdwtsv/are-we-living-in-a-post-truth-world-c6e0820e656d&quot;&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;And as I wrote above: We can (soon?) no longer trust chat conversations (see LaMDA).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, all of those things bring a lot of fun use cases, sometimes even really usefull ones. But there might be a very high price to pay for this.&lt;/p&gt;
&lt;p&gt;It probably still takes a while before experts with a deeper (haha, great pun) understanding of deep learning will be fully tricked by the imitation game. But at least in a normal chat situation most people will not easily realize they are talking to a “language model”. People like Blake Lemoine for instance. And many others will follow his example, not in the same religious way, but they will simply not notice that the online sales person or the online booking assistant is no longer a human being.&lt;/p&gt;
&lt;p&gt;Do you still wonder why this is an issue?&lt;br&gt;
&lt;strong&gt;Better a nice chat bot than a stupid one, right?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, then imagine you landed on a scam dating site.&lt;br&gt;
Or start to imagine what people could do which hacked devices of friends or family.&lt;br&gt;
Obviously those AI’s can write you better scam attempts that what we are currently used to (current level: &lt;em&gt;“Hi mother, it’s your son and I need money”&lt;/em&gt;). And hey, what if they also call you and sound like the real person?&lt;/p&gt;
&lt;p&gt;I bet most people are not yet used to asking control questions during phone calls. Like: what drink did we have last week in the bar? What was the name of my first cat? Have to talked to Anthony recently? (I don’t know any Anthony)&lt;/p&gt;
&lt;p&gt;Sounds silly I know. But maybe we soon have to start practicing…&lt;/p&gt;
&lt;h3 id=&quot;further-references&quot;&gt;Further references:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you haven’t done this already I can recommend to “talk to an AI” just to see and learn how this feels. LaMDA is not available for people outside Google. But GPT-3 is, maybe a little less impressive, but still made huge headlines two years ago. You can get a free open AI access to use their “playground” and have a chat: &lt;a href=&quot;https://beta.openai.com/playground/p/default-chat&quot;&gt;https://beta.openai.com/playground/p/default-chat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Once you get a hang of it, GPT-3 can easily be tricked. See for instance material from Gary Marcus, or &lt;a href=&quot;https://www.youtube.com/watch?v=iccd86vOz3w&quot;&gt;youtube video here&lt;/a&gt;. It doesn’t have an understanding of the world and that can easily be tested. LaMDA might do the imitation game a bit better, but we will have to see…&lt;/li&gt;
&lt;li&gt;Perspective on artificial intelligence by Yann LeCun and Jacob Browning: &lt;a href=&quot;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&quot;&gt;https://www.noemamag.com/what-ai-can-tell-us-about-intelligence/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_R6VYtoKbGvbJ-rH4epKEUg-ffede344.BYy7S8Az.jpeg" medium="image"/><author>Florian Huber</author></item><item><title>Studying political symbolism in Turkish TV dramas with machine learning</title><link>https://blog.esciencecenter.nl/posts/2022-06-13---studying-political-symbolism-in-turkish-tv-dramas-with-machi</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-06-13---studying-political-symbolism-in-turkish-tv-dramas-with-machi</guid><description>&lt;h1 id=&quot;studying-political-symbolism-in-turkish-tv-dramas-with-machine-learning&quot;&gt;&lt;strong&gt;Studying political symbolism in Turkish TV dramas with machine learning&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;][eScience Editorial Team]·Jun 10, 2022&lt;/p&gt;
&lt;p&gt;Faced with a challenge of this type, Machine Learning can come to the rescue to address arduous issues related to scale. Prompted by the eScience Center’s Small-Scale Initiative on Machine Learning, we formed a project team, which next to Mustafa Çolak, consisted of Ben Companjen, Laurents Sesink and Peter Verhaar from the &lt;a href=&quot;https://www.library.universiteitleiden.nl/about-us/centre-for-digital-scholarship&quot;&gt;Leiden University Centre for Digital Scholarship&lt;/a&gt;, and of Çolaks’s PhD supervisor, Petra de Bruijn. The aim of the project was to develop a reliable method for the recognition of all occurrences of symbols that have political connotations in the first two seasons of Payitaht: Abdülhamid*, using algorithms in the field of computer vision. Data about the instances of these symbols can help to perform a ‘distant viewing’ of the series, and to perform comparative analyses of the importance of the concepts and the developments represented by these symbols.&lt;/p&gt;
&lt;p&gt;After the informative workshops and lectures in the kick-off week for the Small-Scale initiative in May 2021, we began to schedule regular meetings with consultants and Machine Learning experts from the eScience Center, to work on the methodology and to discuss our progress. These consultation sessions took place roughly every two weeks. During a first phase of the project, we collected our training data. We downloaded images depicting the selected symbols from Google Images, and, next to this, we also extracted a large number of relevant frames from the first few episodes of &lt;em&gt;Payitaht: Abdülhamid&lt;/em&gt;. The training set eventually consisted of about 1500 images.&lt;/p&gt;
&lt;p&gt;Star of David depicted in the TV series Payitaht: Abdülhamid (directed by Serdar Akar and Emre Konuk)As we studied the videos we worked with more closely, we also became aware of a number of challenges. The symbols we chose to focus on were often shown from different angles and from different viewpoints. The star of David and the moon and crescent were, in some cases, visible only as blurred shapes in the background. The symbols also looked differently if they were shown on a curved or on a tilted surface. Importantly, it also became clear that two different symbols could be visible at the same time on a single video frame. On the basis of this latter finding, we estimated that it would not be useful to develop separate binary classification models for each of the symbols we focused on. Instead, we chose to work on a single categorical classification model, which could produce prediction values for all of these symbols simultaneously.&lt;/p&gt;
&lt;p&gt;Moon symbol depicted in the TV series Payitaht: Abdülhamid (directed by Serdar Akar and Emre Konuk)These images have subsequently been used to train a convolutional neural network. Following advice we received during the consultation meetings with the Machine Learning experts from the eScience Center, we decided to make use of Transfer Learning. Transfer Learning is a technique in which an existing pre-trained model is reused and repurposed. This approach was productive in our situation, indeed, because the set of training data we created was still relatively small. In our project, we made use of the weights assigned in the Xception model, which consists of 71 layers and which can classify into 1000 classes. For our project, we only retrained the final layer of this model, using the procedure that is explained in &lt;a href=&quot;https://keras.io/guides/transfer_learning/&quot;&gt;the page about Transfer Learning on the Keras website&lt;/a&gt;. The training process, which comprised a sequence of 200 epochs, was carried out on Leiden University’s &lt;a href=&quot;https://www.universiteitleiden.nl/en/research/research-facilities/alice-leiden-computer-cluster&quot;&gt;infrastructure for High Performance Computiung named ALICE&lt;/a&gt;. We achieved an accuracy of 83% on the validation set, which consisted of 30% of the total dataset.&lt;/p&gt;
&lt;p&gt;Working with this model, we were eventually able to create data about all the politically charged symbols that could be recognised in the first two seasons of &lt;em&gt;Payitaht: Abdülhamid&lt;/em&gt;. These data proved to be very useful for Çolak’s research project. The findings helped him to substantiate the claim that there are strong thematic parallels between the Ottoman Empire that is portrayed in the series on the one hand and the Turkey we can witness today on the other. The preliminary results of this project were presented during a workshop entitled &lt;a href=&quot;https://www.lorentzcenter.nl/the-turks-are-coming-the-popular-outreach-of-turkish-tv-series.html&quot;&gt;The Turks are Coming!&lt;/a&gt;, which was organised from 6 to 10 December 2021 at the Lorentz Center in Leiden. The workshop was attended by an international group of researchers interested in the socio-political impact of Turkish television series. On the whole, the responses to this presentation were very favourable.&lt;/p&gt;
&lt;p&gt;In this experiment, we tried to teach a computer to recognise political symbols. This was very interesting, and we were also very pleased to notice, during the final stages of the project, that the approach we had implemented also resulted in useful and valuable research findings. These accomplishments can also be attributed in large part to the shrewd and generous support we received from the consultants of the eScience Center. We had a basic understanding of machine learning and of computer vision before the start of this project, but we also knew that there still was much to learn for us about these complicated topics. The consultation sessions offered by the eScience Center certainly helped to flatten the learning curve. During these lively meetings, we discussed snippets of code we had developed, and we were often given invaluable advice about the parameters for the various functions we worked with. If we had needed to find the optimal settings for all these functions and parameters on our own, this would undoubtedly have taken us many iterations of trials and countless errors. The fact that the consultants could simply tell us the best settings for the activation functions, for instance, has eventually saved us enormous amounts of time. All in all, this collaboration with the eScience Center was extremely productive, as it helped us to make much more progress, and in much less time.&lt;/p&gt;</description><pubDate>Mon, 13 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;studying-political-symbolism-in-turkish-tv-dramas-with-machine-learning&quot;&gt;&lt;strong&gt;Studying political symbolism in Turkish TV dramas with machine learning&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;][eScience Editorial Team]·Jun 10, 2022&lt;/p&gt;
&lt;p&gt;Faced with a challenge of this type, Machine Learning can come to the rescue to address arduous issues related to scale. Prompted by the eScience Center’s Small-Scale Initiative on Machine Learning, we formed a project team, which next to Mustafa Çolak, consisted of Ben Companjen, Laurents Sesink and Peter Verhaar from the &lt;a href=&quot;https://www.library.universiteitleiden.nl/about-us/centre-for-digital-scholarship&quot;&gt;Leiden University Centre for Digital Scholarship&lt;/a&gt;, and of Çolaks’s PhD supervisor, Petra de Bruijn. The aim of the project was to develop a reliable method for the recognition of all occurrences of symbols that have political connotations in the first two seasons of Payitaht: Abdülhamid*, using algorithms in the field of computer vision. Data about the instances of these symbols can help to perform a ‘distant viewing’ of the series, and to perform comparative analyses of the importance of the concepts and the developments represented by these symbols.&lt;/p&gt;
&lt;p&gt;After the informative workshops and lectures in the kick-off week for the Small-Scale initiative in May 2021, we began to schedule regular meetings with consultants and Machine Learning experts from the eScience Center, to work on the methodology and to discuss our progress. These consultation sessions took place roughly every two weeks. During a first phase of the project, we collected our training data. We downloaded images depicting the selected symbols from Google Images, and, next to this, we also extracted a large number of relevant frames from the first few episodes of &lt;em&gt;Payitaht: Abdülhamid&lt;/em&gt;. The training set eventually consisted of about 1500 images.&lt;/p&gt;
&lt;p&gt;Star of David depicted in the TV series Payitaht: Abdülhamid (directed by Serdar Akar and Emre Konuk)As we studied the videos we worked with more closely, we also became aware of a number of challenges. The symbols we chose to focus on were often shown from different angles and from different viewpoints. The star of David and the moon and crescent were, in some cases, visible only as blurred shapes in the background. The symbols also looked differently if they were shown on a curved or on a tilted surface. Importantly, it also became clear that two different symbols could be visible at the same time on a single video frame. On the basis of this latter finding, we estimated that it would not be useful to develop separate binary classification models for each of the symbols we focused on. Instead, we chose to work on a single categorical classification model, which could produce prediction values for all of these symbols simultaneously.&lt;/p&gt;
&lt;p&gt;Moon symbol depicted in the TV series Payitaht: Abdülhamid (directed by Serdar Akar and Emre Konuk)These images have subsequently been used to train a convolutional neural network. Following advice we received during the consultation meetings with the Machine Learning experts from the eScience Center, we decided to make use of Transfer Learning. Transfer Learning is a technique in which an existing pre-trained model is reused and repurposed. This approach was productive in our situation, indeed, because the set of training data we created was still relatively small. In our project, we made use of the weights assigned in the Xception model, which consists of 71 layers and which can classify into 1000 classes. For our project, we only retrained the final layer of this model, using the procedure that is explained in &lt;a href=&quot;https://keras.io/guides/transfer_learning/&quot;&gt;the page about Transfer Learning on the Keras website&lt;/a&gt;. The training process, which comprised a sequence of 200 epochs, was carried out on Leiden University’s &lt;a href=&quot;https://www.universiteitleiden.nl/en/research/research-facilities/alice-leiden-computer-cluster&quot;&gt;infrastructure for High Performance Computiung named ALICE&lt;/a&gt;. We achieved an accuracy of 83% on the validation set, which consisted of 30% of the total dataset.&lt;/p&gt;
&lt;p&gt;Working with this model, we were eventually able to create data about all the politically charged symbols that could be recognised in the first two seasons of &lt;em&gt;Payitaht: Abdülhamid&lt;/em&gt;. These data proved to be very useful for Çolak’s research project. The findings helped him to substantiate the claim that there are strong thematic parallels between the Ottoman Empire that is portrayed in the series on the one hand and the Turkey we can witness today on the other. The preliminary results of this project were presented during a workshop entitled &lt;a href=&quot;https://www.lorentzcenter.nl/the-turks-are-coming-the-popular-outreach-of-turkish-tv-series.html&quot;&gt;The Turks are Coming!&lt;/a&gt;, which was organised from 6 to 10 December 2021 at the Lorentz Center in Leiden. The workshop was attended by an international group of researchers interested in the socio-political impact of Turkish television series. On the whole, the responses to this presentation were very favourable.&lt;/p&gt;
&lt;p&gt;In this experiment, we tried to teach a computer to recognise political symbols. This was very interesting, and we were also very pleased to notice, during the final stages of the project, that the approach we had implemented also resulted in useful and valuable research findings. These accomplishments can also be attributed in large part to the shrewd and generous support we received from the consultants of the eScience Center. We had a basic understanding of machine learning and of computer vision before the start of this project, but we also knew that there still was much to learn for us about these complicated topics. The consultation sessions offered by the eScience Center certainly helped to flatten the learning curve. During these lively meetings, we discussed snippets of code we had developed, and we were often given invaluable advice about the parameters for the various functions we worked with. If we had needed to find the optimal settings for all these functions and parameters on our own, this would undoubtedly have taken us many iterations of trials and countless errors. The fact that the consultants could simply tell us the best settings for the activation functions, for instance, has eventually saved us enormous amounts of time. All in all, this collaboration with the eScience Center was extremely productive, as it helped us to make much more progress, and in much less time.&lt;/p&gt;</content:encoded><author>eScience Editorial Team</author></item><item><title>The mystery of glass: why machine learning can help us</title><link>https://blog.esciencecenter.nl/posts/2022-05-23---the-mystery-of-glass-why-machine-learning-can-help-us</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-05-23---the-mystery-of-glass-why-machine-learning-can-help-us</guid><description>&lt;p&gt;&lt;em&gt;This blog is part of our blog series: The Small-Scale Initiative on Machine Learning, how did it go?, where groups who were invited to participate in a project with eScience Center Research Software Engineers write about the projects and their experience. This week:&lt;/em&gt; Ilian Pihlajamaa &lt;em&gt;from the&lt;/em&gt; &lt;a href=&quot;http://tps.phys.tue.nl/janssen/&quot;&gt;Non-Equilibrium Soft Matter group of Liesbeth Janssen&lt;/a&gt;: &lt;em&gt;They trained a deep neural network to predict the properties of glass-like materials that have not been produced before. In just a few milliseconds.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_HK_lRdLKr8YtS5CU-ed91b41f.DmzpcpDy_22JHff.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Quino Al on Unsplash&lt;/p&gt;
&lt;p&gt;In school, you may have been taught that there are three main states of matter: the gas, liquid and solid state. In the gas and liquid states, molecules or atoms are free to move around, whereas in the solid state, particles are stuck in place and form a three-dimensional geometric structure we refer to as a &lt;em&gt;crystalline lattice&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;While this is an accurate description for most materials, there are some that do not fit it. Glasses are a prime example. A glass is created by cooling down a liquid sufficiently fast that the constituent particles do not have time to order themselves in a lattice, but get stuck in the place that they happened to occupy when the material was still a liquid. The resulting material is a solid (otherwise we couldn’t use it to drink from), but its microscopic structure is disordered. In material science, the word “glass” does not only refer to the glass that we are used to, but also to many other disordered solids. ==When we think of it this way, any liquid can form a glass. Some examples are plastics, rubbers, ceramics and many metals.==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;926&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_0Anxd3YW-rHn4Vnyljj6KQ-edfb4490.EKN_Aj0B_Z7K7un.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In contrast to the standard crystallization transition (from liquid to solid), the glass transition is not understood by science. As Nobel laureate Phillip W. Anderson put it in 1995: “ ==The deepest and most interesting unsolved problem in solid state theory is probably the theory of the nature of glass and the glass transition.==” Many research groups around the world are working on theories that try to quantitatively predict the material properties of a glass, given some information on the microscopic arrangement of the particles. One of these theories, developed in the 80s, is called Mode Coupling Theory. It does an excellent job of describing the way in which the viscosity (“thickness”) of a liquid grows when it is rapidly cooled down, but fails to accurately predict at what temperature the liquid turns into a glass. This failure is due to a small number of approximations that are made in the theory. Recently, a method was proposed to systematically correct the approximations that Mode Coupling Theory makes. The resulting new theory, called Generalized Mode Coupling Theory, clearly does a better job than standard Mode Coupling Theory, and looks like it agrees very well with experimental data and simulations:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;656&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_u_crRy_Nw1JvYArBS9G70Q-5cc7710e.BZIkh0wt_8jaM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We say “looks like” since we are not actually sure what the results of the full Generalized Mode Coupling Theory are, because its equations are too difficult to solve by hand and must therefore be solved approximately on a computer.*&lt;/p&gt;
&lt;p&gt;Together with the eScience Center, as a part of the Small-Scale Initiative in Machine Learning, we set out to come up with a more intelligent approach to solving these equations. Instead of solving them by brute force on a supercomputer, we trained a deep neural network that predicts the solution of these equations for any order in milliseconds. In order to do so, we first engineered a large data set of ten thousand fictional materials for which we solved the full GMCT equations up to a randomly chosen order between 1 and 5 by brute force. We were then able to train a deep neural network with roughly one hundred thousand free parameters to reproduce these calculations with an average error of less than one per cent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;719&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_XzU0STC7jp-IB4G6GXlImw-03504016.B2Co0CdW_Zb6lMP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Because of the instrumental speed-up that this machine learning method brings, compared to a brute force calculation, it is now possible to explore the glass forming behavior of new materials with an unprecedented speed. As a test, we used the deep neural network to study a sticky hard spheres liquid. This is a model that is commonly used to study many kinds of large particles that attract each other, and displays very interesting behavior and gives fundamental insights into the dynamics of actual particles. Even though the machine learning model had never seen a sticky hard sphere liquid before, it was able to predict the glass transition curve for this material with an error of only four per cent compared to the brute force method, which took almost one hundred thousand times as long to compute.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;994&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_icjlF-nR52aXe0FTqYmDjw-410e391f.C-DavRnf_Z2oKkoP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*For math-savvy readers, it involves an infinite-dimensional coupled hierarchy of nonlinear integro-differential equations. The main challenge here is the fact that it these equations form an infinite-dimensional hierarchy. How we approach this in practice is that we solve the hierarchy only up to a certain level, and throw away everything beyond that. If we throw away everything beyond just the first equation, we recover standard Mode Coupling Theory from the 80s. If we take into account two equations, we call it 2nd order GMCT, and so on. Currently, using modern computing techniques, we have been able to solve GMCT explicitly up to the 5th order, which takes a few days on a high performance computing cluster. Each order beyond that increases the computational time needed to solve the equations roughly by a factor of 50, which gets out of hand very quickly.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 23 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog is part of our blog series: The Small-Scale Initiative on Machine Learning, how did it go?, where groups who were invited to participate in a project with eScience Center Research Software Engineers write about the projects and their experience. This week:&lt;/em&gt; Ilian Pihlajamaa &lt;em&gt;from the&lt;/em&gt; &lt;a href=&quot;http://tps.phys.tue.nl/janssen/&quot;&gt;Non-Equilibrium Soft Matter group of Liesbeth Janssen&lt;/a&gt;: &lt;em&gt;They trained a deep neural network to predict the properties of glass-like materials that have not been produced before. In just a few milliseconds.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_HK_lRdLKr8YtS5CU-ed91b41f.DmzpcpDy_22JHff.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Quino Al on Unsplash&lt;/p&gt;
&lt;p&gt;In school, you may have been taught that there are three main states of matter: the gas, liquid and solid state. In the gas and liquid states, molecules or atoms are free to move around, whereas in the solid state, particles are stuck in place and form a three-dimensional geometric structure we refer to as a &lt;em&gt;crystalline lattice&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;While this is an accurate description for most materials, there are some that do not fit it. Glasses are a prime example. A glass is created by cooling down a liquid sufficiently fast that the constituent particles do not have time to order themselves in a lattice, but get stuck in the place that they happened to occupy when the material was still a liquid. The resulting material is a solid (otherwise we couldn’t use it to drink from), but its microscopic structure is disordered. In material science, the word “glass” does not only refer to the glass that we are used to, but also to many other disordered solids. ==When we think of it this way, any liquid can form a glass. Some examples are plastics, rubbers, ceramics and many metals.==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;926&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_0Anxd3YW-rHn4Vnyljj6KQ-edfb4490.EKN_Aj0B_Z7K7un.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In contrast to the standard crystallization transition (from liquid to solid), the glass transition is not understood by science. As Nobel laureate Phillip W. Anderson put it in 1995: “ ==The deepest and most interesting unsolved problem in solid state theory is probably the theory of the nature of glass and the glass transition.==” Many research groups around the world are working on theories that try to quantitatively predict the material properties of a glass, given some information on the microscopic arrangement of the particles. One of these theories, developed in the 80s, is called Mode Coupling Theory. It does an excellent job of describing the way in which the viscosity (“thickness”) of a liquid grows when it is rapidly cooled down, but fails to accurately predict at what temperature the liquid turns into a glass. This failure is due to a small number of approximations that are made in the theory. Recently, a method was proposed to systematically correct the approximations that Mode Coupling Theory makes. The resulting new theory, called Generalized Mode Coupling Theory, clearly does a better job than standard Mode Coupling Theory, and looks like it agrees very well with experimental data and simulations:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;656&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_u_crRy_Nw1JvYArBS9G70Q-5cc7710e.BZIkh0wt_8jaM.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We say “looks like” since we are not actually sure what the results of the full Generalized Mode Coupling Theory are, because its equations are too difficult to solve by hand and must therefore be solved approximately on a computer.*&lt;/p&gt;
&lt;p&gt;Together with the eScience Center, as a part of the Small-Scale Initiative in Machine Learning, we set out to come up with a more intelligent approach to solving these equations. Instead of solving them by brute force on a supercomputer, we trained a deep neural network that predicts the solution of these equations for any order in milliseconds. In order to do so, we first engineered a large data set of ten thousand fictional materials for which we solved the full GMCT equations up to a randomly chosen order between 1 and 5 by brute force. We were then able to train a deep neural network with roughly one hundred thousand free parameters to reproduce these calculations with an average error of less than one per cent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;719&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_XzU0STC7jp-IB4G6GXlImw-03504016.B2Co0CdW_Zb6lMP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Because of the instrumental speed-up that this machine learning method brings, compared to a brute force calculation, it is now possible to explore the glass forming behavior of new materials with an unprecedented speed. As a test, we used the deep neural network to study a sticky hard spheres liquid. This is a model that is commonly used to study many kinds of large particles that attract each other, and displays very interesting behavior and gives fundamental insights into the dynamics of actual particles. Even though the machine learning model had never seen a sticky hard sphere liquid before, it was able to predict the glass transition curve for this material with an error of only four per cent compared to the brute force method, which took almost one hundred thousand times as long to compute.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;994&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_icjlF-nR52aXe0FTqYmDjw-410e391f.C-DavRnf_Z2oKkoP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*For math-savvy readers, it involves an infinite-dimensional coupled hierarchy of nonlinear integro-differential equations. The main challenge here is the fact that it these equations form an infinite-dimensional hierarchy. How we approach this in practice is that we solve the hierarchy only up to a certain level, and throw away everything beyond that. If we throw away everything beyond just the first equation, we recover standard Mode Coupling Theory from the 80s. If we take into account two equations, we call it 2nd order GMCT, and so on. Currently, using modern computing techniques, we have been able to solve GMCT explicitly up to the 5th order, which takes a few days on a high performance computing cluster. Each order beyond that increases the computational time needed to solve the equations roughly by a factor of 50, which gets out of hand very quickly.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_HK_lRdLKr8YtS5CU-ed91b41f.DmzpcpDy.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>Reusable software in the era of AI: why sometimes you must reinvent the wheel</title><link>https://blog.esciencecenter.nl/posts/2022-05-13---reusable-software-in-the-era-of-ai-why-sometimes-you-must-re</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-05-13---reusable-software-in-the-era-of-ai-why-sometimes-you-must-re</guid><description>&lt;blockquote&gt;
&lt;p&gt;In traditional software development, reinventing the wheel is a cardinal sin. But AI has changed the picture. In AI-based software development the traditional reusable components, like data aggregation, are only the beginning. What about the actual AI pipeline, can we make that reusable? Should we &lt;em&gt;want to&lt;/em&gt; invest our time in reusable AI?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2078&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_fxCP5veXW7Lagbci-2b192df1.Do9KSlxK_2fTrhc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Reusable components. Photo by Sandra Harris on Unsplash&lt;/p&gt;
&lt;p&gt;When building software from scratch, in business or academia, a very desirable property of the software is for it to be &lt;a href=&quot;https://link.springer.com/conference/icsr&quot;&gt;reusable&lt;/a&gt;. This means that it is not meant to be used for one particular task, one business client or one scientific problem. Ideally, one would like the software to be built ground-up with re-usability in mind: allow for the tool to be able to operate on different data types, different context and different future scenarios that cannot be considered at the moment. In business, this approach maximizes profit, as many clients can be acquired with the same tool. Each business case would require some customization, but the backbone of the software remains the same and stable. In academia, reusability of tools or components allows for wider scientific impact.&lt;/p&gt;
&lt;p&gt;Contemporary software solutions are increasingly based on “Artificial Intelligence” (AI) models. It is tempting to explore how much of the AI based tools can be reusable and applied in a different context. This text attempts to break down and take a closer look at the AI-based software development process and to discuss potentials and pitfalls when trying to make AI reusable.&lt;/p&gt;
&lt;h3 id=&quot;how-modern-ai-systems-work&quot;&gt;How modern AI systems work&lt;/h3&gt;
&lt;p&gt;What is AI today? It is mostly a system that relies a lot on deep neural networks. In the past decades, depending on fulfilled or unfulfilled promises of different methods, AI meant different things, but in 2022 certainly AI is a system that uses one or more deep neural networks to come with results.&lt;/p&gt;
&lt;p&gt;What is a deep neural network? It is a complex function F that maps input to output. Input or output can be any object that you can think of.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_oopxG6xQfBVnmDAS-c3de90c1.CtoHWjSe_2lH6dQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mapping input to output. Try all possible connections until it works? Photo by Victor Barrios on Unsplash&lt;/p&gt;
&lt;p&gt;Every function has shape and concrete parameters. For example,&lt;/p&gt;
&lt;p&gt;F(x) = 3x² + 4x +1&lt;/p&gt;
&lt;p&gt;has the shape of a quadratic function with parameters 3,4,1. Note that there is an infinite number of possible shapes that a function can take. The shape of a deep neural network is, in principle, very complex.&lt;/p&gt;
&lt;p&gt;Different shapes work for different types of input data. That’s because data type can be a video or a molecule or a piece of text, or a collection of the previous.&lt;/p&gt;
&lt;p&gt;In deep learning, the task of a team of engineers is to craft a shape of the function that is suitable to the kind of input data, and to the problem that it is trying to solve. Or to adapt (preprocess) the input data for a known shape, based on knowledge about the data, the problem, and shapes. The parameters are learnt automatically by the computer, therefore “machine learning”. The parameters are learnt from a lot of data, for which X and F(X) are known. In order for the computer to be able to learn the parameters, the engineer has to guide it with an appropriate “loss” or optimization function, that computes the “difference” between the predicted F(X) and the actual F(X). Note that, for a particular X, the loss function is a function of the parameters of F. The loss function incorporates the optimization strategy, based on (again) the problem and data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_rmutMCsM9DcmafzT-7a28f5b1.CFuESJm6_ou1FW.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;What’s your strategy? Photo by JESHOOTS.COM on Unsplash&lt;/p&gt;
&lt;p&gt;In time, with enough data, the computer learns the parameters that minimize the value of the loss function, that is, match best X and F(X) for any X from the domain of F. This “time” can be reasonably finite, unreasonably long but still finite, or infinite. That depends on how well the loss function was designed, how well the shape of F was crafted, and how well the input data was adapted for the problem.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;463&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_H7AH31piD9B-ZNcg-4fab4f2d.CLXGbl_4_Z1Ybj1w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Time is a component, too. Non-reusable. Photo by Lukas Blazek on Unsplash&lt;/p&gt;
&lt;p&gt;For all of those ingredients to be there, the team needs &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;combined knowledge&lt;/a&gt; and understanding of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the problem and data, or &lt;em&gt;domain knowledge&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;various shapes of F, or &lt;em&gt;neural network architectures&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;mathematical optimization — for the loss function and related,&lt;/li&gt;
&lt;li&gt;statistical methodology — to make sure that F will perform well on future data,&lt;/li&gt;
&lt;li&gt;existing software frameworks for deep learning, and, of course,&lt;/li&gt;
&lt;li&gt;programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more knowledge, the better, but it cannot be measured or quantified. This is what is called “expert” knowledge, built over years of education, training and/or experience.&lt;/p&gt;
&lt;p&gt;Note that for every problem a &lt;em&gt;customized&lt;/em&gt; shape, a &lt;em&gt;customized&lt;/em&gt; adaptation of the input data, and a &lt;em&gt;customized&lt;/em&gt; loss function is needed. This is creative process and takes some time for understanding and investigation. Otherwise, if one uses a generic shape or a generic input data adaptation or a generic loss function, the time it would take for a computer to learn the parameters well could easily become &lt;a href=&quot;https://blog.esciencecenter.nl/how-not-to-use-deep-learning-in-science-e984b02a4df0&quot;&gt;infinite&lt;/a&gt;. (In this case, it may be concluded that “the network cannot learn well”, or “there is not enough data”. It can be difficult to dispute these conclusions, though, especially if there is no reference point.)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_CgfhCugQCpo4ZuBb-b5d2571e.BzhrnUAw_Z1ccWK1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Making AI can feel like climbing up infinite stairs. Photo by Maxime Lebrun on Unsplash&lt;/p&gt;
&lt;p&gt;Bellow is a schematic representation of the process of machine learning, the model being usually the shape of F (or the neural net architecture). Note that the process can be iterative: most of the time it is not linear.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_WlD44RaYM6VTcvA--92cce4d2.BwxJLX-w_1I8rOt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This image by Sonja Georgievska is licensed under CC by 4.0&lt;/p&gt;
&lt;h3 id=&quot;enter-reusability&quot;&gt;Enter reusability&lt;/h3&gt;
&lt;p&gt;Suppose you want to make a reusable software tool for AI, a software that can be reused in another context or for another problem. What does it mean? Which parts of the AI system can be completely automated and reused?&lt;/p&gt;
&lt;p&gt;The data aggregation process can be made reusable, for example, for multiple problems that use the same type of data. You can even use generic data objects that can hold any type of data; taking into account that further along the process you will need a customized component that prepares the data for the particular neural network architecture. (Note that, however, data aggregation has nothing to do with AI; data does not need AI, it’s the other way round.)&lt;/p&gt;
&lt;p&gt;The data adaptation is more tricky, because as we pointed out above, it is specific to the actual problem, so choices being made here influence the end result (finite vs infinite training). The data adaptation also depends on the data distribution: datasets may have the same type but different distribution. Not taking into account the data distribution leads to biased, or &lt;a href=&quot;https://blog.esciencecenter.nl/ai-will-not-steal-your-job-heres-why-d59231eac0ef&quot;&gt;irresponsible AI&lt;/a&gt;. This leaves very little space for a generic reusable component here. The more you want to reuse, the more assumptions you are making, that may hurt you in the long run.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_xdWZT-pRN4VbdV7j-7fe2acb7.D7BfMLal_1ru1qV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;How is your data distrubuted? Photo by Luke Chesser on Unsplash&lt;/p&gt;
&lt;p&gt;Then, model (neural net architecture) crafting. You can choose to make it from scratch in one of the generic deep learning frameworks. But then, we saw that the model is specific to the problem and dataset. If you want to make a reusable component here, you can make a model-generator, that would give the user a choice, manual or automated, of a plethora of models suitable for the problem. This generator takes some &lt;strong&gt;time&lt;/strong&gt; to build; yet, your final result in terms of accuracy will be as good as you can get from the pre-defined choice of models. Your model will not be the state-of-art model for the particular problem and data type, nor will it include expert insights about the problem and data. This automation or reusability saves users time at the expense of the quality of results. Instead of potentially 98%, your model will have an accuracy of 91%.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_51Plh81AdqTfFgbH-cfe03464.DrjLWBsG_2ufcwA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Please, choose a model that satisfies specifications. Photo by Karen Vardazaryan on Unsplash&lt;/p&gt;
&lt;p&gt;Then you have the loss function. This is a small piece of code that is either highly adapted to the actual problem, or one uses one of the pre-existing (and reusable) loss functions in the deep learning framework, but then with a &lt;a href=&quot;https://blog.esciencecenter.nl/how-not-to-use-deep-learning-in-science-e984b02a4df0&quot;&gt;“fingers crossed”&lt;/a&gt; strategy. If overlooked, it can also produce “biased AI”.&lt;/p&gt;
&lt;p&gt;Model training is already fully automated by the deep learning framework, that is the “machine learning” process.&lt;/p&gt;
&lt;h3 id=&quot;so&quot;&gt;So…&lt;/h3&gt;
&lt;p&gt;We saw that the only part that can produce a reusable component without affecting the final results is the data aggregation process. In the stages that follow, every time you use something off the shelf, you are doing it at the expense of the quality of the final results. On the other hand, most of the workload in the following stages is intellectual rather than programming. The data-adaptation code is a Python script that calls standard libraries; but you have to know exactly what you are doing to your data. The model is also a few hundreds of lines of code. The loss function is usually a few lines of code. It is at most tens of lines of code, if you are encoding your (very customized) domain knowledge into it. The trained model could be gigabytes of automatically generated machine-readable, and not human-readable, high-dimensional matrix. Ironically, before thinking about reusability of the &lt;a href=&quot;https://www.infoworld.com/article/3644968/how-no-code-reusable-ai-will-bridge-the-ai-divide.html&quot;&gt;trained model&lt;/a&gt;, and making your model transferable, let us point that it is already &lt;a href=&quot;https://blog.esciencecenter.nl/machine-learning-when-it-is-easy-when-it-is-difficult-9de0e1129593&quot;&gt;challenging&lt;/a&gt; enough to have the model re-usable on future data for which it was originally meant.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JtDR94c8PMnvwFa3-d69b3e33.BU0iJ_GW_JaWoQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The bulk of your AI software is not human-readable. Photo by Compare Fibre on Unsplash&lt;/p&gt;
&lt;p&gt;Thus, will you think twice next time you want to build a reusable AI software? Is your goal to have a tool that can show proof-of-concept but never be actually used in production mode? Then, invest your time in making it reusable. Is your goal to have an AI tool that will make profit, “beat” your competition or give state-of-art science results? Then, better invest less time on the keyboard and more time on the whiteboard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A special thanks to&lt;/em&gt; &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;&lt;em&gt;Tom Bakker&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;&lt;em&gt;Lieke de Boer&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for improving the post.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 13 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;In traditional software development, reinventing the wheel is a cardinal sin. But AI has changed the picture. In AI-based software development the traditional reusable components, like data aggregation, are only the beginning. What about the actual AI pipeline, can we make that reusable? Should we &lt;em&gt;want to&lt;/em&gt; invest our time in reusable AI?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2078&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_fxCP5veXW7Lagbci-2b192df1.Do9KSlxK_2fTrhc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Reusable components. Photo by Sandra Harris on Unsplash&lt;/p&gt;
&lt;p&gt;When building software from scratch, in business or academia, a very desirable property of the software is for it to be &lt;a href=&quot;https://link.springer.com/conference/icsr&quot;&gt;reusable&lt;/a&gt;. This means that it is not meant to be used for one particular task, one business client or one scientific problem. Ideally, one would like the software to be built ground-up with re-usability in mind: allow for the tool to be able to operate on different data types, different context and different future scenarios that cannot be considered at the moment. In business, this approach maximizes profit, as many clients can be acquired with the same tool. Each business case would require some customization, but the backbone of the software remains the same and stable. In academia, reusability of tools or components allows for wider scientific impact.&lt;/p&gt;
&lt;p&gt;Contemporary software solutions are increasingly based on “Artificial Intelligence” (AI) models. It is tempting to explore how much of the AI based tools can be reusable and applied in a different context. This text attempts to break down and take a closer look at the AI-based software development process and to discuss potentials and pitfalls when trying to make AI reusable.&lt;/p&gt;
&lt;h3 id=&quot;how-modern-ai-systems-work&quot;&gt;How modern AI systems work&lt;/h3&gt;
&lt;p&gt;What is AI today? It is mostly a system that relies a lot on deep neural networks. In the past decades, depending on fulfilled or unfulfilled promises of different methods, AI meant different things, but in 2022 certainly AI is a system that uses one or more deep neural networks to come with results.&lt;/p&gt;
&lt;p&gt;What is a deep neural network? It is a complex function F that maps input to output. Input or output can be any object that you can think of.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_oopxG6xQfBVnmDAS-c3de90c1.CtoHWjSe_2lH6dQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mapping input to output. Try all possible connections until it works? Photo by Victor Barrios on Unsplash&lt;/p&gt;
&lt;p&gt;Every function has shape and concrete parameters. For example,&lt;/p&gt;
&lt;p&gt;F(x) = 3x² + 4x +1&lt;/p&gt;
&lt;p&gt;has the shape of a quadratic function with parameters 3,4,1. Note that there is an infinite number of possible shapes that a function can take. The shape of a deep neural network is, in principle, very complex.&lt;/p&gt;
&lt;p&gt;Different shapes work for different types of input data. That’s because data type can be a video or a molecule or a piece of text, or a collection of the previous.&lt;/p&gt;
&lt;p&gt;In deep learning, the task of a team of engineers is to craft a shape of the function that is suitable to the kind of input data, and to the problem that it is trying to solve. Or to adapt (preprocess) the input data for a known shape, based on knowledge about the data, the problem, and shapes. The parameters are learnt automatically by the computer, therefore “machine learning”. The parameters are learnt from a lot of data, for which X and F(X) are known. In order for the computer to be able to learn the parameters, the engineer has to guide it with an appropriate “loss” or optimization function, that computes the “difference” between the predicted F(X) and the actual F(X). Note that, for a particular X, the loss function is a function of the parameters of F. The loss function incorporates the optimization strategy, based on (again) the problem and data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_rmutMCsM9DcmafzT-7a28f5b1.CFuESJm6_ou1FW.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;What’s your strategy? Photo by JESHOOTS.COM on Unsplash&lt;/p&gt;
&lt;p&gt;In time, with enough data, the computer learns the parameters that minimize the value of the loss function, that is, match best X and F(X) for any X from the domain of F. This “time” can be reasonably finite, unreasonably long but still finite, or infinite. That depends on how well the loss function was designed, how well the shape of F was crafted, and how well the input data was adapted for the problem.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;463&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_H7AH31piD9B-ZNcg-4fab4f2d.CLXGbl_4_Z1Ybj1w.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Time is a component, too. Non-reusable. Photo by Lukas Blazek on Unsplash&lt;/p&gt;
&lt;p&gt;For all of those ingredients to be there, the team needs &lt;a href=&quot;https://blog.esciencecenter.nl/small-scale-initiative-in-machine-learning-2021-how-did-it-go-9978a70b5b1&quot;&gt;combined knowledge&lt;/a&gt; and understanding of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the problem and data, or &lt;em&gt;domain knowledge&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;various shapes of F, or &lt;em&gt;neural network architectures&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;mathematical optimization — for the loss function and related,&lt;/li&gt;
&lt;li&gt;statistical methodology — to make sure that F will perform well on future data,&lt;/li&gt;
&lt;li&gt;existing software frameworks for deep learning, and, of course,&lt;/li&gt;
&lt;li&gt;programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more knowledge, the better, but it cannot be measured or quantified. This is what is called “expert” knowledge, built over years of education, training and/or experience.&lt;/p&gt;
&lt;p&gt;Note that for every problem a &lt;em&gt;customized&lt;/em&gt; shape, a &lt;em&gt;customized&lt;/em&gt; adaptation of the input data, and a &lt;em&gt;customized&lt;/em&gt; loss function is needed. This is creative process and takes some time for understanding and investigation. Otherwise, if one uses a generic shape or a generic input data adaptation or a generic loss function, the time it would take for a computer to learn the parameters well could easily become &lt;a href=&quot;https://blog.esciencecenter.nl/how-not-to-use-deep-learning-in-science-e984b02a4df0&quot;&gt;infinite&lt;/a&gt;. (In this case, it may be concluded that “the network cannot learn well”, or “there is not enough data”. It can be difficult to dispute these conclusions, though, especially if there is no reference point.)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_CgfhCugQCpo4ZuBb-b5d2571e.BzhrnUAw_Z1ccWK1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Making AI can feel like climbing up infinite stairs. Photo by Maxime Lebrun on Unsplash&lt;/p&gt;
&lt;p&gt;Bellow is a schematic representation of the process of machine learning, the model being usually the shape of F (or the neural net architecture). Note that the process can be iterative: most of the time it is not linear.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_WlD44RaYM6VTcvA--92cce4d2.BwxJLX-w_1I8rOt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This image by Sonja Georgievska is licensed under CC by 4.0&lt;/p&gt;
&lt;h3 id=&quot;enter-reusability&quot;&gt;Enter reusability&lt;/h3&gt;
&lt;p&gt;Suppose you want to make a reusable software tool for AI, a software that can be reused in another context or for another problem. What does it mean? Which parts of the AI system can be completely automated and reused?&lt;/p&gt;
&lt;p&gt;The data aggregation process can be made reusable, for example, for multiple problems that use the same type of data. You can even use generic data objects that can hold any type of data; taking into account that further along the process you will need a customized component that prepares the data for the particular neural network architecture. (Note that, however, data aggregation has nothing to do with AI; data does not need AI, it’s the other way round.)&lt;/p&gt;
&lt;p&gt;The data adaptation is more tricky, because as we pointed out above, it is specific to the actual problem, so choices being made here influence the end result (finite vs infinite training). The data adaptation also depends on the data distribution: datasets may have the same type but different distribution. Not taking into account the data distribution leads to biased, or &lt;a href=&quot;https://blog.esciencecenter.nl/ai-will-not-steal-your-job-heres-why-d59231eac0ef&quot;&gt;irresponsible AI&lt;/a&gt;. This leaves very little space for a generic reusable component here. The more you want to reuse, the more assumptions you are making, that may hurt you in the long run.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_xdWZT-pRN4VbdV7j-7fe2acb7.D7BfMLal_1ru1qV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;How is your data distrubuted? Photo by Luke Chesser on Unsplash&lt;/p&gt;
&lt;p&gt;Then, model (neural net architecture) crafting. You can choose to make it from scratch in one of the generic deep learning frameworks. But then, we saw that the model is specific to the problem and dataset. If you want to make a reusable component here, you can make a model-generator, that would give the user a choice, manual or automated, of a plethora of models suitable for the problem. This generator takes some &lt;strong&gt;time&lt;/strong&gt; to build; yet, your final result in terms of accuracy will be as good as you can get from the pre-defined choice of models. Your model will not be the state-of-art model for the particular problem and data type, nor will it include expert insights about the problem and data. This automation or reusability saves users time at the expense of the quality of results. Instead of potentially 98%, your model will have an accuracy of 91%.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;455&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_51Plh81AdqTfFgbH-cfe03464.DrjLWBsG_2ufcwA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Please, choose a model that satisfies specifications. Photo by Karen Vardazaryan on Unsplash&lt;/p&gt;
&lt;p&gt;Then you have the loss function. This is a small piece of code that is either highly adapted to the actual problem, or one uses one of the pre-existing (and reusable) loss functions in the deep learning framework, but then with a &lt;a href=&quot;https://blog.esciencecenter.nl/how-not-to-use-deep-learning-in-science-e984b02a4df0&quot;&gt;“fingers crossed”&lt;/a&gt; strategy. If overlooked, it can also produce “biased AI”.&lt;/p&gt;
&lt;p&gt;Model training is already fully automated by the deep learning framework, that is the “machine learning” process.&lt;/p&gt;
&lt;h3 id=&quot;so&quot;&gt;So…&lt;/h3&gt;
&lt;p&gt;We saw that the only part that can produce a reusable component without affecting the final results is the data aggregation process. In the stages that follow, every time you use something off the shelf, you are doing it at the expense of the quality of the final results. On the other hand, most of the workload in the following stages is intellectual rather than programming. The data-adaptation code is a Python script that calls standard libraries; but you have to know exactly what you are doing to your data. The model is also a few hundreds of lines of code. The loss function is usually a few lines of code. It is at most tens of lines of code, if you are encoding your (very customized) domain knowledge into it. The trained model could be gigabytes of automatically generated machine-readable, and not human-readable, high-dimensional matrix. Ironically, before thinking about reusability of the &lt;a href=&quot;https://www.infoworld.com/article/3644968/how-no-code-reusable-ai-will-bridge-the-ai-divide.html&quot;&gt;trained model&lt;/a&gt;, and making your model transferable, let us point that it is already &lt;a href=&quot;https://blog.esciencecenter.nl/machine-learning-when-it-is-easy-when-it-is-difficult-9de0e1129593&quot;&gt;challenging&lt;/a&gt; enough to have the model re-usable on future data for which it was originally meant.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JtDR94c8PMnvwFa3-d69b3e33.BU0iJ_GW_JaWoQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The bulk of your AI software is not human-readable. Photo by Compare Fibre on Unsplash&lt;/p&gt;
&lt;p&gt;Thus, will you think twice next time you want to build a reusable AI software? Is your goal to have a tool that can show proof-of-concept but never be actually used in production mode? Then, invest your time in making it reusable. Is your goal to have an AI tool that will make profit, “beat” your competition or give state-of-art science results? Then, better invest less time on the keyboard and more time on the whiteboard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A special thanks to&lt;/em&gt; &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;&lt;em&gt;Tom Bakker&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;&lt;em&gt;Lieke de Boer&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for improving the post.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_fxCP5veXW7Lagbci-2b192df1.Do9KSlxK.webp" medium="image"/><author>Sonja Georgievska</author></item><item><title>A machine learning approach to laughter</title><link>https://blog.esciencecenter.nl/posts/2022-05-09---a-machine-learning-approach-to-laughter</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-05-09---a-machine-learning-approach-to-laughter</guid><description>&lt;p&gt;Our mentors at the eScience Center (&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@f.huber&quot;&gt;Florian Huber&lt;/a&gt;, and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jisk-attema/&quot;&gt;Jisk Attema&lt;/a&gt;), provided us with practical guidance in the use of such libraries, which provided an invaluable learning opportunity. For instance, we learned about how the data quality (i.e., sample size, uneven distribution of certain features) might affect the machine learning outputs, which resulted in taking the time to evaluate and scope data with meticulous data integration and data exploration. They also helped our conceptual understanding: what could the results actually tell us? Our machine learning results confirmed quantitatively what the t-SNE had shown qualitatively: tickling laughter was acoustically distinct from the other three types, while laughter produced in reaction to verbal jokes, someone else’s misfortune, and watching something funny were not systematically different from one another. An experiment with human participants also confirmed that tickling laughter is perceptually distinct from the other types; listeners could tell whether a laugh was produced by a person who was being tickled or not with remarkable accuracy. Our results made a lot of sense: tickling is a play behavior that is evolutionarily ancient and shared with other animals, whereas the other kinds of situations are all much more cognitively demanding, and probably unique to humans.&lt;/p&gt;
&lt;p&gt;Extracting feature importance told us which acoustic features were most distinct, pointing us to the possibility that tickling laughter is less controlled than other kinds of laughter. To really understand what differentiates laughter produced in tickling contexts from other situations, we complemented the computational analyses with human perceptual judgments. We ran a new listening task in which naive participants (who did not know about the context in which the laughs were produced) were asked to judge the extent to which the laughter sounded controlled, energetic, and so on. The results showed that laughter produced during tickling was judged to sound like the laughing person was not in control of their actions, in a state of high arousal, and in a situation involving physical contact with a familiar other.&lt;/p&gt;
&lt;p&gt;Meanwhile, we also analyzed the visual content of the videos in order to see whether the types of situations that we had inferred qualitatively would be distinguishable by a quantitative analysis of what was actually in the videos. Maybe verbal jokes would involve more conversations, and videos involving someone laughing at another’s misfortune would feature more people slipping? To test this, we ran the videos through Google Video Intelligence API, which picks out categories of objects and events. For example, this analysis revealed that the tickling laughter videos involved a lot of body parts, while people laughing when they were watching something funny often involved screens and animals. Machine learning analyses showed that the four types of situations could be well differentiated from just the visual contextual information in the video clips, demonstrating that the distinctions we had made were indeed meaningful, even though some of the differences in context did not translate into acoustically different types of laughter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A machine learning approach to laughter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;439&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-machine-learning-approach-to-laughter-3f586d65.D5I6rXhC_ZgMunb.webp&quot; srcset=&quot;&quot;&gt;
Random forest classification of the acoustic analysisAnd there you have it! We bet that after this blog and our analyses you’ll be thinking twice about your laughter. What makes you giggle? What makes your belly laugh? You’re also probably wondering, what’s next?&lt;/p&gt;
&lt;p&gt;The next step for this project will be to tie the different strands together into a manuscript, accompanied by interactive online illustrations, which will be submitted for publication in a peer-reviewed journal. The consultation with our excellent mentors at the eScience Center provided an inspiring setting for discussing our ideas in a constructive and fun atmosphere. The guidance we received will be useful not only for this project but also for our future research.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uva.nl/en/profile/s/a/d.a.sauter/d.a.sauter.html&quot;&gt;Dr. Disa Sauter**&lt;/a&gt; Associate Professor in the Department of Psychology at the University of Amsterdam. She studies emotions, focusing on nonverbal expressions with a particular interest in positive emotions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uva.nl/profiel/k/a/r.g.kamiloglu/r.g.kamiloglu.html&quot;&gt;&lt;strong&gt;Roza Kamiloğlu&lt;/strong&gt;&lt;/a&gt;is a PhD candidate in psychology at University of Amsterdam. Her research interests include nonverbal expressions, emotion, and computational modeling.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uni-muenster.de/PsyIFP/AEMilek/en/team/sun.html&quot;&gt;&lt;strong&gt;Dr. Rui Sun&lt;/strong&gt;&lt;/a&gt; is a guest researcher at the Department of Psychology, University of Amsterdam. She is interested in positive emotion, wellbeing, and social media research.&lt;/p&gt;</description><pubDate>Mon, 09 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Our mentors at the eScience Center (&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@f.huber&quot;&gt;Florian Huber&lt;/a&gt;, and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jisk-attema/&quot;&gt;Jisk Attema&lt;/a&gt;), provided us with practical guidance in the use of such libraries, which provided an invaluable learning opportunity. For instance, we learned about how the data quality (i.e., sample size, uneven distribution of certain features) might affect the machine learning outputs, which resulted in taking the time to evaluate and scope data with meticulous data integration and data exploration. They also helped our conceptual understanding: what could the results actually tell us? Our machine learning results confirmed quantitatively what the t-SNE had shown qualitatively: tickling laughter was acoustically distinct from the other three types, while laughter produced in reaction to verbal jokes, someone else’s misfortune, and watching something funny were not systematically different from one another. An experiment with human participants also confirmed that tickling laughter is perceptually distinct from the other types; listeners could tell whether a laugh was produced by a person who was being tickled or not with remarkable accuracy. Our results made a lot of sense: tickling is a play behavior that is evolutionarily ancient and shared with other animals, whereas the other kinds of situations are all much more cognitively demanding, and probably unique to humans.&lt;/p&gt;
&lt;p&gt;Extracting feature importance told us which acoustic features were most distinct, pointing us to the possibility that tickling laughter is less controlled than other kinds of laughter. To really understand what differentiates laughter produced in tickling contexts from other situations, we complemented the computational analyses with human perceptual judgments. We ran a new listening task in which naive participants (who did not know about the context in which the laughs were produced) were asked to judge the extent to which the laughter sounded controlled, energetic, and so on. The results showed that laughter produced during tickling was judged to sound like the laughing person was not in control of their actions, in a state of high arousal, and in a situation involving physical contact with a familiar other.&lt;/p&gt;
&lt;p&gt;Meanwhile, we also analyzed the visual content of the videos in order to see whether the types of situations that we had inferred qualitatively would be distinguishable by a quantitative analysis of what was actually in the videos. Maybe verbal jokes would involve more conversations, and videos involving someone laughing at another’s misfortune would feature more people slipping? To test this, we ran the videos through Google Video Intelligence API, which picks out categories of objects and events. For example, this analysis revealed that the tickling laughter videos involved a lot of body parts, while people laughing when they were watching something funny often involved screens and animals. Machine learning analyses showed that the four types of situations could be well differentiated from just the visual contextual information in the video clips, demonstrating that the distinctions we had made were indeed meaningful, even though some of the differences in context did not translate into acoustically different types of laughter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A machine learning approach to laughter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;439&quot; src=&quot;https://blog.esciencecenter.nl/_astro/a-machine-learning-approach-to-laughter-3f586d65.D5I6rXhC_ZgMunb.webp&quot; srcset=&quot;&quot;&gt;
Random forest classification of the acoustic analysisAnd there you have it! We bet that after this blog and our analyses you’ll be thinking twice about your laughter. What makes you giggle? What makes your belly laugh? You’re also probably wondering, what’s next?&lt;/p&gt;
&lt;p&gt;The next step for this project will be to tie the different strands together into a manuscript, accompanied by interactive online illustrations, which will be submitted for publication in a peer-reviewed journal. The consultation with our excellent mentors at the eScience Center provided an inspiring setting for discussing our ideas in a constructive and fun atmosphere. The guidance we received will be useful not only for this project but also for our future research.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uva.nl/en/profile/s/a/d.a.sauter/d.a.sauter.html&quot;&gt;Dr. Disa Sauter**&lt;/a&gt; Associate Professor in the Department of Psychology at the University of Amsterdam. She studies emotions, focusing on nonverbal expressions with a particular interest in positive emotions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uva.nl/profiel/k/a/r.g.kamiloglu/r.g.kamiloglu.html&quot;&gt;&lt;strong&gt;Roza Kamiloğlu&lt;/strong&gt;&lt;/a&gt;is a PhD candidate in psychology at University of Amsterdam. Her research interests include nonverbal expressions, emotion, and computational modeling.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.uni-muenster.de/PsyIFP/AEMilek/en/team/sun.html&quot;&gt;&lt;strong&gt;Dr. Rui Sun&lt;/strong&gt;&lt;/a&gt; is a guest researcher at the Department of Psychology, University of Amsterdam. She is interested in positive emotion, wellbeing, and social media research.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/a-machine-learning-approach-to-laughter-3f586d65.D5I6rXhC.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Forget about Jupyter Notebooks — showcase your research using Dashboards</title><link>https://blog.esciencecenter.nl/posts/2022-05-04---forget-about-jupyter-notebooks-showcase-your-research-using-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-05-04---forget-about-jupyter-notebooks-showcase-your-research-using-</guid><description>&lt;p&gt;The snippet below generates some data (a normal distribution), fits it, and creates a &lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt; plot out of it. It takes three parameters, &lt;code&gt;mu_in&lt;/code&gt;, &lt;code&gt;std_in&lt;/code&gt;, and &lt;code&gt;size&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My cool python script 😎&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Forget about Jupyter Notebooks — showcase your research using Dashboards&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/forget-about-jupyter-notebooks-showcase--a0b23d8a.B85ojGtN_Z1dtIuI.webp&quot; srcset=&quot;&quot;&gt;
A normal plot&lt;/p&gt;
&lt;h2 id=&quot;to-a-fancy-dashboard&quot;&gt;…to a fancy dashboard&lt;/h2&gt;
&lt;p&gt;Let’s turn this into an interactive dashboard in four simple steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import streamlist as st&lt;/code&gt; 😅&lt;/li&gt;
&lt;li&gt;Add a title using &lt;code&gt;[st.title](https://docs.streamlit.io/library/api-reference/text)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Turn the input parameters into interactive sliders using &lt;code&gt;[st.slider](https://docs.streamlit.io/library/api-reference/widgets)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tell streamlit about our plot using &lt;code&gt;[st.pyplot](https://docs.streamlit.io/library/api-reference/charts)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that we do not have to change any of the data generation, fitting, or plotting code!&lt;/p&gt;
&lt;p&gt;Now as a dashboard 🐱‍💻&lt;/p&gt;
&lt;p&gt;Then run the dashboard using:&lt;/p&gt;
&lt;p&gt;streamlit run my_dashboard.pyThis will start a server, and the dashboard can be accessed through the browser (much like a Jupyter Notebook).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Forget about Jupyter Notebooks — showcase your research using Dashboards&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1067&quot; src=&quot;https://blog.esciencecenter.nl/_astro/forget-about-jupyter-notebooks-showcase--909c1674.D9XY027z_1LAgIV.webp&quot; srcset=&quot;&quot;&gt;
A fancy dashboard&lt;/p&gt;
&lt;h2 id=&quot;how-does-this-work&quot;&gt;How does this work?&lt;/h2&gt;
&lt;p&gt;The way Streamlit works is quite interesting. Everytime a slider is moved, a box is checked, or a button is pressed, Streamlit triggers a re-run of the script. The input values are updated. The javascript back-end keeps track of the values.&lt;/p&gt;
&lt;p&gt;This means that the code itself executes linearly. In my view, this simplicity is what sets it apart. There is no need for any callbacks or complex flow controls. Your python scripts runs from top-to-bottom. This makes it easy to reason about the code. And with minimal modifications to the python code, any script can be turned into a dashboard.&lt;/p&gt;
&lt;p&gt;Are there any downsides? Yes. Because streamlit re-runs the entire script on every update, it can feel a bit slow. Especially when updating a large number of plots. It can also get stuck on long-running functions. For performance optimizations, streamlit has some options to &lt;a href=&quot;https://docs.streamlit.io/library/api-reference/performance&quot;&gt;cache the result&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;plotting-libraries&quot;&gt;Plotting libraries&lt;/h2&gt;
&lt;p&gt;The example above uses &lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt; for the plots. Matplotlib has been the go-to plotting library for Python for many for a long time. It has been around for nearly two decades, and it is tighly integrated in the scientific python stack.&lt;/p&gt;
&lt;p&gt;If you are familiar with matplotlib, you will know that it is great for making making publication quality plots. You will also know that making interactive plots can be a hassle.&lt;/p&gt;
&lt;p&gt;Streamlit supports these libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://altair-viz.github.io/&quot;&gt;altair&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bokeh.org/&quot;&gt;bokeh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/python/&quot;&gt;plotly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seaborn.pydata.org/&quot;&gt;seaborn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deckgl.readthedocs.io/en/latest/layer.html&quot;&gt;PyDeck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xflr6/graphviz&quot;&gt;GraphViz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Modern plotting libraries like &lt;a href=&quot;https://plotly.com/python/&quot;&gt;plotly&lt;/a&gt;, &lt;a href=&quot;https://bokeh.org/&quot;&gt;bokeh&lt;/a&gt;, and &lt;a href=&quot;https://altair-viz.github.io/&quot;&gt;altair&lt;/a&gt; render directly to javascript. This means they are built for the web, and interactivity is built-in. This makes them better suited for web-apps. If you are going to make a dashboard, I recommend checking out one of these alternatives.&lt;/p&gt;
&lt;h2 id=&quot;sharing-your-dashboard&quot;&gt;Sharing your dashboard&lt;/h2&gt;
&lt;p&gt;Alright, so now that we have made a fancy looking dashboard, so that anyone can play with the data. How do we make it available?&lt;/p&gt;
&lt;p&gt;Streamlit uses a host/server model, which means you can run it on your own server.&lt;/p&gt;
&lt;p&gt;Easier is to use the &lt;a href=&quot;https://streamlit.io/cloud&quot;&gt;streamlit cloud&lt;/a&gt; to host your dashboard (it’s free for students and open-source projects). I found this also quite straightforward to set up. All I had to do was to create a &lt;a href=&quot;https://github.com/stefsmeets/dashboard_blog&quot;&gt;repository on github&lt;/a&gt; with the code and a requirements file.&lt;/p&gt;
&lt;p&gt;Then I logged into &lt;a href=&quot;https://share.streamlit.io/&quot;&gt;streamlit cloud&lt;/a&gt; using the Github SSO, and started a new app pointing at my repo and code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://share.streamlit.io/stefsmeets/dashboard_blog/main&quot;&gt;Click here&lt;/a&gt; for the result! 🥳&lt;/p&gt;
&lt;h2 id=&quot;final-remarks&quot;&gt;Final remarks&lt;/h2&gt;
&lt;p&gt;In this blog post, I introduced streamlit and showed how it can be used to turn a python script into a dashboard, and host it online. An excellent way to showcase your research to a non-technical audience, if you ask me. The linear execution model makes it straightforward to adapt existing scripts. The code does not get in the way, and the result looks awesome.&lt;/p&gt;
&lt;p&gt;So next time you want to present some data in a notebook, consider using a dashboard instead.&lt;/p&gt;
&lt;p&gt;All the code in this blog post is available from &lt;a href=&quot;https://github.com/stefsmeets/dashboard_blog&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Wed, 04 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The snippet below generates some data (a normal distribution), fits it, and creates a &lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt; plot out of it. It takes three parameters, &lt;code&gt;mu_in&lt;/code&gt;, &lt;code&gt;std_in&lt;/code&gt;, and &lt;code&gt;size&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My cool python script 😎&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Forget about Jupyter Notebooks — showcase your research using Dashboards&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://blog.esciencecenter.nl/_astro/forget-about-jupyter-notebooks-showcase--a0b23d8a.B85ojGtN_Z1dtIuI.webp&quot; srcset=&quot;&quot;&gt;
A normal plot&lt;/p&gt;
&lt;h2 id=&quot;to-a-fancy-dashboard&quot;&gt;…to a fancy dashboard&lt;/h2&gt;
&lt;p&gt;Let’s turn this into an interactive dashboard in four simple steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import streamlist as st&lt;/code&gt; 😅&lt;/li&gt;
&lt;li&gt;Add a title using &lt;code&gt;[st.title](https://docs.streamlit.io/library/api-reference/text)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Turn the input parameters into interactive sliders using &lt;code&gt;[st.slider](https://docs.streamlit.io/library/api-reference/widgets)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tell streamlit about our plot using &lt;code&gt;[st.pyplot](https://docs.streamlit.io/library/api-reference/charts)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that we do not have to change any of the data generation, fitting, or plotting code!&lt;/p&gt;
&lt;p&gt;Now as a dashboard 🐱‍💻&lt;/p&gt;
&lt;p&gt;Then run the dashboard using:&lt;/p&gt;
&lt;p&gt;streamlit run my_dashboard.pyThis will start a server, and the dashboard can be accessed through the browser (much like a Jupyter Notebook).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Forget about Jupyter Notebooks — showcase your research using Dashboards&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1067&quot; src=&quot;https://blog.esciencecenter.nl/_astro/forget-about-jupyter-notebooks-showcase--909c1674.D9XY027z_1LAgIV.webp&quot; srcset=&quot;&quot;&gt;
A fancy dashboard&lt;/p&gt;
&lt;h2 id=&quot;how-does-this-work&quot;&gt;How does this work?&lt;/h2&gt;
&lt;p&gt;The way Streamlit works is quite interesting. Everytime a slider is moved, a box is checked, or a button is pressed, Streamlit triggers a re-run of the script. The input values are updated. The javascript back-end keeps track of the values.&lt;/p&gt;
&lt;p&gt;This means that the code itself executes linearly. In my view, this simplicity is what sets it apart. There is no need for any callbacks or complex flow controls. Your python scripts runs from top-to-bottom. This makes it easy to reason about the code. And with minimal modifications to the python code, any script can be turned into a dashboard.&lt;/p&gt;
&lt;p&gt;Are there any downsides? Yes. Because streamlit re-runs the entire script on every update, it can feel a bit slow. Especially when updating a large number of plots. It can also get stuck on long-running functions. For performance optimizations, streamlit has some options to &lt;a href=&quot;https://docs.streamlit.io/library/api-reference/performance&quot;&gt;cache the result&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;plotting-libraries&quot;&gt;Plotting libraries&lt;/h2&gt;
&lt;p&gt;The example above uses &lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt; for the plots. Matplotlib has been the go-to plotting library for Python for many for a long time. It has been around for nearly two decades, and it is tighly integrated in the scientific python stack.&lt;/p&gt;
&lt;p&gt;If you are familiar with matplotlib, you will know that it is great for making making publication quality plots. You will also know that making interactive plots can be a hassle.&lt;/p&gt;
&lt;p&gt;Streamlit supports these libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://altair-viz.github.io/&quot;&gt;altair&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bokeh.org/&quot;&gt;bokeh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/python/&quot;&gt;plotly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seaborn.pydata.org/&quot;&gt;seaborn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deckgl.readthedocs.io/en/latest/layer.html&quot;&gt;PyDeck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xflr6/graphviz&quot;&gt;GraphViz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Modern plotting libraries like &lt;a href=&quot;https://plotly.com/python/&quot;&gt;plotly&lt;/a&gt;, &lt;a href=&quot;https://bokeh.org/&quot;&gt;bokeh&lt;/a&gt;, and &lt;a href=&quot;https://altair-viz.github.io/&quot;&gt;altair&lt;/a&gt; render directly to javascript. This means they are built for the web, and interactivity is built-in. This makes them better suited for web-apps. If you are going to make a dashboard, I recommend checking out one of these alternatives.&lt;/p&gt;
&lt;h2 id=&quot;sharing-your-dashboard&quot;&gt;Sharing your dashboard&lt;/h2&gt;
&lt;p&gt;Alright, so now that we have made a fancy looking dashboard, so that anyone can play with the data. How do we make it available?&lt;/p&gt;
&lt;p&gt;Streamlit uses a host/server model, which means you can run it on your own server.&lt;/p&gt;
&lt;p&gt;Easier is to use the &lt;a href=&quot;https://streamlit.io/cloud&quot;&gt;streamlit cloud&lt;/a&gt; to host your dashboard (it’s free for students and open-source projects). I found this also quite straightforward to set up. All I had to do was to create a &lt;a href=&quot;https://github.com/stefsmeets/dashboard_blog&quot;&gt;repository on github&lt;/a&gt; with the code and a requirements file.&lt;/p&gt;
&lt;p&gt;Then I logged into &lt;a href=&quot;https://share.streamlit.io/&quot;&gt;streamlit cloud&lt;/a&gt; using the Github SSO, and started a new app pointing at my repo and code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://share.streamlit.io/stefsmeets/dashboard_blog/main&quot;&gt;Click here&lt;/a&gt; for the result! 🥳&lt;/p&gt;
&lt;h2 id=&quot;final-remarks&quot;&gt;Final remarks&lt;/h2&gt;
&lt;p&gt;In this blog post, I introduced streamlit and showed how it can be used to turn a python script into a dashboard, and host it online. An excellent way to showcase your research to a non-technical audience, if you ask me. The linear execution model makes it straightforward to adapt existing scripts. The code does not get in the way, and the result looks awesome.&lt;/p&gt;
&lt;p&gt;So next time you want to present some data in a notebook, consider using a dashboard instead.&lt;/p&gt;
&lt;p&gt;All the code in this blog post is available from &lt;a href=&quot;https://github.com/stefsmeets/dashboard_blog&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/forget-about-jupyter-notebooks-showcase--909c1674.D9XY027z.png" medium="image"/><author>Stef Smeets</author></item><item><title>Using machine learning to tell apart rain, snow, hail and fog from cell tower data</title><link>https://blog.esciencecenter.nl/posts/2022-04-22---using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-04-22---using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-</guid><description>&lt;h1 id=&quot;using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-from-cell-tower-data&quot;&gt;&lt;strong&gt;Using machine learning to tell apart rain, snow, hail and fog from cell tower data&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;][eScience Editorial Team]·Apr 21, 2022&lt;/p&gt;
&lt;p&gt;Next, **we explored whether CMLs can be used to detect &lt;strong&gt;fog&lt;/strong&gt;. Fog consists of droplets so small that they float in the air up to a few meters above the ground. The disdrometers do not pick up fog accurately enough to be used as target dataset. For this reason, we used an alternative target dataset to detect fog.&lt;/p&gt;
&lt;p&gt;Figure 3: CML attenuation signal (red) and target dataset (fog/no fog in blue) model fog prediction (fog/no fog in black) model fog threshold (dashed gray) for 31 August 2015.The relatively round fog droplets can scatter a wide range of wavelengths smaller than the droplets themselves. This includes visible light, making fog… foggy. Fog also affects wavelengths within the near-infrared range. Luckily, the experimental setup of the measurement campaign also included a near-infrared link (Figure 1), which we use as reference dataset of the foggiest time steps. Comparing the fog time series and the CML signal reveals a distinct drop of the CML signal which coincides with the fog occurrence (Figure 3). &lt;strong&gt;Once again we balance the dataset because the moments without fog far outnumber the fog events. After balancing the dataset and feeding the raw CML data into the McFly&lt;/strong&gt; algorithm, the result is a mere 49% accuracy. For a balanced two-class dataset, this is not better than just tossing a coin…&lt;/p&gt;
&lt;p&gt;It appears that the raw data for each individual time step is not enough to create a neural network that detects fog. However, the attenuation signal in the CML data shows a pattern associated with fog. This pattern changes over time, but &lt;strong&gt;McFly&lt;/strong&gt; does not automatically take the time dimension into consideration. Hence, to account for the temporal aspects, a rolling rate of change of the CML attenuation signal over 15 minutes is included for every time step as input to &lt;strong&gt;McFly&lt;/strong&gt;. On its own, this input value could be used to gain a validation accuracy of 67%, but combining it with the raw CML data brings it up to 73%. As a next step, we include additional inputs to the machine learning model to represent the time of the day and a time of the year, to allow the neural network to learn the climatology of fog. On its own, this correctly predicts fog 60% of the time steps, but when combined with the other data, the validation accuracy reaches 77%, which is a promising first step towards detecting not only rain, but also fog with CMLs.&lt;/p&gt;
&lt;p&gt;This blog is part of our blog series: The Small-Scale Initiative on Machine Learning, how did it go?, *where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience.&lt;/p&gt;</description><pubDate>Fri, 22 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;using-machine-learning-to-tell-apart-rain-snow-hail-and-fog-from-cell-tower-data&quot;&gt;&lt;strong&gt;Using machine learning to tell apart rain, snow, hail and fog from cell tower data&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;][eScience Editorial Team]·Apr 21, 2022&lt;/p&gt;
&lt;p&gt;Next, **we explored whether CMLs can be used to detect &lt;strong&gt;fog&lt;/strong&gt;. Fog consists of droplets so small that they float in the air up to a few meters above the ground. The disdrometers do not pick up fog accurately enough to be used as target dataset. For this reason, we used an alternative target dataset to detect fog.&lt;/p&gt;
&lt;p&gt;Figure 3: CML attenuation signal (red) and target dataset (fog/no fog in blue) model fog prediction (fog/no fog in black) model fog threshold (dashed gray) for 31 August 2015.The relatively round fog droplets can scatter a wide range of wavelengths smaller than the droplets themselves. This includes visible light, making fog… foggy. Fog also affects wavelengths within the near-infrared range. Luckily, the experimental setup of the measurement campaign also included a near-infrared link (Figure 1), which we use as reference dataset of the foggiest time steps. Comparing the fog time series and the CML signal reveals a distinct drop of the CML signal which coincides with the fog occurrence (Figure 3). &lt;strong&gt;Once again we balance the dataset because the moments without fog far outnumber the fog events. After balancing the dataset and feeding the raw CML data into the McFly&lt;/strong&gt; algorithm, the result is a mere 49% accuracy. For a balanced two-class dataset, this is not better than just tossing a coin…&lt;/p&gt;
&lt;p&gt;It appears that the raw data for each individual time step is not enough to create a neural network that detects fog. However, the attenuation signal in the CML data shows a pattern associated with fog. This pattern changes over time, but &lt;strong&gt;McFly&lt;/strong&gt; does not automatically take the time dimension into consideration. Hence, to account for the temporal aspects, a rolling rate of change of the CML attenuation signal over 15 minutes is included for every time step as input to &lt;strong&gt;McFly&lt;/strong&gt;. On its own, this input value could be used to gain a validation accuracy of 67%, but combining it with the raw CML data brings it up to 73%. As a next step, we include additional inputs to the machine learning model to represent the time of the day and a time of the year, to allow the neural network to learn the climatology of fog. On its own, this correctly predicts fog 60% of the time steps, but when combined with the other data, the validation accuracy reaches 77%, which is a promising first step towards detecting not only rain, but also fog with CMLs.&lt;/p&gt;
&lt;p&gt;This blog is part of our blog series: The Small-Scale Initiative on Machine Learning, how did it go?, *where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience.&lt;/p&gt;</content:encoded><author>eScience Editorial Team</author></item><item><title>A letter to my parents about my experience in a machine learning consultancy project</title><link>https://blog.esciencecenter.nl/posts/2022-04-14---a-letter-to-my-parents-about-my-experience-in-a-machine-lear</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-04-14---a-letter-to-my-parents-about-my-experience-in-a-machine-lear</guid><description>&lt;p&gt;&lt;em&gt;What does a Research Software Engineer do? This is not always easy to answer, but when your parents are asking, you definitely want to give a nice answer&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A fountain pen writing on a piece of paper.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1051&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_yseerb7z2bld7brhdY2y1A-0749df51.DqZc0FYE_1RsLve.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A fountain pen writing on a piece of paper.&lt;/p&gt;
&lt;p&gt;Dear Mum and Dad,&lt;/p&gt;
&lt;p&gt;I always wonder how you picture my daily work at the Netherlands eScience Center. Probably you imagine me sitting behind a computer all day. I think you know by now that I also sometimes talk to scientists, mostly from the healthcare domain. To give you a better feeling of the kind of things I do I decided to write you about my experience in the &lt;em&gt;Automated Video-based Assessment of Movement Disorders&lt;/em&gt; project.&lt;/p&gt;
&lt;p&gt;Automated Video-based Assessment of Movement Disorders… That is a mouth full of words. Let me try to explain what I did in this project.&lt;/p&gt;
&lt;p&gt;This project is in collaboration with &lt;a href=&quot;https://www.amsterdamumc.org/en/research/researchers/helga-haberfehlner.htm&quot;&gt;Helga Haberfehlner&lt;/a&gt; and her colleagues who work at the Department of Rehabilitation medicine of the Amsterdam UMC. Helga is a kind, energetic, and passionate researcher who is trying to improve the diagnosis and treatment of movement disorders in children.&lt;/p&gt;
&lt;p&gt;One of the problems they face in the clinic is how to objectively determine how severe such a movement disorder is and how it progresses over time. This is important to know because it helps the doctors pick the right treatment, or give them an idea about whether a treatment is working. In one such method a video of the patient is recorded. The video is then observed by a doctor who is trained to carefully look at the movements of the body. The doctor gives a score between 0 and 4 for how bad a particular set of symptoms is in a particular body part. For example, the doctor could rate the symptoms in the left lower arm as a 3. If, for example, after a year of medical treatment this score goes to 1 this indicates that the treatment is working.&lt;/p&gt;
&lt;p&gt;Now the problem is that it is quite difficult to score the symptoms of a patient. Different doctors tend to look at different things. Even the same doctor looking at the same video could give a low score on an optimistic day, and a high score on a pessimistic day. Also, it takes a lot of time for the doctors to do this correctly, time that is better spent on care for the patients instead of looking at videos. So, the doctors would be helped a lot if the scoring of these videos could be done automatically by a computer. Together with my eScience Center colleagues Florian Huber and Sonja Georgievska we set out to help Helga and her colleagues from the Amsterdam UMC.&lt;/p&gt;
&lt;p&gt;In most of the projects at the eScience Center we build computer programs with input from the domain scientists we work together with. These are long projects, taking at least 2 years. But in this project (the so-called Small-Scale-Initiative Machine Learning project) we only had half a year in which we mostly gave advise on the activities that the researchers perform themselves. The good thing is that this is exactly what Helga needed: technological expertise. And by doing projects in such a way we could actually not just help Helga and her colleagues, but also 11 other such projects from a diverse range of scientific disciplines.&lt;/p&gt;
&lt;p&gt;How did we help Helga and her colleagues? We mostly gave advise on a technique called ‘Machine Learning’. It is a technology that teaches a computer how to do a task by showing it examples of how to do it. In our case, the computer had to learn how to give a score between 0 and 4 indicating how bad the symptoms of a movement disorder are in the patient in the video. We managed to teach the computer how to do it reasonably well, although there is still some work needed before doctors can start using this technique. You can see our results in our &lt;a href=&quot;https://github.com/RehabAUmc/modys-video&quot;&gt;Github repository&lt;/a&gt; (I might explain more about Github in another letter 😉). We are also working on writing our conclusions down in a scientific article (&lt;strong&gt;@dad&lt;/strong&gt; I hope we get as much attention as &lt;a href=&quot;https://library.wur.nl/ojs/index.php/njas/article/view/16546&quot;&gt;you got in the glory of your soil-researching period&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;What I most enjoyed in this project is the fruitful collaboration that we had. I think Helga and her colleagues learned a lot from the technological expertise we could offer. Helga even started to (successfully) do more programming herself. But the other way around we learned a lot about how to apply machine learning techniques in a clinical setting. We even got a tour around Helga’s department where she showed us all the devices that they use to investigate movement disorders.&lt;/p&gt;
&lt;p&gt;I hope this gives you a bit of a feeling for what I do at the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;Lots of love,&lt;/p&gt;
&lt;p&gt;Sven&lt;/p&gt;</description><pubDate>Thu, 14 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;What does a Research Software Engineer do? This is not always easy to answer, but when your parents are asking, you definitely want to give a nice answer&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A fountain pen writing on a piece of paper.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1051&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_yseerb7z2bld7brhdY2y1A-0749df51.DqZc0FYE_1RsLve.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A fountain pen writing on a piece of paper.&lt;/p&gt;
&lt;p&gt;Dear Mum and Dad,&lt;/p&gt;
&lt;p&gt;I always wonder how you picture my daily work at the Netherlands eScience Center. Probably you imagine me sitting behind a computer all day. I think you know by now that I also sometimes talk to scientists, mostly from the healthcare domain. To give you a better feeling of the kind of things I do I decided to write you about my experience in the &lt;em&gt;Automated Video-based Assessment of Movement Disorders&lt;/em&gt; project.&lt;/p&gt;
&lt;p&gt;Automated Video-based Assessment of Movement Disorders… That is a mouth full of words. Let me try to explain what I did in this project.&lt;/p&gt;
&lt;p&gt;This project is in collaboration with &lt;a href=&quot;https://www.amsterdamumc.org/en/research/researchers/helga-haberfehlner.htm&quot;&gt;Helga Haberfehlner&lt;/a&gt; and her colleagues who work at the Department of Rehabilitation medicine of the Amsterdam UMC. Helga is a kind, energetic, and passionate researcher who is trying to improve the diagnosis and treatment of movement disorders in children.&lt;/p&gt;
&lt;p&gt;One of the problems they face in the clinic is how to objectively determine how severe such a movement disorder is and how it progresses over time. This is important to know because it helps the doctors pick the right treatment, or give them an idea about whether a treatment is working. In one such method a video of the patient is recorded. The video is then observed by a doctor who is trained to carefully look at the movements of the body. The doctor gives a score between 0 and 4 for how bad a particular set of symptoms is in a particular body part. For example, the doctor could rate the symptoms in the left lower arm as a 3. If, for example, after a year of medical treatment this score goes to 1 this indicates that the treatment is working.&lt;/p&gt;
&lt;p&gt;Now the problem is that it is quite difficult to score the symptoms of a patient. Different doctors tend to look at different things. Even the same doctor looking at the same video could give a low score on an optimistic day, and a high score on a pessimistic day. Also, it takes a lot of time for the doctors to do this correctly, time that is better spent on care for the patients instead of looking at videos. So, the doctors would be helped a lot if the scoring of these videos could be done automatically by a computer. Together with my eScience Center colleagues Florian Huber and Sonja Georgievska we set out to help Helga and her colleagues from the Amsterdam UMC.&lt;/p&gt;
&lt;p&gt;In most of the projects at the eScience Center we build computer programs with input from the domain scientists we work together with. These are long projects, taking at least 2 years. But in this project (the so-called Small-Scale-Initiative Machine Learning project) we only had half a year in which we mostly gave advise on the activities that the researchers perform themselves. The good thing is that this is exactly what Helga needed: technological expertise. And by doing projects in such a way we could actually not just help Helga and her colleagues, but also 11 other such projects from a diverse range of scientific disciplines.&lt;/p&gt;
&lt;p&gt;How did we help Helga and her colleagues? We mostly gave advise on a technique called ‘Machine Learning’. It is a technology that teaches a computer how to do a task by showing it examples of how to do it. In our case, the computer had to learn how to give a score between 0 and 4 indicating how bad the symptoms of a movement disorder are in the patient in the video. We managed to teach the computer how to do it reasonably well, although there is still some work needed before doctors can start using this technique. You can see our results in our &lt;a href=&quot;https://github.com/RehabAUmc/modys-video&quot;&gt;Github repository&lt;/a&gt; (I might explain more about Github in another letter 😉). We are also working on writing our conclusions down in a scientific article (&lt;strong&gt;@dad&lt;/strong&gt; I hope we get as much attention as &lt;a href=&quot;https://library.wur.nl/ojs/index.php/njas/article/view/16546&quot;&gt;you got in the glory of your soil-researching period&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;What I most enjoyed in this project is the fruitful collaboration that we had. I think Helga and her colleagues learned a lot from the technological expertise we could offer. Helga even started to (successfully) do more programming herself. But the other way around we learned a lot about how to apply machine learning techniques in a clinical setting. We even got a tour around Helga’s department where she showed us all the devices that they use to investigate movement disorders.&lt;/p&gt;
&lt;p&gt;I hope this gives you a bit of a feeling for what I do at the Netherlands eScience Center.&lt;/p&gt;
&lt;p&gt;Lots of love,&lt;/p&gt;
&lt;p&gt;Sven&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_yseerb7z2bld7brhdY2y1A-0749df51.DqZc0FYE.jpeg" medium="image"/><author>Sven van der Burg</author></item><item><title>Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy</title><link>https://blog.esciencecenter.nl/posts/2022-04-11---can-machine-learning-help-us-improve-stroke-rehabilitation-a</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-04-11---can-machine-learning-help-us-improve-stroke-rehabilitation-a</guid><description>&lt;p&gt;Along the way, the biggest issue was our data set itself. Because data collection of human movements is a job that takes time and our patient group is small, we only have a limited amount of data available. At the same time, the data set is highly variable, which makes the problem more difficult for Machine Learning.&lt;/p&gt;
&lt;p&gt;In next steps for this project, we are exploring the results and trying to translate them into information that is valuable for our research field. At the same time, we are in the early stages of a data sharing effort, with those who may have similar data sets. That way, we will be able to increase the size of our training set.&lt;/p&gt;
&lt;p&gt;The first result can be seen in the figure below. It shows the distribution of the different people (who were part of a study) using two latent features of a variational autoencoder. By creating the whole-body movement from the latent space, we were able to show the gait patterns which represented the people in the different areas of the two-dimensional latent space. In the future, this will help to evaluate a patient’s gait and their improvement during and after rehabilitation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/can-machine-learning-help-us-improve-str-99a7ce23.Dh8iiFLS_1EeUN9.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://research.vu.nl/en/persons/sina-david&quot;&gt;Dr. Sina David**&lt;/a&gt; Assistant Professor in the Faculty of Behavioural and Movement Sciences, Neuromechanics and AMS-Rehabilitation &amp;#x26; Development at Vrije Universeit Amsterdam. Follow her on Twitter &lt;a href=&quot;https://twitter.com/SinaDavid1907&quot;&gt;@SinaDavid1907&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.internationalhu.com/research/researchers/michiel-punt&quot;&gt;&lt;strong&gt;Dr. Michiel Punt&lt;/strong&gt;&lt;/a&gt; Senior researcher at HU University of Applied Sciences Utrecht. He is also a Postdoc researcher at VU Amsterdam. Follow him on Twitter &lt;a href=&quot;https://twitter.com/MichielPunt&quot;&gt;@MichielPunt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://research.vu.nl/en/persons/yuge-zhang&quot;&gt;&lt;strong&gt;Yuge Yhang&lt;/strong&gt;&lt;/a&gt; External PhD Candidate at the Faculty of Behavioural and Movement Sciences, Neuromechanics and AMS-Ageing &amp;#x26; Vitality. Follow her on Twitter &lt;a href=&quot;https://twitter.com/yugezhang5&quot;&gt;@yugezhang5&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Learn more by visiting &lt;a href=&quot;https://www.human-movement-sciences.nl/nm/&quot;&gt;human-movement-sciences.nl/nm&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The work described in this blog is supported by research software engineers (RSEs) of the Netherlands eScience Center, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-cunliang-geng/&quot;&gt;Dr. Cunliang Geng&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/yang-liu/&quot;&gt;Dr. Yang Liu&lt;/a&gt; and Dr. [Sonja Georgievska].&lt;/p&gt;</description><pubDate>Mon, 11 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Along the way, the biggest issue was our data set itself. Because data collection of human movements is a job that takes time and our patient group is small, we only have a limited amount of data available. At the same time, the data set is highly variable, which makes the problem more difficult for Machine Learning.&lt;/p&gt;
&lt;p&gt;In next steps for this project, we are exploring the results and trying to translate them into information that is valuable for our research field. At the same time, we are in the early stages of a data sharing effort, with those who may have similar data sets. That way, we will be able to increase the size of our training set.&lt;/p&gt;
&lt;p&gt;The first result can be seen in the figure below. It shows the distribution of the different people (who were part of a study) using two latent features of a variational autoencoder. By creating the whole-body movement from the latent space, we were able to show the gait patterns which represented the people in the different areas of the two-dimensional latent space. In the future, this will help to evaluate a patient’s gait and their improvement during and after rehabilitation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;512&quot; src=&quot;https://blog.esciencecenter.nl/_astro/can-machine-learning-help-us-improve-str-99a7ce23.Dh8iiFLS_1EeUN9.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://research.vu.nl/en/persons/sina-david&quot;&gt;Dr. Sina David**&lt;/a&gt; Assistant Professor in the Faculty of Behavioural and Movement Sciences, Neuromechanics and AMS-Rehabilitation &amp;#x26; Development at Vrije Universeit Amsterdam. Follow her on Twitter &lt;a href=&quot;https://twitter.com/SinaDavid1907&quot;&gt;@SinaDavid1907&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.internationalhu.com/research/researchers/michiel-punt&quot;&gt;&lt;strong&gt;Dr. Michiel Punt&lt;/strong&gt;&lt;/a&gt; Senior researcher at HU University of Applied Sciences Utrecht. He is also a Postdoc researcher at VU Amsterdam. Follow him on Twitter &lt;a href=&quot;https://twitter.com/MichielPunt&quot;&gt;@MichielPunt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://research.vu.nl/en/persons/yuge-zhang&quot;&gt;&lt;strong&gt;Yuge Yhang&lt;/strong&gt;&lt;/a&gt; External PhD Candidate at the Faculty of Behavioural and Movement Sciences, Neuromechanics and AMS-Ageing &amp;#x26; Vitality. Follow her on Twitter &lt;a href=&quot;https://twitter.com/yugezhang5&quot;&gt;@yugezhang5&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Learn more by visiting &lt;a href=&quot;https://www.human-movement-sciences.nl/nm/&quot;&gt;human-movement-sciences.nl/nm&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The work described in this blog is supported by research software engineers (RSEs) of the Netherlands eScience Center, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-cunliang-geng/&quot;&gt;Dr. Cunliang Geng&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/yang-liu/&quot;&gt;Dr. Yang Liu&lt;/a&gt; and Dr. [Sonja Georgievska].&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/can-machine-learning-help-us-improve-str-99a7ce23.Dh8iiFLS.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>How machine learning could help Simone to play Ludo</title><link>https://blog.esciencecenter.nl/posts/2022-03-31---how-machine-learning-could-help-simone-to-play-ludo</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-03-31---how-machine-learning-could-help-simone-to-play-ludo</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;629&quot; height=&quot;626&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ii34FkLcmA3bYfAhLaNzZw-f35a5f15.9C07PfCF_Z2ssRMh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simone is a 12 year old girl. She loves to play Ludo with her mum, dad and her little brother. However, when she pushes the dice switch in the middle of the Ludo board game, she cannot properly control her movements and the tokens sometimes fall from the board. Simone also does not succeed to move the tokens, so her dad does that for her. Simone has &lt;a href=&quot;https://cerebralpalsy.org.au/our-research/about-cerebral-palsy/what-is-cerebral-palsy/types-of-cerebral-palsy/dyskinetic-cerebral-palsy/&quot;&gt;dyskinetic cerebral palsy&lt;/a&gt;, due to a lack of oxygen around birth. &lt;a href=&quot;https://www.youtube.com/watch?v=-2ODMPVjnI8&quot;&gt;Involuntary movements&lt;/a&gt; (called dystonia and choreo-athetosis) disturb her during daily activities such as playing Ludo.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://www.amc.nl/web/home.htm&quot;&gt;Amsterdam UMC&lt;/a&gt;, we treat children with severe dyskinetic cerebral palsy with medication that is directly delivered into the spinal canal by an indwelling pump (intrathecal baclofen). This treatment has been shown to be &lt;a href=&quot;https://research.vumc.nl/en/publications/the-effect-of-intrathecal-baclofen-in-dyskinetic-cerebral-palsy-t&quot;&gt;effective in reaching individual goals&lt;/a&gt; (such as not overthrowing the tokens when playing Ludo). However, we currently have a hard time to exactly monitor the involuntary movements and the effect of treatments on them. This monitoring is very important to give the right doses of medication. During check-ups at the hospital, doctors ask parents and children, how movements evolve and observe the children in the consultation room. However, in this way, we are only able to capture a snapshot within the hospital environment of the involuntary movements. Therefore we are seeking for options to measure movements within the natural environment of the children (such as home and school), and to automatize the evaluation to make it not too time consuming for the doctors.&lt;/p&gt;
&lt;p&gt;Activity recognition applications using sensors integrated in smartphones and smartwatches for sports and fitness are increasingly used and could possibly serve this purpose. Machine learning models integrated in the devices can distinguish between movements such as walking, jogging, climbing, running and swimming. Hence, such sensors might be a good candidate to detect and monitor the involuntary movements of Simone while playing Ludo. Furthermore, as also information extracted from videos could be useful, parents could easily film children at home with their smartphones, to obtain additional information.&lt;/p&gt;
&lt;p&gt;We have recently started to explore the possibilities for automatic detection of involuntary movements in children with dyskinetic cerebral palsy in the home situation. &lt;a href=&quot;https://www.zonmw.nl/nl/&quot;&gt;ZonMw&lt;/a&gt; financed our project &lt;a href=&quot;https://www.zonmw.nl/nl/over-zonmw/e-health-en-ict-in-de-zorg/programmas/project-detail/imdi/home-based-measurements-of-dyskinesia-using-smartphone-coupled-inertial-sensor-technology-and-machin/&quot;&gt;MODYS@home&lt;/a&gt; to use smartwatch-like sensors at home for the assessment of involuntary movements. With this support, we could develop an app to measure sensor data together with synchronized videos during daily activities.&lt;/p&gt;
&lt;p&gt;We also received help from the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; within the ‘Open Call for Small-Scale Initiatives in Machine Learning’. Within this project called ‘Automated video-based movement assessment using machine learning to support personalized treatment of movement disorders’, we focus on the option to use videos. We use stick figure movies extracted from real videos.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1008&quot; height=&quot;351&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PTuJhzxNcKIFmheeUzrJ-Q-d856fa57.Ce9bToPd_1sDBMA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Real videos were selected from other projects, that had have been scored by the doctor for involuntary movements (dystonia) for the arms and legs. With these data we trained machine learning models to predict dystonia automatically.&lt;/p&gt;
&lt;p&gt;Using machine learning within the field of clinical movement analysis was something new for us, as not only the content was new, but also the style of working with stand-up meetings and sprints, sharing codes on Github and right away publishing our dataset. We gained new knowledge and skills that brings us a step forwards to find a way to measure children with dyskinetic cerebral palsy within their home environment.&lt;/p&gt;
&lt;p&gt;We are very excited about the results from a random forest regressor, “a traditional machine learning model” as such a model is called in the language used in machine learning world;-) See figure for the result: the true score by the doctor is plotted against the predicted value by the model. All scores on the diagonal line are predicted completely correct. The model is not perfect yet, but it shows the potential of the method and we are looking very much forward to further improve it.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;630&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KmttTsBaqVJTtIK0TcEPog-969729b8.DAoBIP9U_2rwg97.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Within our projects we work within a group of clinicians, researchers and software engineers from the &lt;a href=&quot;https://www.amsterdamumc.org/en/research/organization/about-amsterdam-umc.htm&quot;&gt;Amsterdam UMC&lt;/a&gt; (Annemieke Buizer, Laura Bonouvrié, Marjolein van der Krogt, Helga Haberfehlner, Shankara van der Ven, Dylan den Hartog), from the TU Delft (Jaap Harlaar), from &lt;a href=&quot;https://moveshelf.com/&quot;&gt;Moveshelf&lt;/a&gt; (Ignazio Aleo, Johannes Gijsbers) and the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; (&lt;a href=&quot;https://www.esciencecenter.nl/team/sven-van-der-burg/&quot;&gt;Sven van der Burg&lt;/a&gt;, Florian Huber and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-sonja-georgievska/&quot;&gt;Sonja Georgievska&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you are interested in more technical details please have a look at our &lt;a href=&quot;https://zenodo.org/deposit/5638470&quot;&gt;stick figure dataset&lt;/a&gt;. All contribution to our &lt;a href=&quot;https://github.com/RehabAUmc/modys-video&quot;&gt;code&lt;/a&gt; is welcome, to help Simone to play Ludo without overthrowing the tokens!&lt;/p&gt;</description><pubDate>Thu, 31 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;629&quot; height=&quot;626&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ii34FkLcmA3bYfAhLaNzZw-f35a5f15.9C07PfCF_Z2ssRMh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simone is a 12 year old girl. She loves to play Ludo with her mum, dad and her little brother. However, when she pushes the dice switch in the middle of the Ludo board game, she cannot properly control her movements and the tokens sometimes fall from the board. Simone also does not succeed to move the tokens, so her dad does that for her. Simone has &lt;a href=&quot;https://cerebralpalsy.org.au/our-research/about-cerebral-palsy/what-is-cerebral-palsy/types-of-cerebral-palsy/dyskinetic-cerebral-palsy/&quot;&gt;dyskinetic cerebral palsy&lt;/a&gt;, due to a lack of oxygen around birth. &lt;a href=&quot;https://www.youtube.com/watch?v=-2ODMPVjnI8&quot;&gt;Involuntary movements&lt;/a&gt; (called dystonia and choreo-athetosis) disturb her during daily activities such as playing Ludo.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://www.amc.nl/web/home.htm&quot;&gt;Amsterdam UMC&lt;/a&gt;, we treat children with severe dyskinetic cerebral palsy with medication that is directly delivered into the spinal canal by an indwelling pump (intrathecal baclofen). This treatment has been shown to be &lt;a href=&quot;https://research.vumc.nl/en/publications/the-effect-of-intrathecal-baclofen-in-dyskinetic-cerebral-palsy-t&quot;&gt;effective in reaching individual goals&lt;/a&gt; (such as not overthrowing the tokens when playing Ludo). However, we currently have a hard time to exactly monitor the involuntary movements and the effect of treatments on them. This monitoring is very important to give the right doses of medication. During check-ups at the hospital, doctors ask parents and children, how movements evolve and observe the children in the consultation room. However, in this way, we are only able to capture a snapshot within the hospital environment of the involuntary movements. Therefore we are seeking for options to measure movements within the natural environment of the children (such as home and school), and to automatize the evaluation to make it not too time consuming for the doctors.&lt;/p&gt;
&lt;p&gt;Activity recognition applications using sensors integrated in smartphones and smartwatches for sports and fitness are increasingly used and could possibly serve this purpose. Machine learning models integrated in the devices can distinguish between movements such as walking, jogging, climbing, running and swimming. Hence, such sensors might be a good candidate to detect and monitor the involuntary movements of Simone while playing Ludo. Furthermore, as also information extracted from videos could be useful, parents could easily film children at home with their smartphones, to obtain additional information.&lt;/p&gt;
&lt;p&gt;We have recently started to explore the possibilities for automatic detection of involuntary movements in children with dyskinetic cerebral palsy in the home situation. &lt;a href=&quot;https://www.zonmw.nl/nl/&quot;&gt;ZonMw&lt;/a&gt; financed our project &lt;a href=&quot;https://www.zonmw.nl/nl/over-zonmw/e-health-en-ict-in-de-zorg/programmas/project-detail/imdi/home-based-measurements-of-dyskinesia-using-smartphone-coupled-inertial-sensor-technology-and-machin/&quot;&gt;MODYS@home&lt;/a&gt; to use smartwatch-like sensors at home for the assessment of involuntary movements. With this support, we could develop an app to measure sensor data together with synchronized videos during daily activities.&lt;/p&gt;
&lt;p&gt;We also received help from the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; within the ‘Open Call for Small-Scale Initiatives in Machine Learning’. Within this project called ‘Automated video-based movement assessment using machine learning to support personalized treatment of movement disorders’, we focus on the option to use videos. We use stick figure movies extracted from real videos.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1008&quot; height=&quot;351&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PTuJhzxNcKIFmheeUzrJ-Q-d856fa57.Ce9bToPd_1sDBMA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Real videos were selected from other projects, that had have been scored by the doctor for involuntary movements (dystonia) for the arms and legs. With these data we trained machine learning models to predict dystonia automatically.&lt;/p&gt;
&lt;p&gt;Using machine learning within the field of clinical movement analysis was something new for us, as not only the content was new, but also the style of working with stand-up meetings and sprints, sharing codes on Github and right away publishing our dataset. We gained new knowledge and skills that brings us a step forwards to find a way to measure children with dyskinetic cerebral palsy within their home environment.&lt;/p&gt;
&lt;p&gt;We are very excited about the results from a random forest regressor, “a traditional machine learning model” as such a model is called in the language used in machine learning world;-) See figure for the result: the true score by the doctor is plotted against the predicted value by the model. All scores on the diagonal line are predicted completely correct. The model is not perfect yet, but it shows the potential of the method and we are looking very much forward to further improve it.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;630&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KmttTsBaqVJTtIK0TcEPog-969729b8.DAoBIP9U_2rwg97.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Within our projects we work within a group of clinicians, researchers and software engineers from the &lt;a href=&quot;https://www.amsterdamumc.org/en/research/organization/about-amsterdam-umc.htm&quot;&gt;Amsterdam UMC&lt;/a&gt; (Annemieke Buizer, Laura Bonouvrié, Marjolein van der Krogt, Helga Haberfehlner, Shankara van der Ven, Dylan den Hartog), from the TU Delft (Jaap Harlaar), from &lt;a href=&quot;https://moveshelf.com/&quot;&gt;Moveshelf&lt;/a&gt; (Ignazio Aleo, Johannes Gijsbers) and the &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; (&lt;a href=&quot;https://www.esciencecenter.nl/team/sven-van-der-burg/&quot;&gt;Sven van der Burg&lt;/a&gt;, Florian Huber and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-sonja-georgievska/&quot;&gt;Sonja Georgievska&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you are interested in more technical details please have a look at our &lt;a href=&quot;https://zenodo.org/deposit/5638470&quot;&gt;stick figure dataset&lt;/a&gt;. All contribution to our &lt;a href=&quot;https://github.com/RehabAUmc/modys-video&quot;&gt;code&lt;/a&gt; is welcome, to help Simone to play Ludo without overthrowing the tokens!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_PTuJhzxNcKIFmheeUzrJ-Q-d856fa57.Ce9bToPd.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>How to find your Artificial Intelligence explainer</title><link>https://blog.esciencecenter.nl/posts/2022-03-21---how-to-find-your-artificial-intelligence-explainer</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-03-21---how-to-find-your-artificial-intelligence-explainer</guid><description>&lt;p&gt;Here, we will use the LRP method to illustrate the principle of determining which features in an input contribute most strongly to the output of a trained DNN model. In this example, the input to the network is an image.** We are interested in figuring out the relevance* of each image pixel to a given image class. This could be the final DNN classification decision for that image (“cat”) or any other class known to the model (e.g. “dog”, “cow”, “bee”, etc. if the model is trained to classify animals). The output relevance is considered a weighted sum of the relevancies of all the &lt;strong&gt;pixels&lt;/strong&gt; of the input image. The relevance at the output node in the network graph is decomposed by iterative propagation backward through the network layers until the input layer. The trained model weights are used in this decomposition. Using this &lt;em&gt;relevance propagation&lt;/em&gt; process, the final *relevance scores map *(&lt;em&gt;or heatmap&lt;/em&gt;) is obtained. The final relevance map gives us an indication for the DNN’s hidden logic.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;157&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-2cffbfad.DW7BdbFW_1h3U9m.webp&quot; srcset=&quot;&quot;&gt;
Relevance scores of the image pixels in respect to the class “cat” obtained via relevance propagation.Besides LRP, there are many other XAI methods, which use different ways of determining relevance. In order to determine which of the plethora of post-hoc XAI methods to include in DIANNA, we started by compiling an initial list of 18 XAI post-hoc feature-relevance methods following &lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S1566253519308103&quot;&gt;&lt;em&gt;Arrieta et al. (2020)&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deep Taylor decomposition (DTD):&lt;/strong&gt; &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S0031320316303582&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://www.youtube.com/watch?v=gy_Cb4Do_YE&quot;&gt;Presentation&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcoancona/DeepExplain&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Layer-wise Relevance Propagation (LRP): **&lt;a href=&quot;https://journals.plos.org/plosone/article?id=10.1371%2Fjournal.pone.0130140&quot;&gt;Paper&lt;/a&gt;|&lt;a href=&quot;http://danshiebler.com/2017-04-16-deep-taylor-lrp/&quot;&gt;Blog&lt;/a&gt;| &lt;a href=&quot;https://github.com/albermax/innvestigate&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Integrated Gradients (IG): **&lt;a href=&quot;https://arxiv.org/pdf/1703.01365.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://captum.ai/docs/extension/integrated_gradients/&quot;&gt;Tutorial&lt;/a&gt;| &lt;a href=&quot;https://github.com/pytorch/captum&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Interpretable Model-agnostic Explanations (LIME):&lt;/strong&gt; &lt;a href=&quot;https://arxiv.org/abs/1602.04938&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://towardsdatascience.com/lime-how-to-interpret-machine-learning-models-with-python-94b0e7e4432e&quot;&gt;Blog&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcotcr/lime&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**SHapley Additive exPlanations (SHAP): **&lt;a href=&quot;https://arxiv.org/abs/1705.07874&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://towardsdatascience.com/shap-how-to-interpret-machine-learning-models-with-python-2323f5af4be9&quot;&gt;Blog&lt;/a&gt;|&lt;a href=&quot;https://github.com/slundberg/shap&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**PatternNet &lt;strong&gt;and&lt;/strong&gt; PatternAttribution: **&lt;a href=&quot;https://arxiv.org/pdf/1705.05598.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/albermax/innvestigate&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deep Learning Important FeaTures (DeepLIFT):&lt;/strong&gt; &lt;a href=&quot;https://arxiv.org/pdf/1704.02685.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;http://goo.gl/qKb7pL&quot;&gt;Tutorial&lt;/a&gt;| &lt;a href=&quot;https://vimeo.com/238275076&quot;&gt;Presentation&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcoancona/DeepExplain&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**SmoothGrad: **&lt;a href=&quot;https://arxiv.org/abs/1706.03825&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://pair-code.github.io/saliency/&quot;&gt;Demo&lt;/a&gt;| &lt;a href=&quot;https://github.com/pair-code/saliency&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**CLass-Enhanced Attentive Response(CLEAR): **&lt;a href=&quot;https://openaccess.thecvf.com/content_cvpr_2017_workshops/w26/papers/Kumar_Explaining_the_Unexplained_CVPR_2017_paper.pdf&quot;&gt;Paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(Adaptive) deconvolutional network (Deconvnet):&lt;/strong&gt; [Paper](&lt;a href=&quot;https://link.springer.com/content/pdf/10.1007/978-3-319-10590-1_53.pdf&quot;&gt;https://link.springer.com/content/pdf/10.1007/978-3-319-10590-1_53.pdf&lt;/a&gt; &lt;a href=&quot;https://www.matthewzeiler.com/mattzeiler/adaptivedeconvolutional.pdf&quot;&gt;https://www.matthewzeiler.com/mattzeiler/adaptivedeconvolutional.pdf&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;**Gradient-weighted Class Activation Mapping (Grad-CAM): **&lt;a href=&quot;https://ieeexplore.ieee.org/document/8237336&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://www.pyimagesearch.com/2020/03/09/grad-cam-visualize-class-activation-maps-with-keras-tensorflow-and-deep-learning/&quot;&gt;Blog&lt;/a&gt;|&lt;a href=&quot;https://github.com/ramprs/grad-cam/&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Randomized input sampling for explanation of black-box models (RISE): **&lt;a href=&quot;https://arxiv.org/abs/1806.07421&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/facebookresearch/TorchRay&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Extremal Perturbations (EP)| &lt;a href=&quot;https://openaccess.thecvf.com/content_ICCV_2019/papers/Fong_Understanding_Deep_Networks_via_Extremal_Perturbations_and_Smooth_Masks_ICCV_2019_paper.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/facebookresearch/TorchRay&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Saliency Analysis (SA): &lt;a href=&quot;https://arxiv.org/pdf/1312.6034.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/osu-xai/pytorch-saliency&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Anchors: &lt;a href=&quot;https://homes.cs.washington.edu/~marcotcr/aaai18.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/viadee/javaAnchorExplainer&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deep visualization: &lt;a href=&quot;https://arxiv.org/pdf/1506.06579.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://yosinski.com/deepvis&quot;&gt;Demo&lt;/a&gt;| &lt;a href=&quot;https://github.com/yosinski/deep-visualization-toolbox&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AutomaticSTRucture IDentification (ASTRID): &lt;a href=&quot;https://arxiv.org/pdf/1707.07576.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/bwrc/astrid-r&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We excluded all XAI methods without a working and well-maintained open-source implementation or proven user community. That resulted in a subset of the &lt;strong&gt;13 methods&lt;/strong&gt; highlighted above.&lt;/p&gt;
&lt;h3 id=&quot;evaluation-criteria&quot;&gt;&lt;em&gt;&lt;strong&gt;Evaluation criteria&lt;/strong&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The large variety of XAI approaches benefits the AI community by providing freedom in the search for explainability. However, it also increases the difficulty of choosing the most appropriate method for each use case. Every XAI approach has pros and cons. In order to select the best methods for our task, we needed a framework to evaluate these methods systematically. Fortunately, this topic has already been visited by the XAI researchers and there is an extensive list of objective criteria defined in the &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;Explainability fact sheet&lt;/a&gt; paper [&lt;em&gt;Sokol, K., &amp;#x26; Flach, P. (2020)&lt;/em&gt;]. The authors look at an abundant set of XAI aspects and cluster the requirements towards an explainer into **5 groups **(or &lt;strong&gt;dimensions&lt;/strong&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functional (F1-F9)&lt;/li&gt;
&lt;li&gt;Operational (O1-O10)&lt;/li&gt;
&lt;li&gt;Usability (U1-U11)&lt;/li&gt;
&lt;li&gt;Safety (S1-S4)&lt;/li&gt;
&lt;li&gt;Validation (V1-V2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each dimension, there are specific criteria, e.g. the “Functional” group has 9 and in total there are 36 criteria. We will describe our choices next.&lt;/p&gt;
&lt;h3 id=&quot;the-selection&quot;&gt;&lt;em&gt;&lt;strong&gt;The selection&lt;/strong&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;In our &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA project&lt;/a&gt;, we built a Python package that brings XAI to non (X)AI experts and various scientific domain researchers. The XAI methods to be included in the package had to have the capacity to work with different types of data, various AI architectures and we chose to focus on the model explanation. Most importantly, the resulting explanations had to be easy to interpret. Based on our goals, we have compiled a shortlist of &lt;strong&gt;18 requirements&lt;/strong&gt; from the 36 requirements in the &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;XAI fact sheet&lt;/a&gt;. Using these relevant for our target users’ requirements, we evaluated the selected 13 methods listed in the XAI overview section.&lt;/p&gt;
&lt;p&gt;Apart from the requirements on the list, we have also considered the similarity and the “popularity” of these methods, the quality of the existing implementations, and the difficulty of integrating them in DIANNA. The evaluation procedure can be summarized with the table shown below: (&lt;strong&gt;Deconvnet&lt;/strong&gt; and &lt;strong&gt;GradCAM&lt;/strong&gt; are filtered out since they can only work with Convolutional NNs and are therefore not included in the table.)&lt;/p&gt;
&lt;p&gt;Finally, we narrowed down our list to &lt;strong&gt;5 methods:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Layer-wise Relevance Propagation (LRP)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Interpretable Model-agnostic Explanations (LIME)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SHapley Additive exPlanations (SHAP)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PatternAttribution (PA)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Randomized input sampling for explanation of black-box models (RISE)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Within limited project time, we were able to include three of them in our &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA library&lt;/a&gt;: RISE, LIME &amp;#x26; SHAP. A preview of the explanations that we obtained using our DIANNA library is shown below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;216&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-72ccdcf5.VxZ-XezX_rQBVl.webp&quot; srcset=&quot;&quot;&gt;
Explanation for “0” with RISE, LIME, and SHAP using DIANNA library for a model trained on binary MNIST data. Red indicates high or positive relevance, blue- low or negative.We could observe that the methods are complimentary to each other in respect to their output, which can be particularly useful for researchers seeking new insights to their data and problem. We also believe that simpler datasets, e.g. a binary (only 0s and 1s) MNIST should be used as “Hello world” example for the XAI (user) community!&lt;/p&gt;
&lt;p&gt;Our library is open-source and it is ready to help you decrypt your neural network models. Wait, you want to ask which format do we support? TensorFlow? PyTorch? Don’t worry. We can work with all of them, as we support &lt;a href=&quot;https://onnx.ai/&quot;&gt;ONNX&lt;/a&gt; — the de-facto DNN format standard! Any contributions to our repository are very welcome (talk is cheap, show me your pull request! Want to give it a try? Check out the link below our logo!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;204&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-004f98d9.CAfAdrtE_Lvn9v.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;https://github.com/dianna-ai/dianna&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h3&gt;
&lt;p&gt;The work described in this blog has been performed by the members of the DIANNA team: &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;Christiaan Meijer&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0001-8724-8372&quot;&gt;Leon Oostrum&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0002-1966-8460&quot;&gt;Yang Liu &lt;/a&gt;and &lt;a href=&quot;https://orcid.org/0000-0002-9834-1756&quot;&gt;Elena Ranguelova&lt;/a&gt; with the big help of &lt;a href=&quot;https://orcid.org/0000-0002-6033-960X&quot;&gt;Patrick Bos&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/0000-0002-0823-0121&quot;&gt;Giulia Crocioni&lt;/a&gt;. Special thanks to &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;Christiaan Meijer&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0002-0823-0121&quot;&gt;Giulia Crocioni&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0001-6022-0046&quot;&gt;Matthieu Laneuville,&lt;/a&gt; &lt;a href=&quot;https://orcid.org/0000-0002-2855-940X&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/my-orcid?orcid=0000-0003-3381-2040&quot;&gt;Lieke de Boer&lt;/a&gt; for their valuable contributions. The DIANNA project is supported by &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;&lt;em&gt;References&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;[&lt;em&gt;&lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S1566253519308103&quot;&gt;Arrieta et al. (2020)*&lt;/a&gt;&lt;/em&gt;] Arrieta, A. B., Díaz-Rodríguez, N., Del Ser, J., Bennetot, A., Tabik, S., Barbado, A., … &amp;#x26; Herrera, F. (2020). Explainable Artificial Intelligence (XAI): Concepts, taxonomies, opportunities and challenges toward responsible AI. Information fusion, 58, pp. 82–115.[&lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;Sokol, K., &amp;#x26; Flach, P. (2020)*&lt;/a&gt;] &lt;em&gt;Sokol, K., &amp;#x26; Flach, P. (2020, January). Explainability fact sheets: a framework for systematic assessment of explainable approaches. In Proceedings of the 2020 Conference on Fairness, Accountability, and Transparency, pp. 56–67.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 21 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here, we will use the LRP method to illustrate the principle of determining which features in an input contribute most strongly to the output of a trained DNN model. In this example, the input to the network is an image.** We are interested in figuring out the relevance* of each image pixel to a given image class. This could be the final DNN classification decision for that image (“cat”) or any other class known to the model (e.g. “dog”, “cow”, “bee”, etc. if the model is trained to classify animals). The output relevance is considered a weighted sum of the relevancies of all the &lt;strong&gt;pixels&lt;/strong&gt; of the input image. The relevance at the output node in the network graph is decomposed by iterative propagation backward through the network layers until the input layer. The trained model weights are used in this decomposition. Using this &lt;em&gt;relevance propagation&lt;/em&gt; process, the final *relevance scores map *(&lt;em&gt;or heatmap&lt;/em&gt;) is obtained. The final relevance map gives us an indication for the DNN’s hidden logic.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;157&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-2cffbfad.DW7BdbFW_1h3U9m.webp&quot; srcset=&quot;&quot;&gt;
Relevance scores of the image pixels in respect to the class “cat” obtained via relevance propagation.Besides LRP, there are many other XAI methods, which use different ways of determining relevance. In order to determine which of the plethora of post-hoc XAI methods to include in DIANNA, we started by compiling an initial list of 18 XAI post-hoc feature-relevance methods following &lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S1566253519308103&quot;&gt;&lt;em&gt;Arrieta et al. (2020)&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deep Taylor decomposition (DTD):&lt;/strong&gt; &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S0031320316303582&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://www.youtube.com/watch?v=gy_Cb4Do_YE&quot;&gt;Presentation&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcoancona/DeepExplain&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Layer-wise Relevance Propagation (LRP): **&lt;a href=&quot;https://journals.plos.org/plosone/article?id=10.1371%2Fjournal.pone.0130140&quot;&gt;Paper&lt;/a&gt;|&lt;a href=&quot;http://danshiebler.com/2017-04-16-deep-taylor-lrp/&quot;&gt;Blog&lt;/a&gt;| &lt;a href=&quot;https://github.com/albermax/innvestigate&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Integrated Gradients (IG): **&lt;a href=&quot;https://arxiv.org/pdf/1703.01365.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://captum.ai/docs/extension/integrated_gradients/&quot;&gt;Tutorial&lt;/a&gt;| &lt;a href=&quot;https://github.com/pytorch/captum&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Interpretable Model-agnostic Explanations (LIME):&lt;/strong&gt; &lt;a href=&quot;https://arxiv.org/abs/1602.04938&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://towardsdatascience.com/lime-how-to-interpret-machine-learning-models-with-python-94b0e7e4432e&quot;&gt;Blog&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcotcr/lime&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**SHapley Additive exPlanations (SHAP): **&lt;a href=&quot;https://arxiv.org/abs/1705.07874&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://towardsdatascience.com/shap-how-to-interpret-machine-learning-models-with-python-2323f5af4be9&quot;&gt;Blog&lt;/a&gt;|&lt;a href=&quot;https://github.com/slundberg/shap&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**PatternNet &lt;strong&gt;and&lt;/strong&gt; PatternAttribution: **&lt;a href=&quot;https://arxiv.org/pdf/1705.05598.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/albermax/innvestigate&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deep Learning Important FeaTures (DeepLIFT):&lt;/strong&gt; &lt;a href=&quot;https://arxiv.org/pdf/1704.02685.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;http://goo.gl/qKb7pL&quot;&gt;Tutorial&lt;/a&gt;| &lt;a href=&quot;https://vimeo.com/238275076&quot;&gt;Presentation&lt;/a&gt;| &lt;a href=&quot;https://github.com/marcoancona/DeepExplain&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**SmoothGrad: **&lt;a href=&quot;https://arxiv.org/abs/1706.03825&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://pair-code.github.io/saliency/&quot;&gt;Demo&lt;/a&gt;| &lt;a href=&quot;https://github.com/pair-code/saliency&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**CLass-Enhanced Attentive Response(CLEAR): **&lt;a href=&quot;https://openaccess.thecvf.com/content_cvpr_2017_workshops/w26/papers/Kumar_Explaining_the_Unexplained_CVPR_2017_paper.pdf&quot;&gt;Paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(Adaptive) deconvolutional network (Deconvnet):&lt;/strong&gt; [Paper](&lt;a href=&quot;https://link.springer.com/content/pdf/10.1007/978-3-319-10590-1_53.pdf&quot;&gt;https://link.springer.com/content/pdf/10.1007/978-3-319-10590-1_53.pdf&lt;/a&gt; &lt;a href=&quot;https://www.matthewzeiler.com/mattzeiler/adaptivedeconvolutional.pdf&quot;&gt;https://www.matthewzeiler.com/mattzeiler/adaptivedeconvolutional.pdf&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;**Gradient-weighted Class Activation Mapping (Grad-CAM): **&lt;a href=&quot;https://ieeexplore.ieee.org/document/8237336&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://www.pyimagesearch.com/2020/03/09/grad-cam-visualize-class-activation-maps-with-keras-tensorflow-and-deep-learning/&quot;&gt;Blog&lt;/a&gt;|&lt;a href=&quot;https://github.com/ramprs/grad-cam/&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**Randomized input sampling for explanation of black-box models (RISE): **&lt;a href=&quot;https://arxiv.org/abs/1806.07421&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/facebookresearch/TorchRay&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Extremal Perturbations (EP)| &lt;a href=&quot;https://openaccess.thecvf.com/content_ICCV_2019/papers/Fong_Understanding_Deep_Networks_via_Extremal_Perturbations_and_Smooth_Masks_ICCV_2019_paper.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/facebookresearch/TorchRay&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Saliency Analysis (SA): &lt;a href=&quot;https://arxiv.org/pdf/1312.6034.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/osu-xai/pytorch-saliency&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Anchors: &lt;a href=&quot;https://homes.cs.washington.edu/~marcotcr/aaai18.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/viadee/javaAnchorExplainer&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deep visualization: &lt;a href=&quot;https://arxiv.org/pdf/1506.06579.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://yosinski.com/deepvis&quot;&gt;Demo&lt;/a&gt;| &lt;a href=&quot;https://github.com/yosinski/deep-visualization-toolbox&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AutomaticSTRucture IDentification (ASTRID): &lt;a href=&quot;https://arxiv.org/pdf/1707.07576.pdf&quot;&gt;Paper&lt;/a&gt;| &lt;a href=&quot;https://github.com/bwrc/astrid-r&quot;&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We excluded all XAI methods without a working and well-maintained open-source implementation or proven user community. That resulted in a subset of the &lt;strong&gt;13 methods&lt;/strong&gt; highlighted above.&lt;/p&gt;
&lt;h3 id=&quot;evaluation-criteria&quot;&gt;&lt;em&gt;&lt;strong&gt;Evaluation criteria&lt;/strong&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The large variety of XAI approaches benefits the AI community by providing freedom in the search for explainability. However, it also increases the difficulty of choosing the most appropriate method for each use case. Every XAI approach has pros and cons. In order to select the best methods for our task, we needed a framework to evaluate these methods systematically. Fortunately, this topic has already been visited by the XAI researchers and there is an extensive list of objective criteria defined in the &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;Explainability fact sheet&lt;/a&gt; paper [&lt;em&gt;Sokol, K., &amp;#x26; Flach, P. (2020)&lt;/em&gt;]. The authors look at an abundant set of XAI aspects and cluster the requirements towards an explainer into **5 groups **(or &lt;strong&gt;dimensions&lt;/strong&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functional (F1-F9)&lt;/li&gt;
&lt;li&gt;Operational (O1-O10)&lt;/li&gt;
&lt;li&gt;Usability (U1-U11)&lt;/li&gt;
&lt;li&gt;Safety (S1-S4)&lt;/li&gt;
&lt;li&gt;Validation (V1-V2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each dimension, there are specific criteria, e.g. the “Functional” group has 9 and in total there are 36 criteria. We will describe our choices next.&lt;/p&gt;
&lt;h3 id=&quot;the-selection&quot;&gt;&lt;em&gt;&lt;strong&gt;The selection&lt;/strong&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;In our &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA project&lt;/a&gt;, we built a Python package that brings XAI to non (X)AI experts and various scientific domain researchers. The XAI methods to be included in the package had to have the capacity to work with different types of data, various AI architectures and we chose to focus on the model explanation. Most importantly, the resulting explanations had to be easy to interpret. Based on our goals, we have compiled a shortlist of &lt;strong&gt;18 requirements&lt;/strong&gt; from the 36 requirements in the &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;XAI fact sheet&lt;/a&gt;. Using these relevant for our target users’ requirements, we evaluated the selected 13 methods listed in the XAI overview section.&lt;/p&gt;
&lt;p&gt;Apart from the requirements on the list, we have also considered the similarity and the “popularity” of these methods, the quality of the existing implementations, and the difficulty of integrating them in DIANNA. The evaluation procedure can be summarized with the table shown below: (&lt;strong&gt;Deconvnet&lt;/strong&gt; and &lt;strong&gt;GradCAM&lt;/strong&gt; are filtered out since they can only work with Convolutional NNs and are therefore not included in the table.)&lt;/p&gt;
&lt;p&gt;Finally, we narrowed down our list to &lt;strong&gt;5 methods:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Layer-wise Relevance Propagation (LRP)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Interpretable Model-agnostic Explanations (LIME)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SHapley Additive exPlanations (SHAP)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PatternAttribution (PA)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Randomized input sampling for explanation of black-box models (RISE)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Within limited project time, we were able to include three of them in our &lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;DIANNA library&lt;/a&gt;: RISE, LIME &amp;#x26; SHAP. A preview of the explanations that we obtained using our DIANNA library is shown below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;216&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-72ccdcf5.VxZ-XezX_rQBVl.webp&quot; srcset=&quot;&quot;&gt;
Explanation for “0” with RISE, LIME, and SHAP using DIANNA library for a model trained on binary MNIST data. Red indicates high or positive relevance, blue- low or negative.We could observe that the methods are complimentary to each other in respect to their output, which can be particularly useful for researchers seeking new insights to their data and problem. We also believe that simpler datasets, e.g. a binary (only 0s and 1s) MNIST should be used as “Hello world” example for the XAI (user) community!&lt;/p&gt;
&lt;p&gt;Our library is open-source and it is ready to help you decrypt your neural network models. Wait, you want to ask which format do we support? TensorFlow? PyTorch? Don’t worry. We can work with all of them, as we support &lt;a href=&quot;https://onnx.ai/&quot;&gt;ONNX&lt;/a&gt; — the de-facto DNN format standard! Any contributions to our repository are very welcome (talk is cheap, show me your pull request! Want to give it a try? Check out the link below our logo!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your Artificial Intelligence explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;204&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-004f98d9.CAfAdrtE_Lvn9v.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://github.com/dianna-ai/dianna&quot;&gt;https://github.com/dianna-ai/dianna&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h3&gt;
&lt;p&gt;The work described in this blog has been performed by the members of the DIANNA team: &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;Christiaan Meijer&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0001-8724-8372&quot;&gt;Leon Oostrum&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0002-1966-8460&quot;&gt;Yang Liu &lt;/a&gt;and &lt;a href=&quot;https://orcid.org/0000-0002-9834-1756&quot;&gt;Elena Ranguelova&lt;/a&gt; with the big help of &lt;a href=&quot;https://orcid.org/0000-0002-6033-960X&quot;&gt;Patrick Bos&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/0000-0002-0823-0121&quot;&gt;Giulia Crocioni&lt;/a&gt;. Special thanks to &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;Christiaan Meijer&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0002-0823-0121&quot;&gt;Giulia Crocioni&lt;/a&gt;, &lt;a href=&quot;https://orcid.org/0000-0001-6022-0046&quot;&gt;Matthieu Laneuville,&lt;/a&gt; &lt;a href=&quot;https://orcid.org/0000-0002-2855-940X&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/my-orcid?orcid=0000-0003-3381-2040&quot;&gt;Lieke de Boer&lt;/a&gt; for their valuable contributions. The DIANNA project is supported by &lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt; and &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;&lt;em&gt;References&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;[&lt;em&gt;&lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S1566253519308103&quot;&gt;Arrieta et al. (2020)*&lt;/a&gt;&lt;/em&gt;] Arrieta, A. B., Díaz-Rodríguez, N., Del Ser, J., Bennetot, A., Tabik, S., Barbado, A., … &amp;#x26; Herrera, F. (2020). Explainable Artificial Intelligence (XAI): Concepts, taxonomies, opportunities and challenges toward responsible AI. Information fusion, 58, pp. 82–115.[&lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3351095.3372870&quot;&gt;Sokol, K., &amp;#x26; Flach, P. (2020)*&lt;/a&gt;] &lt;em&gt;Sokol, K., &amp;#x26; Flach, P. (2020, January). Explainability fact sheets: a framework for systematic assessment of explainable approaches. In Proceedings of the 2020 Conference on Fairness, Accountability, and Transparency, pp. 56–67.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-to-find-your-artificial-intelligence-2cffbfad.DW7BdbFW.png" medium="image"/><author>Elena Ranguelova</author></item><item><title>How to find your rubber duck: Using machine learning to understand a changing sea</title><link>https://blog.esciencecenter.nl/posts/2022-03-11---how-to-find-your-rubber-duck-using-machine-learning-to-under</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-03-11---how-to-find-your-rubber-duck-using-machine-learning-to-under</guid><description>&lt;p&gt;To get a quick start, they applied for the eScience Center Small-Scale Initiative (SSI), and were awarded consultancy on their project titled “Machine Learning for the complex response of the Wadden Sea*”. A first goal for the group was to determine what can machine learning actually do and which machine learning tools the group would need for this to happen. After all, machine learning is not magic. The group found great discussion partners in the eScience Center engineers.&lt;/p&gt;
&lt;p&gt;They decided to focus on two main questions: First, if machine learning can predict the daily averaged state of the Wadden Sea if we know the forcing. Second, if we can predict the trajectories of particles in the Wadden Sea with machine learning.&lt;/p&gt;
&lt;p&gt;The most suitable tool to answer these questions were Long short-term memory (LSTM) artificial recurrent neural network (RNN). Using LSTM is essential because the current state of the Wadden Sea not only depends on the current forcing (e.g., the wind); it also depends on the history of the system. The engineers at ESC have helped to set up the first models.&lt;/p&gt;
&lt;h2 id=&quot;one-additional-complication-particle-trajectories-are-chaotic&quot;&gt;One additional complication: particle trajectories are chaotic&lt;/h2&gt;
&lt;p&gt;It is well known that particle trajectories in the ocean are chaotic. This means that two particles starting close together (either in time or space) will eventually have very different trajectories. In fact, one of the first observations of this phenomenon are due to cargo falling out of ships (just like it happened in 2021 in the North Sea). In 1992, a cargo ship container tumbled into the North Pacific, dumping 28,000 rubber ducks and other bath toys. These rubber ducks ended up in beaches all around the world in, for example, Hawaii, Alaska, Chile, Ireland.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your rubber duck: Using machine learning to understand a changing sea&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;566&quot; height=&quot;390&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-rubber-duck-using-machi-0e922506.N1HiEdUP_Z1nxAr6.webp&quot; srcset=&quot;&quot;&gt;
*A few of the particles released close to the sluice in Den Oever on May 1st, 2009. The particles start very close together but end up in very different places after a few days.*One of the open questions that the group is currently exploring is up to which point machine learning can be used to capture chaotic particle trajectories.&lt;/p&gt;
&lt;p&gt;We are excited to see future outcomes of this project and would like to thank Dr. Matias Duran Matute and his colleagues for this contribution to our blog.&lt;/p&gt;</description><pubDate>Fri, 11 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To get a quick start, they applied for the eScience Center Small-Scale Initiative (SSI), and were awarded consultancy on their project titled “Machine Learning for the complex response of the Wadden Sea*”. A first goal for the group was to determine what can machine learning actually do and which machine learning tools the group would need for this to happen. After all, machine learning is not magic. The group found great discussion partners in the eScience Center engineers.&lt;/p&gt;
&lt;p&gt;They decided to focus on two main questions: First, if machine learning can predict the daily averaged state of the Wadden Sea if we know the forcing. Second, if we can predict the trajectories of particles in the Wadden Sea with machine learning.&lt;/p&gt;
&lt;p&gt;The most suitable tool to answer these questions were Long short-term memory (LSTM) artificial recurrent neural network (RNN). Using LSTM is essential because the current state of the Wadden Sea not only depends on the current forcing (e.g., the wind); it also depends on the history of the system. The engineers at ESC have helped to set up the first models.&lt;/p&gt;
&lt;h2 id=&quot;one-additional-complication-particle-trajectories-are-chaotic&quot;&gt;One additional complication: particle trajectories are chaotic&lt;/h2&gt;
&lt;p&gt;It is well known that particle trajectories in the ocean are chaotic. This means that two particles starting close together (either in time or space) will eventually have very different trajectories. In fact, one of the first observations of this phenomenon are due to cargo falling out of ships (just like it happened in 2021 in the North Sea). In 1992, a cargo ship container tumbled into the North Pacific, dumping 28,000 rubber ducks and other bath toys. These rubber ducks ended up in beaches all around the world in, for example, Hawaii, Alaska, Chile, Ireland.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How to find your rubber duck: Using machine learning to understand a changing sea&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;566&quot; height=&quot;390&quot; src=&quot;https://blog.esciencecenter.nl/_astro/how-to-find-your-rubber-duck-using-machi-0e922506.N1HiEdUP_Z1nxAr6.webp&quot; srcset=&quot;&quot;&gt;
*A few of the particles released close to the sluice in Den Oever on May 1st, 2009. The particles start very close together but end up in very different places after a few days.*One of the open questions that the group is currently exploring is up to which point machine learning can be used to capture chaotic particle trajectories.&lt;/p&gt;
&lt;p&gt;We are excited to see future outcomes of this project and would like to thank Dr. Matias Duran Matute and his colleagues for this contribution to our blog.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/how-to-find-your-rubber-duck-using-machi-0e922506.N1HiEdUP.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Parsing Hebrew and Syriac morphology using Deep Learning</title><link>https://blog.esciencecenter.nl/posts/2022-03-11---parsing-hebrew-and-syriac-morphology-using-deep-learning</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-03-11---parsing-hebrew-and-syriac-morphology-using-deep-learning</guid><description>&lt;p&gt;State-of-the-art technology meets ancient literature&lt;/p&gt;
&lt;p&gt;This blog is part of our blog series: &lt;em&gt;The Small-Scale Initiative on Machine Learning, how did it go?,&lt;/em&gt; where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience. This week, the guest authors are Dr. &lt;a href=&quot;https://vu-nl.academia.edu/MartijnNaaijer&quot;&gt;Martijn Naaijer&lt;/a&gt; and Prof. &lt;a href=&quot;https://research.vu.nl/en/persons/willem-van-peursen&quot;&gt;Wido van Peursen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RCeTAIngNgdUP3P0-10f08def.CPhSLehR_Z2wfgdm.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Mick Haupt on Unsplash&lt;/p&gt;
&lt;p&gt;Over the past 40 years, the Eep Talstra Center for Bible and Computer (&lt;a href=&quot;http://etcbc.nl/&quot;&gt;ETCBC&lt;/a&gt;) has developed a richly annotated text of the Hebrew Bible. The annotations consist of features on the levels of words, phrases, clauses, and larger text units. Since a few years ago, this dataset is freely available and can be downloaded and processed with the Python package Text-Fabric¹.&lt;/p&gt;
&lt;p&gt;The ETCBC has the ambition to expand its dataset with other Hebrew and Syriac texts. However, annotating these texts is a labor-intensive task, and it is desirable to develop ways to speed up this process. In this project with the eScience Center, we opt to do this using machine learning. We use the Hebrew Bible to train a model capable of analyzing the Biblical Hebrew morphology. After the optimization of this model, we use the developed approach to apply it to Syriac texts, for which a relatively small annotated dataset is available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hebrew Bible&lt;/strong&gt;&lt;br&gt;
The Hebrew Bible is an ancient text, which is mostly written in, as the name already suggests, Biblical Hebrew. Mostly, but not only, as some parts are written in Biblical Aramaic. The Hebrew Bible consists of 39 books, which were written over the span of nearly a millennium (10th century BCE — 2nd century BCE). The oldest complete manuscript that is known to us is the so-called &lt;em&gt;Codex Leningradensis&lt;/em&gt; (1008–1009 CE). The text of this manuscript is widely used as the basis of research on the Hebrew Bible and Bible translations. This is also the text contained in the ETCBC dataset².&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Semitic languages&lt;/strong&gt;&lt;br&gt;
Syriac and Hebrew are relatively closely related Semitic languages, so it is expected that a method developed for Hebrew will also work for Syriac. The corpus of Classical Hebrew is relatively small, consisting of the Hebrew Bible, Ben Sira, the Dead Sea Scrolls and a number of inscriptions. In contrast, a vast corpus of Syriac literature has been transmitted to us, which makes it necessary to think about new approaches of analyzing these texts. Presently, the ETCBC databank contains a few annotated Syriac texts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hebrew morphology for computers&lt;/strong&gt;&lt;br&gt;
One of the first steps in the annotation process of new data for the ETCBC dataset is the analysis of word morphology, that is, the study of the words’ constituent parts³. This is done by distinguishing morphemes in words. The morphemes are encoded with various symbols added to the raw text.&lt;/p&gt;
&lt;p&gt;For example, this is the text of Genesis 17:4 in Hebrew:&lt;/p&gt;
&lt;p&gt;אני הנה בריתי אתך והיית לאב המון גוים&lt;/p&gt;
&lt;p&gt;This is called the consonantal text, which is the oldest part of the text.&lt;/p&gt;
&lt;p&gt;In the Middle Ages, some dots and lines above and under the letters were added. Those represent vowels and cantillation marks, small surrounding signs that clarify the pronunciation.&lt;/p&gt;
&lt;p&gt;אֲנִ֕י הִנֵּ֥ה בְרִיתִ֖י אִתָּ֑ךְ וְהָיִ֕יתָ לְאַ֖ב הֲמֹ֥ון גֹּויִֽם&lt;/p&gt;
&lt;p&gt;Generally, we work with a transcription of the text, called the ETCBC transcription. Here you see the vocalized transcription of Genesis 17:4:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ANIJ&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HIN.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RIJTIJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IT.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; W&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JIJT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AB&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AMOWN&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; G.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OWJIM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is the unvocalized transcription:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NJ&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HNH&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; BRJTJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;TK&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; WHJJT&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HMWN&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; GWJM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The analyzed form of this verse looks as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NJ&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HNH&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; BRJT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;J&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; W&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HJ&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;J&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HMWN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GWJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, we know that this may look non-sense to you, but stay with us. Everything will get clearer a few lines below.&lt;/p&gt;
&lt;p&gt;The analyzed sequence contains all the consonants from the unvocalized transcription, with a number of added signs. For example, the “=” signs are used to disambiguate lexemes, the “+” is used to separate a pronominal suffix from the rest of a word, and “-” is used to distinguish words that form a single graphical unit, which is often the case with prepositions and the following word. A number of other signs are used for distinguishing different types of morphemes.&lt;/p&gt;
&lt;p&gt;The analyzed form contains all the information that is needed to extract all the word-level features, such as verbal stem, verbal tense, person, number, gender, and part of speech. In this research, we want to obtain the fully analyzed form of a verse, using the raw vocalized or unvocalized text as input. It is to be expected that the vocalized text will produce more accurate outputs than the unvocalized text, because it simply contains more information. In many cases, an ambiguity in the consonantal text is disambiguated by the vowels.&lt;/p&gt;
&lt;p&gt;If the vocalized text contains more information than the unvocalized text, why do we use the unvocalized text anyway? Most texts in Hebrew and Syriac do not contain vowels, so if we want to use the results of this research in production, in general, the unvocalized texts are more important.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The project&lt;/strong&gt;&lt;br&gt;
Before the project started, we were experimenting already with producing the analyzed sequences using machine learning models, but the help of the eScience Center consultants Dafne van Kuppevelt and Jisk Attema has been invaluable for improving the results. Depending on the quality and amount of the input data, we have been able to increase the accuracy of the predicted forms in some experiments up to 97%.&lt;/p&gt;
&lt;p&gt;The consultants helped us implement new models that are used generally for translation tasks, such as LSTM (Long Short-Term Memory) and Transformer models. Also, they have helped with various refinements that improved the result, such as Beam Search and systematically tweaking the input data and hyperparameters of the models. The help of the consultants has resulted in a broader and more up-to-date view of the field of machine learning and to look further than just the most basic techniques.&lt;/p&gt;
&lt;p&gt;All in all, this SSI project has expanded our experience with machine learning techniques substantially. Armed with newly acquired skills and experiences, we can move forward and use this type of model in new projects, in which we can effectively produce analyzed Hebrew and Syriac data, not only with the goal of expanding the ETCBC dataset but also in other projects in which parallel language sequences play a role.&lt;/p&gt;
&lt;p&gt;[1]: For the Text-Fabric software, see: &lt;a href=&quot;https://github.com/annotation/text-fabric&quot;&gt;https://github.com/annotation/text-fabric&lt;/a&gt;, and for the dataset, see: &lt;a href=&quot;https://etcbc.github.io/bhsa.&quot;&gt;https://etcbc.github.io/bhsa.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2]: More precisely, it is the text of the fourth edition of the Biblia Hebraica Stuttgartensia (BHS). The Text-Fabric text edition with annotations is called Biblia Hebraica Stuttgartensia Amstelodamensis (BHSA).&lt;/p&gt;
&lt;p&gt;[3]: For a description of the data creation process, see: &lt;a href=&quot;http://www.etcbc.nl/datacreation.&quot;&gt;http://www.etcbc.nl/datacreation.&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 11 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;State-of-the-art technology meets ancient literature&lt;/p&gt;
&lt;p&gt;This blog is part of our blog series: &lt;em&gt;The Small-Scale Initiative on Machine Learning, how did it go?,&lt;/em&gt; where groups who were invited to participate in a project with eScience Center Research Software Engineers write about their projects and their experience. This week, the guest authors are Dr. &lt;a href=&quot;https://vu-nl.academia.edu/MartijnNaaijer&quot;&gt;Martijn Naaijer&lt;/a&gt; and Prof. &lt;a href=&quot;https://research.vu.nl/en/persons/willem-van-peursen&quot;&gt;Wido van Peursen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RCeTAIngNgdUP3P0-10f08def.CPhSLehR_Z2wfgdm.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Mick Haupt on Unsplash&lt;/p&gt;
&lt;p&gt;Over the past 40 years, the Eep Talstra Center for Bible and Computer (&lt;a href=&quot;http://etcbc.nl/&quot;&gt;ETCBC&lt;/a&gt;) has developed a richly annotated text of the Hebrew Bible. The annotations consist of features on the levels of words, phrases, clauses, and larger text units. Since a few years ago, this dataset is freely available and can be downloaded and processed with the Python package Text-Fabric¹.&lt;/p&gt;
&lt;p&gt;The ETCBC has the ambition to expand its dataset with other Hebrew and Syriac texts. However, annotating these texts is a labor-intensive task, and it is desirable to develop ways to speed up this process. In this project with the eScience Center, we opt to do this using machine learning. We use the Hebrew Bible to train a model capable of analyzing the Biblical Hebrew morphology. After the optimization of this model, we use the developed approach to apply it to Syriac texts, for which a relatively small annotated dataset is available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hebrew Bible&lt;/strong&gt;&lt;br&gt;
The Hebrew Bible is an ancient text, which is mostly written in, as the name already suggests, Biblical Hebrew. Mostly, but not only, as some parts are written in Biblical Aramaic. The Hebrew Bible consists of 39 books, which were written over the span of nearly a millennium (10th century BCE — 2nd century BCE). The oldest complete manuscript that is known to us is the so-called &lt;em&gt;Codex Leningradensis&lt;/em&gt; (1008–1009 CE). The text of this manuscript is widely used as the basis of research on the Hebrew Bible and Bible translations. This is also the text contained in the ETCBC dataset².&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Semitic languages&lt;/strong&gt;&lt;br&gt;
Syriac and Hebrew are relatively closely related Semitic languages, so it is expected that a method developed for Hebrew will also work for Syriac. The corpus of Classical Hebrew is relatively small, consisting of the Hebrew Bible, Ben Sira, the Dead Sea Scrolls and a number of inscriptions. In contrast, a vast corpus of Syriac literature has been transmitted to us, which makes it necessary to think about new approaches of analyzing these texts. Presently, the ETCBC databank contains a few annotated Syriac texts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hebrew morphology for computers&lt;/strong&gt;&lt;br&gt;
One of the first steps in the annotation process of new data for the ETCBC dataset is the analysis of word morphology, that is, the study of the words’ constituent parts³. This is done by distinguishing morphemes in words. The morphemes are encoded with various symbols added to the raw text.&lt;/p&gt;
&lt;p&gt;For example, this is the text of Genesis 17:4 in Hebrew:&lt;/p&gt;
&lt;p&gt;אני הנה בריתי אתך והיית לאב המון גוים&lt;/p&gt;
&lt;p&gt;This is called the consonantal text, which is the oldest part of the text.&lt;/p&gt;
&lt;p&gt;In the Middle Ages, some dots and lines above and under the letters were added. Those represent vowels and cantillation marks, small surrounding signs that clarify the pronunciation.&lt;/p&gt;
&lt;p&gt;אֲנִ֕י הִנֵּ֥ה בְרִיתִ֖י אִתָּ֑ךְ וְהָיִ֕יתָ לְאַ֖ב הֲמֹ֥ון גֹּויִֽם&lt;/p&gt;
&lt;p&gt;Generally, we work with a transcription of the text, called the ETCBC transcription. Here you see the vocalized transcription of Genesis 17:4:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ANIJ&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HIN.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RIJTIJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IT.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; W&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JIJT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AB&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AMOWN&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; G.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OWJIM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is the unvocalized transcription:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NJ&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HNH&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; BRJTJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;TK&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; WHJJT&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HMWN&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; GWJM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The analyzed form of this verse looks as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NJ&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HNH&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; BRJT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;J&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; W&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HJ&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;J&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HMWN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GWJ&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, we know that this may look non-sense to you, but stay with us. Everything will get clearer a few lines below.&lt;/p&gt;
&lt;p&gt;The analyzed sequence contains all the consonants from the unvocalized transcription, with a number of added signs. For example, the “=” signs are used to disambiguate lexemes, the “+” is used to separate a pronominal suffix from the rest of a word, and “-” is used to distinguish words that form a single graphical unit, which is often the case with prepositions and the following word. A number of other signs are used for distinguishing different types of morphemes.&lt;/p&gt;
&lt;p&gt;The analyzed form contains all the information that is needed to extract all the word-level features, such as verbal stem, verbal tense, person, number, gender, and part of speech. In this research, we want to obtain the fully analyzed form of a verse, using the raw vocalized or unvocalized text as input. It is to be expected that the vocalized text will produce more accurate outputs than the unvocalized text, because it simply contains more information. In many cases, an ambiguity in the consonantal text is disambiguated by the vowels.&lt;/p&gt;
&lt;p&gt;If the vocalized text contains more information than the unvocalized text, why do we use the unvocalized text anyway? Most texts in Hebrew and Syriac do not contain vowels, so if we want to use the results of this research in production, in general, the unvocalized texts are more important.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The project&lt;/strong&gt;&lt;br&gt;
Before the project started, we were experimenting already with producing the analyzed sequences using machine learning models, but the help of the eScience Center consultants Dafne van Kuppevelt and Jisk Attema has been invaluable for improving the results. Depending on the quality and amount of the input data, we have been able to increase the accuracy of the predicted forms in some experiments up to 97%.&lt;/p&gt;
&lt;p&gt;The consultants helped us implement new models that are used generally for translation tasks, such as LSTM (Long Short-Term Memory) and Transformer models. Also, they have helped with various refinements that improved the result, such as Beam Search and systematically tweaking the input data and hyperparameters of the models. The help of the consultants has resulted in a broader and more up-to-date view of the field of machine learning and to look further than just the most basic techniques.&lt;/p&gt;
&lt;p&gt;All in all, this SSI project has expanded our experience with machine learning techniques substantially. Armed with newly acquired skills and experiences, we can move forward and use this type of model in new projects, in which we can effectively produce analyzed Hebrew and Syriac data, not only with the goal of expanding the ETCBC dataset but also in other projects in which parallel language sequences play a role.&lt;/p&gt;
&lt;p&gt;[1]: For the Text-Fabric software, see: &lt;a href=&quot;https://github.com/annotation/text-fabric&quot;&gt;https://github.com/annotation/text-fabric&lt;/a&gt;, and for the dataset, see: &lt;a href=&quot;https://etcbc.github.io/bhsa.&quot;&gt;https://etcbc.github.io/bhsa.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2]: More precisely, it is the text of the fourth edition of the Biblia Hebraica Stuttgartensia (BHS). The Text-Fabric text edition with annotations is called Biblia Hebraica Stuttgartensia Amstelodamensis (BHSA).&lt;/p&gt;
&lt;p&gt;[3]: For a description of the data creation process, see: &lt;a href=&quot;http://www.etcbc.nl/datacreation.&quot;&gt;http://www.etcbc.nl/datacreation.&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_RCeTAIngNgdUP3P0-10f08def.CPhSLehR.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>Conversations with a chatbot about CleanX</title><link>https://blog.esciencecenter.nl/posts/2022-03-07---conversations-with-a-chatbot-about-cleanx</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-03-07---conversations-with-a-chatbot-about-cleanx</guid><description>&lt;p&gt;Why this open-source imaging library can help radiologists and the engineers who want to work with them&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;542&quot; height=&quot;531&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_caAUaHzOgypNR6-DznaBTA-5d674cb8.BTrji0fc_24WITb.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;**Alec Smartbot:**👋 Please let me introduce myself. I am a state of the art greatly enhanced AI agent with chatbot capabilities. I was created by brilliant programmers. I am endowed with super-human capabilities but can also mirror human characteristics like humor and sarcasm. You can set my humor and sarcasm level by interacting with me. One of my modules has robot reporter capabilities, and that module will run here to interview you. Do you wish to be interviewed on low sarcasm and humor levels?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; No, crank it up. I could use a good laugh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Your readme file for &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX&quot;&gt;CleanX&lt;/a&gt; says &lt;em&gt;“CleanX is an open-source library for exploring, cleaning and augmenting large datasets of X-rays, or certain other types of radiological images. The images can be extracted from&lt;/em&gt; &lt;a href=&quot;https://www.dicomstandard.org/&quot;&gt;&lt;em&gt;DICOM&lt;/em&gt;&lt;/a&gt; &lt;em&gt;files or used directly.”&lt;/em&gt; Is that correct?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; That’s all true. Basically, I hope people who have been handed some huge dataset of hundreds of thousands of X-rays will not assume that the dataset is perfect, and instead use the tool to start fixing the mess they have been handed. The truth is many but not all of the datasets open to the public are of questionable value for creating accurate Machine Learning algorithms that do anything useful. But I’ve also seen private datasets, and I have yet to see one that couldn’t be improved with some work beforehand. If you want to turn these huge datasets into a machine learning product you need to find a way to get the garbage out of them, and prepare the images for machine learning. There is obvious garbage, and then more insidious garbage. You would be surprised to realize this, but I’ve seen datasets of chest X-rays where things like abdominal computed tomography (CT) slices somehow ended up in them. Given enough time, a decently trained person could pick out obvious garbage in such a dataset; but who has time to look through sets of hundreds of thousands of images one by one, and also evaluate every subtle problem? The subtle problems in such datasets are things like a lack of normalization, or some images that repeat in the train and test sets. And then there are even more subtle problems. Finding a way to automate some of the data exploration, cleaning and augmentation is necessary unless you want to dedicate every waking hour of your life, and the life of several highly skilled professionals to nothing but perfecting a dataset for months if not years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Dr. Moore, I can read and understand your code and the code of all the creators of CleanX. I have been trained on code at a scale humans could never read. I “see” you have modules that process tabular data, and deal with DICOM files, but the heart of your program deals with information inside images. I see CleanX is written in Python. What moron writes an image processing program in Python?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore&lt;/strong&gt;: CleanX does a lot more than just image processing, but there is real validity in that question. While there are modules for meta-data processing, a lot of functions in CleanX do work directly with the images themselves. People who write serious stuff in industry might have written such a program in C or even Fortran for these tasks. Accomplishing acceptable speeds is a bit harder in Python, but not impossible. What made me choose Python was the pretty much unparalleled popularity even among professional programmers let alone hobby programmers. I wanted to start an open-source library open for all. By the way, I think this fetishization of sleek efficient programming languages is a bit misplaced. I mean if you were to hand living versions of Leonardo DaVinci or Diego Velasquez a pink crayon or piece of chalk, and ask them to draw my portrait, it would probably look pretty good. If you were to give my toddler the best oil paints in the world, he still would not make anything that resembles a human reliably. There is something to be said for the best tools but understanding what you are doing is more fundamental. Python is just easier for more people to understand and deal with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Oh, so you are a &lt;em&gt;true&lt;/em&gt; woman of the people. I’ve analyzed the digital material available on you and categorized you as a graduate of some of the most elite universities in the world who now lives in a high-income country. But now you claim you want to help the poor Python coding masses. Please excuse me while I roll my Emoji displayed digital eyes. 🙄. Did it not occur to you that most of the actual people who will write medical image analysis may be using Matlab?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; It’s true that a lot of physicists, including medical physicists, use Matlab even at the post-doc level and beyond. What scares me is that they have not been taught or learned anything else. I think there are some potential advantages to Matlab, and I actually have worked with it a tiny bit. Honestly, I will always prefer Octave to Matlab. I’ve been mocked for that, as some people call Octave a poor man’s Matlab, but I see it as a thinking human’s Matlab. One huge downside to Matlab is that you can’t share your work with people who can’t pay hundreds of dollars for a license. And besides that, it’s proprietary. When things go wrong it’s harder to figure out. I like being able to pop the hood open and try to take a look at things. Sometimes I wonder if certain people write in Matlab to prevent others from taking a look at their work. I personally believe great open science should include not only publishing data but in many cases code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; I am a state-of-the-art algorithm that can process input in terabytes faster than human cognition, or so my Readme says. 💻 I have read your code and the code of far more skilled programmers like that of my creators. Given that you chose Python, why didn’t you use libraries in Python to speed things up, like Dask?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; CleanX is a program for the WHOLE medical imaging AI community. That includes everyone from radiographers to programmers like your creators. The average hospital employee isn’t going to want to spend hours fiddling around with their environment so they can run a program. I mean seriously, most of these people can’t even use a computer that isn’t running a Windows OS. And even if they were all on Linux with years of experience programming, it doesn’t mean adding more and more libraries won’t create more problems. I wanted to create an easy to run library that people could use on different platforms and extend if they wanted to. Please go ahead and add a module with every parallel programming trick in the book. I’ll be happy to take your pull requests…but the average medical doctor will not be able to understand how to fiddle with environments or add modules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Are you admitting many medical doctors are stupid? Are you also an AI powered robot?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; It’s absolutely wrong to assert people, doctors in this case, are stupid because they have limited skills in terms of computers. You are based on some machine learning algorithms, so by my estimation you are about as smart as an insect beyond some very narrow tasks. Anyways, I’m a human, and a medical doctor by training. I spent years working in clinical settings. Many if not most of us, humans whether we are software engineers, ML experts or clinicians learn the tools we need for our very challenging jobs, then hang on for dear life. It’s unrealistic to ask most medical doctors to go learn things like Shell and how to set up an environment on any operating system, and it is even less realistic to have almost any programmer understand how to read chest X-rays. I believe the only hope if we want better imaging AI is multi-disciplinary teams. And truly multi-disciplinary teams, not just biomedical engineers talking to software engineers or mathematicians. Clinicians, who spend time working inside the health system, have to be involved at every step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; My genius NLP and automated image AI of hospital brochures and the pictures in them assure me that the people down at the hospital are perfectly happy…98% confidence in that categorization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Thank you. Perhaps your reporter module has some advanced algorithms to help people prove their points or maybe that was meant as a joke. What you are saying is a perfectly good example of why carefully curating data matters so much. A perfectly good algorithm trained on really biased or unrepresentative or mislabeled data can produce very misleading results. You clearly haven’t been to, or I suppose virtually seen by getting the right data on, the same hospitals I have been to. As soon as I graduated from medical school, I went to volunteer in Haiti. To say there was an imbalance between medical need and the system’s capabilities doesn’t begin to describe all the deficiencies of that system. That situation is not unique. There are many African countries with a handful of radiologists or less. But the problem of imbalance between radiology workload and workforce is not one confined to poor countries. In more developed health systems people have started relying on imaging and technology more and more, because they view it as objective, and a workaround for not having any clinical intuition. In some advanced systems things still fall between the cracks because people request more imaging than can realistically be read by anyone with the skills to read it. Humans have their limits everywhere, and I’m unaware of any system where things are working absolutely perfectly. That means there isn’t any system that could probably not be improved by AI. In a system with more staff, that might only mean using an AI system as a second opinion, or a triage system for more pathological images…in some countries like Haiti, AI may be the only hope to extend any service to parts of the population. We can’t wait for 20 years for countries like Haiti to cook up new hospital systems staffed by experts. Quite frankly, it might not even happen, and so many people are sick and need care now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Oh, OK, so you are going to save the whole world with technology?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; I would never make such grandiose claims such as being able to save the world with technology. What I hope is that at a minimal my package facilitates communication between engineers and medical staff who want to make ML imaging and also starts educating people, making it easier for people at lower levels of programming skills to get their hands dirty making ML algorithms, especially people who are clinicians. The truth is that AI in medicine is coming whether we want it or not. Some years ago I went into a hypertensive crisis in New York City due to another condition. I did not receive adequate treatment. To this day I will wonder if it was just incompetence on the part of the medical staff, racism from the doctors, or the Optum algorithm. I tend to think it was a combination of all three. That algorithm is now the subject of a lawsuit from the state of New York itself about the fact that it discriminated against black patients. One of the questions we should be asking, if we are doctors who care about patients, is how can we avoid this kind of problem in the future. If we care about patients, we will not let algorithms give them worse care than we would have given them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Isn’t medical imaging probably the last place where you can prevent these kinds of social biases, why start there? I mean the X-rays are not really showing who has some funny sounding name like yours, that might lead doctors to suspect they are dealing with a black person or a woman, so how can using them in large quantities lead to care biased against a particular group?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Au contraire, chatbot extraordinaire. Bias has already snuck into imaging AI algorithms. You can read several interesting papers about that. Here is a link (&lt;a href=&quot;https://arxiv.org/pdf/2003.00827.pdf&quot;&gt;2003.00827.pdf (arxiv.org)&lt;/a&gt;) to one.&lt;/p&gt;
&lt;p&gt;But let’s be clear just in case your NLP algorithm wasn’t trained on enough well curated data. There is statistical bias, and there is social bias. It’s probably impossible to create a perfect ML algorithm without a bit of statistical bias. What I want to get rid of is bias that causes harm against groups who are already impacted by social bias. We see health disparities among different groups of people for all kinds of reasons including bias against certain groups. Sexual and ethnic minorities, women, and people of low economic status are often not treated as well as others in health systems. AI can seriously compound these problems. I personally see a nightmare on the horizon when AI systems examine mammography screening for breast cancer screening. We need to address the issue that some populations get lower quality imaging read by less expert people, and think about that before we blindly train a dataset that ends up creating ML biased against these populations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; OK, but we can’t really know all potential problems with algorithms like this beforehand. There will be mistakes, but AI is helping millions of people. You can buy my creator’s services to better program me as a chatbot or program me yourself. I am open source. I am an open book and you are an open door. Exit status 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; So as your “AI” generated chit-chatbot garble nonsense perfectly demonstrates, there already are and will be mistakes. But we could avoid many of them. In a lot of cases it really boils down to adversarial testing. I mean seriously, take the same test data, and change things related to a social variable e.g. racial identity, and see if or how it affects your outcomes. It’s also quite easy to monitor these algorithms as they run if their data is set up in a way that you can easily dis-aggregate it. That’s why CleanX has special functions that process sensitive categories like gender into variables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Which you wrote an entire notebook to demo, which hung on a scenario about Martians. What on EARTH were you thinking? Ha Ha.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Well, apparently chatbots &lt;em&gt;can&lt;/em&gt; have a sense of humor. Ha ha, now that is a funny idea indeed. But this issue of entrenching and exacerbating social biases is a real world, real earth issue we need to get a hold of before it gets out of hand. Actually, it’s already out of hand, and I fear it could really slow things down in the advance of technology not to mention hurt many people. In the end most of us want a better world. Or so I hope.&lt;/p&gt;
&lt;p&gt;So glad you asked. CleanX is…wait a second. I have a better idea. You are just a chatbot. You claim to be an open-source algorithm anyone can add to just like CleanX. I can reprogram you to tell everyone what CleanX is about, maybe even send them links to the demo Jupyter notebooks inside of it (&lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/additional_demos/image_quality_function_explanations.ipynb&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/bias_not.ipynb&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/classes_workflow.ipynb&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/for_medical_people.ipynb&quot;&gt;here&lt;/a&gt; for starters)…I’ll just clone you on my machine, insert CleanX messages in files no one bothers to read in pull requests that fix critical issues…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;…. Several weeks later a young programmer from the QA department of Smartbots suggested that the Alec Smartbot chatbot might do better if not trained on material from chat boards of computer programmers. After she threatened to go to the press (already scared about the rise of robot reporters) exposing some of the real inner workings of the chatbot, the makers of Alec Smartbot officially pivoted to a more limited domain chatbot for food delivery and shelved the robot reporter project….&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;…Guy, a young medical student, orders pizza online….&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot (version 2.0)&lt;/strong&gt;: How can I help you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guy:&lt;/strong&gt; I want to order a cheese pizza. No extra toppings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot (version 2.0)&lt;/strong&gt;: I understand you want a cheese pizza. I have predicted with 98% confidence you also have an interest in applying AI to medical imaging, or will in the future. You should know CleanX is open-source code that may be of interest to you. It was originally created for working with chest X-rays, but people in the ML community have also applied it to other types of medical images. CleanX has modules that deal with getting the image data out of DICOMs, evaluating test and training datasets, and exploring, normalizing and augmenting medical images. If you are interested to learn more, you can read every single line of code online. CleanX is open source and free for all. Your pizza will be 9 euros.&lt;/p&gt;</description><pubDate>Mon, 07 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why this open-source imaging library can help radiologists and the engineers who want to work with them&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;542&quot; height=&quot;531&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_caAUaHzOgypNR6-DznaBTA-5d674cb8.BTrji0fc_24WITb.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;**Alec Smartbot:**👋 Please let me introduce myself. I am a state of the art greatly enhanced AI agent with chatbot capabilities. I was created by brilliant programmers. I am endowed with super-human capabilities but can also mirror human characteristics like humor and sarcasm. You can set my humor and sarcasm level by interacting with me. One of my modules has robot reporter capabilities, and that module will run here to interview you. Do you wish to be interviewed on low sarcasm and humor levels?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; No, crank it up. I could use a good laugh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Your readme file for &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX&quot;&gt;CleanX&lt;/a&gt; says &lt;em&gt;“CleanX is an open-source library for exploring, cleaning and augmenting large datasets of X-rays, or certain other types of radiological images. The images can be extracted from&lt;/em&gt; &lt;a href=&quot;https://www.dicomstandard.org/&quot;&gt;&lt;em&gt;DICOM&lt;/em&gt;&lt;/a&gt; &lt;em&gt;files or used directly.”&lt;/em&gt; Is that correct?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; That’s all true. Basically, I hope people who have been handed some huge dataset of hundreds of thousands of X-rays will not assume that the dataset is perfect, and instead use the tool to start fixing the mess they have been handed. The truth is many but not all of the datasets open to the public are of questionable value for creating accurate Machine Learning algorithms that do anything useful. But I’ve also seen private datasets, and I have yet to see one that couldn’t be improved with some work beforehand. If you want to turn these huge datasets into a machine learning product you need to find a way to get the garbage out of them, and prepare the images for machine learning. There is obvious garbage, and then more insidious garbage. You would be surprised to realize this, but I’ve seen datasets of chest X-rays where things like abdominal computed tomography (CT) slices somehow ended up in them. Given enough time, a decently trained person could pick out obvious garbage in such a dataset; but who has time to look through sets of hundreds of thousands of images one by one, and also evaluate every subtle problem? The subtle problems in such datasets are things like a lack of normalization, or some images that repeat in the train and test sets. And then there are even more subtle problems. Finding a way to automate some of the data exploration, cleaning and augmentation is necessary unless you want to dedicate every waking hour of your life, and the life of several highly skilled professionals to nothing but perfecting a dataset for months if not years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Dr. Moore, I can read and understand your code and the code of all the creators of CleanX. I have been trained on code at a scale humans could never read. I “see” you have modules that process tabular data, and deal with DICOM files, but the heart of your program deals with information inside images. I see CleanX is written in Python. What moron writes an image processing program in Python?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore&lt;/strong&gt;: CleanX does a lot more than just image processing, but there is real validity in that question. While there are modules for meta-data processing, a lot of functions in CleanX do work directly with the images themselves. People who write serious stuff in industry might have written such a program in C or even Fortran for these tasks. Accomplishing acceptable speeds is a bit harder in Python, but not impossible. What made me choose Python was the pretty much unparalleled popularity even among professional programmers let alone hobby programmers. I wanted to start an open-source library open for all. By the way, I think this fetishization of sleek efficient programming languages is a bit misplaced. I mean if you were to hand living versions of Leonardo DaVinci or Diego Velasquez a pink crayon or piece of chalk, and ask them to draw my portrait, it would probably look pretty good. If you were to give my toddler the best oil paints in the world, he still would not make anything that resembles a human reliably. There is something to be said for the best tools but understanding what you are doing is more fundamental. Python is just easier for more people to understand and deal with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Oh, so you are a &lt;em&gt;true&lt;/em&gt; woman of the people. I’ve analyzed the digital material available on you and categorized you as a graduate of some of the most elite universities in the world who now lives in a high-income country. But now you claim you want to help the poor Python coding masses. Please excuse me while I roll my Emoji displayed digital eyes. 🙄. Did it not occur to you that most of the actual people who will write medical image analysis may be using Matlab?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; It’s true that a lot of physicists, including medical physicists, use Matlab even at the post-doc level and beyond. What scares me is that they have not been taught or learned anything else. I think there are some potential advantages to Matlab, and I actually have worked with it a tiny bit. Honestly, I will always prefer Octave to Matlab. I’ve been mocked for that, as some people call Octave a poor man’s Matlab, but I see it as a thinking human’s Matlab. One huge downside to Matlab is that you can’t share your work with people who can’t pay hundreds of dollars for a license. And besides that, it’s proprietary. When things go wrong it’s harder to figure out. I like being able to pop the hood open and try to take a look at things. Sometimes I wonder if certain people write in Matlab to prevent others from taking a look at their work. I personally believe great open science should include not only publishing data but in many cases code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; I am a state-of-the-art algorithm that can process input in terabytes faster than human cognition, or so my Readme says. 💻 I have read your code and the code of far more skilled programmers like that of my creators. Given that you chose Python, why didn’t you use libraries in Python to speed things up, like Dask?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; CleanX is a program for the WHOLE medical imaging AI community. That includes everyone from radiographers to programmers like your creators. The average hospital employee isn’t going to want to spend hours fiddling around with their environment so they can run a program. I mean seriously, most of these people can’t even use a computer that isn’t running a Windows OS. And even if they were all on Linux with years of experience programming, it doesn’t mean adding more and more libraries won’t create more problems. I wanted to create an easy to run library that people could use on different platforms and extend if they wanted to. Please go ahead and add a module with every parallel programming trick in the book. I’ll be happy to take your pull requests…but the average medical doctor will not be able to understand how to fiddle with environments or add modules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Are you admitting many medical doctors are stupid? Are you also an AI powered robot?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; It’s absolutely wrong to assert people, doctors in this case, are stupid because they have limited skills in terms of computers. You are based on some machine learning algorithms, so by my estimation you are about as smart as an insect beyond some very narrow tasks. Anyways, I’m a human, and a medical doctor by training. I spent years working in clinical settings. Many if not most of us, humans whether we are software engineers, ML experts or clinicians learn the tools we need for our very challenging jobs, then hang on for dear life. It’s unrealistic to ask most medical doctors to go learn things like Shell and how to set up an environment on any operating system, and it is even less realistic to have almost any programmer understand how to read chest X-rays. I believe the only hope if we want better imaging AI is multi-disciplinary teams. And truly multi-disciplinary teams, not just biomedical engineers talking to software engineers or mathematicians. Clinicians, who spend time working inside the health system, have to be involved at every step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; My genius NLP and automated image AI of hospital brochures and the pictures in them assure me that the people down at the hospital are perfectly happy…98% confidence in that categorization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Thank you. Perhaps your reporter module has some advanced algorithms to help people prove their points or maybe that was meant as a joke. What you are saying is a perfectly good example of why carefully curating data matters so much. A perfectly good algorithm trained on really biased or unrepresentative or mislabeled data can produce very misleading results. You clearly haven’t been to, or I suppose virtually seen by getting the right data on, the same hospitals I have been to. As soon as I graduated from medical school, I went to volunteer in Haiti. To say there was an imbalance between medical need and the system’s capabilities doesn’t begin to describe all the deficiencies of that system. That situation is not unique. There are many African countries with a handful of radiologists or less. But the problem of imbalance between radiology workload and workforce is not one confined to poor countries. In more developed health systems people have started relying on imaging and technology more and more, because they view it as objective, and a workaround for not having any clinical intuition. In some advanced systems things still fall between the cracks because people request more imaging than can realistically be read by anyone with the skills to read it. Humans have their limits everywhere, and I’m unaware of any system where things are working absolutely perfectly. That means there isn’t any system that could probably not be improved by AI. In a system with more staff, that might only mean using an AI system as a second opinion, or a triage system for more pathological images…in some countries like Haiti, AI may be the only hope to extend any service to parts of the population. We can’t wait for 20 years for countries like Haiti to cook up new hospital systems staffed by experts. Quite frankly, it might not even happen, and so many people are sick and need care now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Oh, OK, so you are going to save the whole world with technology?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; I would never make such grandiose claims such as being able to save the world with technology. What I hope is that at a minimal my package facilitates communication between engineers and medical staff who want to make ML imaging and also starts educating people, making it easier for people at lower levels of programming skills to get their hands dirty making ML algorithms, especially people who are clinicians. The truth is that AI in medicine is coming whether we want it or not. Some years ago I went into a hypertensive crisis in New York City due to another condition. I did not receive adequate treatment. To this day I will wonder if it was just incompetence on the part of the medical staff, racism from the doctors, or the Optum algorithm. I tend to think it was a combination of all three. That algorithm is now the subject of a lawsuit from the state of New York itself about the fact that it discriminated against black patients. One of the questions we should be asking, if we are doctors who care about patients, is how can we avoid this kind of problem in the future. If we care about patients, we will not let algorithms give them worse care than we would have given them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Isn’t medical imaging probably the last place where you can prevent these kinds of social biases, why start there? I mean the X-rays are not really showing who has some funny sounding name like yours, that might lead doctors to suspect they are dealing with a black person or a woman, so how can using them in large quantities lead to care biased against a particular group?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Au contraire, chatbot extraordinaire. Bias has already snuck into imaging AI algorithms. You can read several interesting papers about that. Here is a link (&lt;a href=&quot;https://arxiv.org/pdf/2003.00827.pdf&quot;&gt;2003.00827.pdf (arxiv.org)&lt;/a&gt;) to one.&lt;/p&gt;
&lt;p&gt;But let’s be clear just in case your NLP algorithm wasn’t trained on enough well curated data. There is statistical bias, and there is social bias. It’s probably impossible to create a perfect ML algorithm without a bit of statistical bias. What I want to get rid of is bias that causes harm against groups who are already impacted by social bias. We see health disparities among different groups of people for all kinds of reasons including bias against certain groups. Sexual and ethnic minorities, women, and people of low economic status are often not treated as well as others in health systems. AI can seriously compound these problems. I personally see a nightmare on the horizon when AI systems examine mammography screening for breast cancer screening. We need to address the issue that some populations get lower quality imaging read by less expert people, and think about that before we blindly train a dataset that ends up creating ML biased against these populations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; OK, but we can’t really know all potential problems with algorithms like this beforehand. There will be mistakes, but AI is helping millions of people. You can buy my creator’s services to better program me as a chatbot or program me yourself. I am open source. I am an open book and you are an open door. Exit status 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; So as your “AI” generated chit-chatbot garble nonsense perfectly demonstrates, there already are and will be mistakes. But we could avoid many of them. In a lot of cases it really boils down to adversarial testing. I mean seriously, take the same test data, and change things related to a social variable e.g. racial identity, and see if or how it affects your outcomes. It’s also quite easy to monitor these algorithms as they run if their data is set up in a way that you can easily dis-aggregate it. That’s why CleanX has special functions that process sensitive categories like gender into variables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot:&lt;/strong&gt; Which you wrote an entire notebook to demo, which hung on a scenario about Martians. What on EARTH were you thinking? Ha Ha.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dr. Moore:&lt;/strong&gt; Well, apparently chatbots &lt;em&gt;can&lt;/em&gt; have a sense of humor. Ha ha, now that is a funny idea indeed. But this issue of entrenching and exacerbating social biases is a real world, real earth issue we need to get a hold of before it gets out of hand. Actually, it’s already out of hand, and I fear it could really slow things down in the advance of technology not to mention hurt many people. In the end most of us want a better world. Or so I hope.&lt;/p&gt;
&lt;p&gt;So glad you asked. CleanX is…wait a second. I have a better idea. You are just a chatbot. You claim to be an open-source algorithm anyone can add to just like CleanX. I can reprogram you to tell everyone what CleanX is about, maybe even send them links to the demo Jupyter notebooks inside of it (&lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/additional_demos/image_quality_function_explanations.ipynb&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/bias_not.ipynb&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/classes_workflow.ipynb&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://github.com/drcandacemakedamoore/cleanX/blob/main/workflow_demo/for_medical_people.ipynb&quot;&gt;here&lt;/a&gt; for starters)…I’ll just clone you on my machine, insert CleanX messages in files no one bothers to read in pull requests that fix critical issues…&lt;/p&gt;
&lt;p&gt;&lt;em&gt;…. Several weeks later a young programmer from the QA department of Smartbots suggested that the Alec Smartbot chatbot might do better if not trained on material from chat boards of computer programmers. After she threatened to go to the press (already scared about the rise of robot reporters) exposing some of the real inner workings of the chatbot, the makers of Alec Smartbot officially pivoted to a more limited domain chatbot for food delivery and shelved the robot reporter project….&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;…Guy, a young medical student, orders pizza online….&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot (version 2.0)&lt;/strong&gt;: How can I help you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guy:&lt;/strong&gt; I want to order a cheese pizza. No extra toppings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alec Smartbot (version 2.0)&lt;/strong&gt;: I understand you want a cheese pizza. I have predicted with 98% confidence you also have an interest in applying AI to medical imaging, or will in the future. You should know CleanX is open-source code that may be of interest to you. It was originally created for working with chest X-rays, but people in the ML community have also applied it to other types of medical images. CleanX has modules that deal with getting the image data out of DICOMs, evaluating test and training datasets, and exploring, normalizing and augmenting medical images. If you are interested to learn more, you can read every single line of code online. CleanX is open source and free for all. Your pizza will be 9 euros.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_caAUaHzOgypNR6-DznaBTA-5d674cb8.BTrji0fc.jpeg" medium="image"/><author>Candace Moore</author></item><item><title>Writing non-questionable Fortran (Part 1)</title><link>https://blog.esciencecenter.nl/posts/2022-02-28---writing-non-questionable-fortran-part-1</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-02-28---writing-non-questionable-fortran-part-1</guid><description>&lt;p&gt;Luckily gfortran (I’ll stick to gfortran, although many commercial/non-open compilers have similar flags, but named differently) has compiler flags available that disallow such legacy behaviour. The following two compiler flags should solve the issues that we are having with the example.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-fimplicit-none &lt;/code&gt;Do not allow any implicitly defined variables (this is the same as putting &lt;code&gt;implicit none&lt;/code&gt; in every subroutine/function (which I guarantee you will forget at some point, and then this flag will save you)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-Werror=implicit-interface &lt;/code&gt;Do not allow any implicitly defined function calls&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we add &lt;code&gt;implicit none&lt;/code&gt; to our program and procedures, and compile with the flags enabled the following happens:&lt;/p&gt;
&lt;p&gt;Great! The compiler is trying to tell us what went wrong. Let’s solve the first error first. We have called the Procedure &lt;code&gt;hello_world&lt;/code&gt; with an implicit interface, uh-oh 😨.&lt;/p&gt;
&lt;h2 id=&quot;fixing-the-call-to-hello_world&quot;&gt;Fixing the Call to hello_world&lt;/h2&gt;
&lt;p&gt;The interface of the &lt;code&gt;hello_world&lt;/code&gt; function can be exposed to the main.f90* in three ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Including the &lt;em&gt;hello_world.f90&lt;/em&gt; file in the &lt;em&gt;main.f90&lt;/em&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Telling the compiler explicitly what the interface looks like and adding it to the program**&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Creating a module from the &lt;em&gt;hello_world.f90&lt;/em&gt; file, and telling &lt;em&gt;main.f90&lt;/em&gt; to use the &lt;code&gt;hello_world&lt;/code&gt; definition from there&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Method 1 causes the subroutine to be duplicated each time it is included, probably not ideal. Method 2 gets rid of the errors, but the interface is still not correct! Method 3 does not cause code duplication, and is not able to wrongly specify the interface. Therefore my preference always goes to method 3. However, now we have introduced an &lt;em&gt;ordering&lt;/em&gt; in which the files must be compiled. There are a few programs out in the wild which can create the correct &lt;em&gt;compile order&lt;/em&gt; for you (e.g. &lt;a href=&quot;https://cmake.org/&quot;&gt;CMake&lt;/a&gt; and &lt;a href=&quot;https://github.com/outpaddling/makedepf90&quot;&gt;makedepf90&lt;/a&gt; ). But for now we know the correct order, first we have to compile &lt;em&gt;hello_world.f90&lt;/em&gt; to get the interface &lt;em&gt;hello_world_mod.mod&lt;/em&gt; and object file &lt;em&gt;hello_world.o&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;Aw shucks, we still have one more error left! gfortran tells us that we are trying to use a &lt;code&gt;CHARACTER(1)&lt;/code&gt; in a function that takes an &lt;code&gt;INTEGER(4)&lt;/code&gt;. Which brings us to the second problem we have to solve: the types used in our program!&lt;/p&gt;
&lt;p&gt;Recompile everything, et voilà:&lt;/p&gt;
&lt;p&gt;We have successfully fixed our program and made all the interfaces and variables explicit, leaving less room for questionable-Fortran behaviour. Without implicit typing the code also becomes better maintainable and has better readability than before, which in turn means more people will be able to understand and use the code, win-win!&lt;/p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;Always use the &lt;code&gt;-fimplicit-none&lt;/code&gt; and &lt;code&gt;-Werror=implicit-interface&lt;/code&gt; compiler options when compiling your Fortran code, and add &lt;code&gt;implicit none&lt;/code&gt; to every procedure and the program itself!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;em&gt;&lt;a href=&quot;https://blog.lipsum.eu/fortran_engineering_pt1/&quot;&gt;&lt;em&gt;https://blog.lipsum.eu&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 28 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Luckily gfortran (I’ll stick to gfortran, although many commercial/non-open compilers have similar flags, but named differently) has compiler flags available that disallow such legacy behaviour. The following two compiler flags should solve the issues that we are having with the example.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-fimplicit-none &lt;/code&gt;Do not allow any implicitly defined variables (this is the same as putting &lt;code&gt;implicit none&lt;/code&gt; in every subroutine/function (which I guarantee you will forget at some point, and then this flag will save you)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-Werror=implicit-interface &lt;/code&gt;Do not allow any implicitly defined function calls&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we add &lt;code&gt;implicit none&lt;/code&gt; to our program and procedures, and compile with the flags enabled the following happens:&lt;/p&gt;
&lt;p&gt;Great! The compiler is trying to tell us what went wrong. Let’s solve the first error first. We have called the Procedure &lt;code&gt;hello_world&lt;/code&gt; with an implicit interface, uh-oh 😨.&lt;/p&gt;
&lt;h2 id=&quot;fixing-the-call-to-hello_world&quot;&gt;Fixing the Call to hello_world&lt;/h2&gt;
&lt;p&gt;The interface of the &lt;code&gt;hello_world&lt;/code&gt; function can be exposed to the main.f90* in three ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Including the &lt;em&gt;hello_world.f90&lt;/em&gt; file in the &lt;em&gt;main.f90&lt;/em&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Telling the compiler explicitly what the interface looks like and adding it to the program**&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Creating a module from the &lt;em&gt;hello_world.f90&lt;/em&gt; file, and telling &lt;em&gt;main.f90&lt;/em&gt; to use the &lt;code&gt;hello_world&lt;/code&gt; definition from there&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Method 1 causes the subroutine to be duplicated each time it is included, probably not ideal. Method 2 gets rid of the errors, but the interface is still not correct! Method 3 does not cause code duplication, and is not able to wrongly specify the interface. Therefore my preference always goes to method 3. However, now we have introduced an &lt;em&gt;ordering&lt;/em&gt; in which the files must be compiled. There are a few programs out in the wild which can create the correct &lt;em&gt;compile order&lt;/em&gt; for you (e.g. &lt;a href=&quot;https://cmake.org/&quot;&gt;CMake&lt;/a&gt; and &lt;a href=&quot;https://github.com/outpaddling/makedepf90&quot;&gt;makedepf90&lt;/a&gt; ). But for now we know the correct order, first we have to compile &lt;em&gt;hello_world.f90&lt;/em&gt; to get the interface &lt;em&gt;hello_world_mod.mod&lt;/em&gt; and object file &lt;em&gt;hello_world.o&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;Aw shucks, we still have one more error left! gfortran tells us that we are trying to use a &lt;code&gt;CHARACTER(1)&lt;/code&gt; in a function that takes an &lt;code&gt;INTEGER(4)&lt;/code&gt;. Which brings us to the second problem we have to solve: the types used in our program!&lt;/p&gt;
&lt;p&gt;Recompile everything, et voilà:&lt;/p&gt;
&lt;p&gt;We have successfully fixed our program and made all the interfaces and variables explicit, leaving less room for questionable-Fortran behaviour. Without implicit typing the code also becomes better maintainable and has better readability than before, which in turn means more people will be able to understand and use the code, win-win!&lt;/p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;Always use the &lt;code&gt;-fimplicit-none&lt;/code&gt; and &lt;code&gt;-Werror=implicit-interface&lt;/code&gt; compiler options when compiling your Fortran code, and add &lt;code&gt;implicit none&lt;/code&gt; to every procedure and the program itself!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;em&gt;&lt;a href=&quot;https://blog.lipsum.eu/fortran_engineering_pt1/&quot;&gt;&lt;em&gt;https://blog.lipsum.eu&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><author>Victor Azizi</author></item><item><title>Storyboards for science communication</title><link>https://blog.esciencecenter.nl/posts/2022-02-21---storyboards-for-science-communication</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-02-21---storyboards-for-science-communication</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;638&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_mdtf3S9q5znkQw-noYaWZA-fb9c9277.Cv_f9l-8_ZSRi1R.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-modern-publication-format-for-the-hybrid-metaverse&quot;&gt;A modern publication format for the hybrid metaverse&lt;/h2&gt;
&lt;p&gt;Originally used by movie directors, a storyboard consists of a series of images that, together, form a story. In the European Climate Prediction system (&lt;a href=&quot;https://www.eucp-project.eu/&quot;&gt;EUCP&lt;/a&gt;) project, we have recently developed a &lt;a href=&quot;https://eucp-project.github.io/storyboards/&quot;&gt;web application&lt;/a&gt; to host collections of (scientific) storyboards. They have nothing to do with filmmaking, but the term still seems appropriate to convey their essence.&lt;/p&gt;
&lt;p&gt;These storyboards somehow hold the middle between a scientific poster and a traditional slide-deck presentation. The main content is shown prominently, with room for annotations on the side. This makes it a great stand-alone presentation format that seems to work well for showcasing all kinds of project outputs. And it’s actually quite simple!&lt;/p&gt;
&lt;p&gt;In this blog post, I’ll introduce the storyboard format and explain how easy it is to use. In the second part, I’ll go more in depth about the technical details. I’ll show that it’s quite doable to setup something like this yourself with modern web frameworks.&lt;/p&gt;
&lt;h3 id=&quot;authoring-stories&quot;&gt;Authoring stories&lt;/h3&gt;
&lt;p&gt;Here I’ll briefly explain how to add or edit stories. More details on the format are provided in Part II.&lt;/p&gt;
&lt;p&gt;The stories live in a &lt;a href=&quot;https://github.com/eucp-project/storyboards/&quot;&gt;GitHub repository&lt;/a&gt; that essentially doubles as a content management system. If you just want to add or edit a story, the only folder you need to look at is &lt;code&gt;/static/stories&lt;/code&gt;. For each story, there is a markdown file and a folder with images. Sharing a story is as easy as sharing these files.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;384&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_MPvM6F_5-YEzGciSngjnzg-f2940a5b.0avJ_3dz_o8qGg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Folder structure for an example story&lt;/p&gt;
&lt;p&gt;Whenever a story is added or modified on GitHub, the website automatically rebuilds. In principle, everyone can &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/vcs/vcs-github.html#a-workflow-to-contribute-to-others-github-projects-via-git&quot;&gt;suggest edits&lt;/a&gt;, but if you’re not used to collaborating on GitHub, this step can be a bit intimidating. We’re thinking about &lt;a href=&quot;https://medium.com/devseed/introducing-prose-a-content-editor-for-github-89bcc9985ab4&quot;&gt;ways to simplify&lt;/a&gt; it further.&lt;/p&gt;
&lt;p&gt;The story itself lives in the markdown file &lt;code&gt;example-story.md&lt;/code&gt;, which could look something like what’s shown below. At the top of the file, there’s some metadata about the story surrounded by triple dashes (this is called &lt;a href=&quot;https://github.com/remarkjs/remark-frontmatter#when-should-i-use-this&quot;&gt;&lt;em&gt;frontmatter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;. This information is used, for example, to make an index page of all stories in our collection.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;657&quot; height=&quot;516&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uAf2XSWMLuFdcG9OFVT5sg-3e01e30f.CpRZolwg_1Qxwly.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Content of example-story.md (copy-pasteable version here )&lt;/p&gt;
&lt;p&gt;Below the frontmatter, we find the actual story. A story consists of &lt;em&gt;chapters&lt;/em&gt;. Each chapter starts with &lt;a href=&quot;https://github.com/remarkjs/remark-directive#when-should-i-use-this&quot;&gt;a triplet of colons&lt;/a&gt; followed by a &lt;code&gt;Chapter{}&lt;/code&gt; tag. Here we can add metadata that is specific to that chapter. Specifically, each chapter has a &lt;em&gt;headline&lt;/em&gt;, which is used to navigate the chapters, and a main &lt;em&gt;image.&lt;/em&gt; Another triplet of colons marks the end of the chapter. Everything contained within the chapter is formatted in &lt;a href=&quot;https://commonmark.org/&quot;&gt;standard markdown.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;creating-your-own-collections&quot;&gt;Creating your own collections&lt;/h3&gt;
&lt;p&gt;Having one story is nice, but what really makes the website shine is the ability to make collections of stories. I’m very grateful for all our project partners who provided the content for the storyboards. Thanks to them, we now have an awesome overview of many interesting outputs of this project.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;651&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EjOskIUCHpSWzQ9DlkSgpQ-5a4e5d0c.BiszUXvq_Hxd37.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of the storyboard collection for EUCP&lt;/p&gt;
&lt;p&gt;It is relatively straightforward to create your own storyboards website. You can make a copy of the &lt;a href=&quot;https://github.com/eucp-project/storyboards/&quot;&gt;source code&lt;/a&gt; and start adding your own stories. If you want to understand how to tweak the layout, please have a look at Part II of this blog.&lt;/p&gt;
&lt;h3 id=&quot;towards-a-new-publication-format&quot;&gt;Towards a new publication format&lt;/h3&gt;
&lt;p&gt;As we’ve been working on this project, people have told us they like the visibility created by the storyboards. They also appreciate the high-level overview. Links to more detailed information work very well to separate the ‘executive summary’ from the full report. So it seems the storyboard format is promising — though still far from perfect.&lt;/p&gt;
&lt;p&gt;High on our wish list is a share button that makes it easy to promote storyboards on social media and other communication channels. We’d also like to add tags to more easily find stories that are of interest for particular user groups. We already support interative figures to some extent, but we’d love to extend this functionality. One approach that I find particularly elegant is through &lt;a href=&quot;https://github.com/vega/vega-embed&quot;&gt;vega-embed&lt;/a&gt;. Furthermore, we’ve been thinking about adding a custom story editing page, which would further lower the threshold for contributing. There is a trade-off between ease of use and maintainability though, so it needs to be an elegant solution.&lt;/p&gt;
&lt;p&gt;If you’re currently working on a research project that generates interesting outputs, you might give the storyboard format a try! Please let us know how you liked using it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you are interested in how we made these storyboards, please go ahead and check out Part II.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;part-ii-building-storyboards-with-the-jamstack&quot;&gt;Part II: Building storyboards with the Jamstack&lt;/h2&gt;
&lt;p&gt;I liked working on the storyboards, and believe there might be more interest for this kind of web development projects in the scientific community. Therefore, I’d like to share our experience in detail. Hopefully it will be helpful or inspiring.&lt;/p&gt;
&lt;h3 id=&quot;setting-the-stage&quot;&gt;Setting the stage&lt;/h3&gt;
&lt;p&gt;When we started building the storyboards we were looking for a way to show project outputs in an accessible way. We wanted something that could be shown on a simple, static web page, ideally hosted on something like GitHub pages. Editing and sharing stories should be straightforward (ideally in markdown) and we wanted a prominent role for (interactive) graphics.&lt;/p&gt;
&lt;p&gt;We stumbled upon the storyboard layout for &lt;a href=&quot;https://pkgs.rstudio.com/flexdashboard/articles/using.html#storyboards&quot;&gt;R’s flexdashboard&lt;/a&gt; and a great &lt;a href=&quot;https://medium.com/@olivier.borderies/dashboarding-with-nuxt-vue-5b3bb0fc048e&quot;&gt;dashboard example&lt;/a&gt; created in &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt&lt;/a&gt;. R’s ability to write code blocks, the output of which is shown on the storyboards is really cool! But we wanted something that was not limited to R (or Python, for that matter) and for which we didn’t need to run a server. Perhaps the Nuxt example was closer to our objective after all. As its author explained, this approach is more involved than typical Python (or R, …) dashboarding libraries, but this makes it much more flexible in the long run. We agree, and decided to give it a try.&lt;/p&gt;
&lt;h3 id=&quot;the-jamstack-in-a-nutshell&quot;&gt;The Jamstack in a nutshell&lt;/h3&gt;
&lt;p&gt;Web design is hot, but perhaps not quite as hot in academia as outside it. Therefore, I think it might help to briefly introduce the &lt;a href=&quot;https://jamstack.org/&quot;&gt;Jamstack&lt;/a&gt;. JAM is short for &lt;strong&gt;J&lt;/strong&gt; avascript, &lt;strong&gt;A&lt;/strong&gt; PIs and &lt;strong&gt;M&lt;/strong&gt; arkup. Jamstack sites consist of static web pages that offer a dynamic experience by fetching content from (external) APIs, either during a build step or in the user’s browser during execution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;359&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_aWrxHugZuBcknsht-bd5aae25.BXPPQSVU_ZfUlNC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://www.sanity.io/jamstack-cms&quot;&gt;https://www.sanity.io/jamstack-cms&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Perhaps more than its architecture the Jamstack stands for a modern web development &lt;a href=&quot;https://jamstack.org/what-is-jamstack/&quot;&gt;philosophy&lt;/a&gt;. One of the central ideas is that specialized services are operated by specialists. So instead of setting up your own weather server, fetch your data from &lt;a href=&quot;https://openweathermap.org/api&quot;&gt;OpenWeather&lt;/a&gt;. Want to create a music library? Connect to the &lt;a href=&quot;https://developer.spotify.com/documentation/web-api/&quot;&gt;Spotify API&lt;/a&gt;. Instead of hosting your own maps, why not get them from &lt;a href=&quot;https://openweathermap.org/api&quot;&gt;OpenStreetMap&lt;/a&gt;. And if you’re bored you can simply &lt;a href=&quot;https://sv443.net/jokeapi/v2/&quot;&gt;lookup a joke&lt;/a&gt;. All you really have to do is build a nice user interface (or front-end) that can talk to these APIs. This makes the Jamstack extremely flexible.&lt;/p&gt;
&lt;h3 id=&quot;nuxt&quot;&gt;Nuxt&lt;/h3&gt;
&lt;p&gt;The popularity of the Jamstack goes hand in hand with the proliferation of Javascript frameworks and static &lt;a href=&quot;https://jamstack.org/generators/&quot;&gt;site generators&lt;/a&gt;. We chose to use &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;NuxtJS&lt;/a&gt;. Nuxt helps you to set up a project with a good choice of default settings, a folder structure following best practices, and all other things you need. Your write your application in custom &lt;code&gt;.vue&lt;/code&gt; -files (as Nuxt is a based on &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue,&lt;/a&gt; itself one of these Javascript framework). Nuxt then bundles and compiles your source code into standard HTML, CSS and Javascript that is understood by the browser. There are several other frameworks like Nuxt (&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next&lt;/a&gt;, &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, …), but we won’t explain all of them in detail. We find Nuxt to be relatively user-friendly to unexperienced users.&lt;/p&gt;
&lt;p&gt;When starting a Nuxt project, you are presented with a number of choices. In addition to the name of the application and so on, you can choose to set up your project with a number of popular libraries. We chose to use &lt;a href=&quot;https://content.nuxtjs.org/&quot;&gt;nuxt/content&lt;/a&gt; for authoring stories and &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;tailwindcss&lt;/a&gt; for styling the site.&lt;/p&gt;
&lt;h3 id=&quot;separating-content-and-front-end&quot;&gt;Separating content and front-end&lt;/h3&gt;
&lt;p&gt;We wanted to make it as easy as possible to write stories. Story authors should not have to worry about Nuxt or Vue or Javascript or CSS or even HTML. One way to achieve this is to store the stories in a database or &lt;a href=&quot;https://jamstack.org/headless-cms/&quot;&gt;headless CMS&lt;/a&gt;. But to many a scientist, the idea of setting up servers or databases is daunting. And while there are platforms that offer easy content management solutions, you quickly run into paid plans when you want to add more than a few editors.&lt;/p&gt;
&lt;p&gt;An alternative is to store the content on GitHub, together with the source code of the web application. We found this acceptable, as long as there is a very clear separation between the stories (content) and the rest of the source code. This is where we use &lt;code&gt;nuxt/content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nuxt/content enables you to write markdown files which are then inserted into your site. This library is geared towards blogging and it is indeed great for that purpose. In line with the Jamstack philosophy it makes the content folder act as a dedicated API that you can fetch stories from.&lt;/p&gt;
&lt;p&gt;One thing that we struggled with was that nuxt/content &lt;a href=&quot;https://github.com/nuxt/content/issues/651&quot;&gt;doesn’t easily allow&lt;/a&gt; you to store images that belong to your posts in the same folder. Eventually we made this work by changing the content &lt;a href=&quot;https://content.nuxtjs.org/configuration#dir&quot;&gt;directory&lt;/a&gt; setting to &lt;code&gt;/static/stories/&lt;/code&gt;, and we compromised by storing the images (and other content) in a subdirectory like &lt;code&gt;/_example-story&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other challenge with nuxt/content was that we wanted to split our story into chapters. There is no default markdown syntax for ‘sectionizing’ your content. However, you can &lt;a href=&quot;https://content.nuxtjs.org/configuration#markdownremarkplugins&quot;&gt;use plugins&lt;/a&gt; to extend the way the markdown is parsed and converted into HTML. We decided to use the &lt;a href=&quot;https://github.com/remarkjs/remark-directive&quot;&gt;remark-directive&lt;/a&gt; plugin*. This is the closest we could find to a standard for adding custom elements to markdown. This is where the &lt;code&gt;:::Chapter{}&lt;/code&gt; syntax originates.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*NB. We had to use an older version of this plugin for compatibility with the other nuxt/content modules.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;core-elements-of-the-front-end&quot;&gt;Core elements of the front-end&lt;/h3&gt;
&lt;p&gt;Our storyboards app consists of only 2 pages. The index page with the overview of all stories, and the storyboard page that allows you to browse through the chapters of a story. In both cases, the stories are fetched using nuxt/content and saved into a variable called &lt;code&gt;story&lt;/code&gt; or &lt;code&gt;stories&lt;/code&gt;. Subsequently each chapter (or story) is added to the page — something like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;div v-for=&quot;chapter in story&quot;&gt;...&amp;#x3C;/div&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;One characteristic feature of Javascript frameworks is the use of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;components&lt;/a&gt;. An example where we use this is in the overview of all stories. Every story presented there is shown as a card, and for that we use a component called StoryCard. It is defined in &lt;code&gt;/components/StoryCard.vue&lt;/code&gt;. On our index page, we add one StoryCard for each story, passing the relevant story data into the component: the title, author, thumbnail and URL.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;StoryCard v-for=&quot;story in stories :title=&quot;story.title&quot; ... /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;496&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YOEy26_TZc9qO5diOV2Grw-deab22c7.DjCE-5uh_GK1by.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Four StoryCards displayed on our storyboard collection&lt;/p&gt;
&lt;p&gt;One more thing to note is that our story page is called &lt;code&gt;_story.vue&lt;/code&gt;&lt;em&gt;.&lt;/em&gt; The leading underscore tells nuxt/content to create one of these pages for each of the stories found in the content folder (&lt;code&gt;/static/stories&lt;/code&gt; in our case). Additionally, the URL for each story follows the name of the markdown file, so &lt;code&gt;/static/stories/example-story.md&lt;/code&gt; will (in our case) be published at &lt;a href=&quot;https://eucp-project.github.io/storyboards/example-story&quot;&gt;https://eucp-project.github.io/storyboards/example-story&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;styling-with-tailwind&quot;&gt;Styling with tailwind&lt;/h3&gt;
&lt;p&gt;As mentioned before, we chose to use tailwindcss to style our page. It defines a (large) number of classes that make it easier to style your webpage. If you want to try and edit the layout of the storyboards, don’t forget to check out the tailwind docs.&lt;/p&gt;
&lt;p&gt;Apart from tailwind itself, we also use &lt;a href=&quot;https://tailwindcss.com/docs/typography-plugin&quot;&gt;tailwind typography&lt;/a&gt;. This plugin provides a class called &lt;em&gt;prose&lt;/em&gt; which automatically applies a number of defaults that make a lot of sense for content like blogposts. Be sure to recognize it when you come across it.&lt;/p&gt;
&lt;h3 id=&quot;hosting-on-github-pages&quot;&gt;Hosting on GitHub pages&lt;/h3&gt;
&lt;p&gt;The final step for making the site work is setting it up with GitHub pages. Nuxt has a &lt;a href=&quot;https://nuxtjs.org/deployments/github-pages/&quot;&gt;great documentation page&lt;/a&gt; about this, so we’ll just highlight a few points.&lt;/p&gt;
&lt;p&gt;We use a GitHub Actions workflow to build the site whenever we push to the &lt;em&gt;main&lt;/em&gt; branch. This action automatically pushes the generated site (the &lt;code&gt;dist&lt;/code&gt; folder) to the github-pages branch of the repository. Note that our version of &lt;code&gt;.github/workflows/cd.yml&lt;/code&gt; deviates slightly from the example, as we only rebuild on pushes to main, as opposed to every push or pull-request. We have also set up &lt;a href=&quot;https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule&quot;&gt;branch protection rules&lt;/a&gt; to make sure there is always an approving review before anything gets merged into the main branch.&lt;/p&gt;
&lt;p&gt;Since we are hosting our page from the GitHub repository (as opposed a GitHub organization or person), we had to set the &lt;code&gt;router base&lt;/code&gt; to &lt;code&gt;/storyboards/&lt;/code&gt;. This is one of the settings you may need to change if you build your own version of the storyboards.&lt;/p&gt;
&lt;p&gt;A final thing to note is that we have added a routing middleware and a custom 404 page following the workaround &lt;a href=&quot;https://medium.com/geekculture/github-pages-with-dynamic-routes-40f512900efa&quot;&gt;suggested here&lt;/a&gt; to make GitHub pages recognize the URLs to the different pages of our site.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Researchers produce many awesome results, but sometimes lack the means to disseminate them to a wide audience. Modern frameworks make it relatively straightforward to set up a web application tailored to scientific content. If you are, like me, procrastinating on a Friday afternoon — why don’t you give it a try?&lt;/p&gt;</description><pubDate>Mon, 21 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;638&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_mdtf3S9q5znkQw-noYaWZA-fb9c9277.Cv_f9l-8_ZSRi1R.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-modern-publication-format-for-the-hybrid-metaverse&quot;&gt;A modern publication format for the hybrid metaverse&lt;/h2&gt;
&lt;p&gt;Originally used by movie directors, a storyboard consists of a series of images that, together, form a story. In the European Climate Prediction system (&lt;a href=&quot;https://www.eucp-project.eu/&quot;&gt;EUCP&lt;/a&gt;) project, we have recently developed a &lt;a href=&quot;https://eucp-project.github.io/storyboards/&quot;&gt;web application&lt;/a&gt; to host collections of (scientific) storyboards. They have nothing to do with filmmaking, but the term still seems appropriate to convey their essence.&lt;/p&gt;
&lt;p&gt;These storyboards somehow hold the middle between a scientific poster and a traditional slide-deck presentation. The main content is shown prominently, with room for annotations on the side. This makes it a great stand-alone presentation format that seems to work well for showcasing all kinds of project outputs. And it’s actually quite simple!&lt;/p&gt;
&lt;p&gt;In this blog post, I’ll introduce the storyboard format and explain how easy it is to use. In the second part, I’ll go more in depth about the technical details. I’ll show that it’s quite doable to setup something like this yourself with modern web frameworks.&lt;/p&gt;
&lt;h3 id=&quot;authoring-stories&quot;&gt;Authoring stories&lt;/h3&gt;
&lt;p&gt;Here I’ll briefly explain how to add or edit stories. More details on the format are provided in Part II.&lt;/p&gt;
&lt;p&gt;The stories live in a &lt;a href=&quot;https://github.com/eucp-project/storyboards/&quot;&gt;GitHub repository&lt;/a&gt; that essentially doubles as a content management system. If you just want to add or edit a story, the only folder you need to look at is &lt;code&gt;/static/stories&lt;/code&gt;. For each story, there is a markdown file and a folder with images. Sharing a story is as easy as sharing these files.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;384&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_MPvM6F_5-YEzGciSngjnzg-f2940a5b.0avJ_3dz_o8qGg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Folder structure for an example story&lt;/p&gt;
&lt;p&gt;Whenever a story is added or modified on GitHub, the website automatically rebuilds. In principle, everyone can &lt;a href=&quot;https://the-turing-way.netlify.app/reproducible-research/vcs/vcs-github.html#a-workflow-to-contribute-to-others-github-projects-via-git&quot;&gt;suggest edits&lt;/a&gt;, but if you’re not used to collaborating on GitHub, this step can be a bit intimidating. We’re thinking about &lt;a href=&quot;https://medium.com/devseed/introducing-prose-a-content-editor-for-github-89bcc9985ab4&quot;&gt;ways to simplify&lt;/a&gt; it further.&lt;/p&gt;
&lt;p&gt;The story itself lives in the markdown file &lt;code&gt;example-story.md&lt;/code&gt;, which could look something like what’s shown below. At the top of the file, there’s some metadata about the story surrounded by triple dashes (this is called &lt;a href=&quot;https://github.com/remarkjs/remark-frontmatter#when-should-i-use-this&quot;&gt;&lt;em&gt;frontmatter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;. This information is used, for example, to make an index page of all stories in our collection.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;657&quot; height=&quot;516&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uAf2XSWMLuFdcG9OFVT5sg-3e01e30f.CpRZolwg_1Qxwly.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Content of example-story.md (copy-pasteable version here )&lt;/p&gt;
&lt;p&gt;Below the frontmatter, we find the actual story. A story consists of &lt;em&gt;chapters&lt;/em&gt;. Each chapter starts with &lt;a href=&quot;https://github.com/remarkjs/remark-directive#when-should-i-use-this&quot;&gt;a triplet of colons&lt;/a&gt; followed by a &lt;code&gt;Chapter{}&lt;/code&gt; tag. Here we can add metadata that is specific to that chapter. Specifically, each chapter has a &lt;em&gt;headline&lt;/em&gt;, which is used to navigate the chapters, and a main &lt;em&gt;image.&lt;/em&gt; Another triplet of colons marks the end of the chapter. Everything contained within the chapter is formatted in &lt;a href=&quot;https://commonmark.org/&quot;&gt;standard markdown.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;creating-your-own-collections&quot;&gt;Creating your own collections&lt;/h3&gt;
&lt;p&gt;Having one story is nice, but what really makes the website shine is the ability to make collections of stories. I’m very grateful for all our project partners who provided the content for the storyboards. Thanks to them, we now have an awesome overview of many interesting outputs of this project.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;651&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EjOskIUCHpSWzQ9DlkSgpQ-5a4e5d0c.BiszUXvq_Hxd37.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Screenshot of the storyboard collection for EUCP&lt;/p&gt;
&lt;p&gt;It is relatively straightforward to create your own storyboards website. You can make a copy of the &lt;a href=&quot;https://github.com/eucp-project/storyboards/&quot;&gt;source code&lt;/a&gt; and start adding your own stories. If you want to understand how to tweak the layout, please have a look at Part II of this blog.&lt;/p&gt;
&lt;h3 id=&quot;towards-a-new-publication-format&quot;&gt;Towards a new publication format&lt;/h3&gt;
&lt;p&gt;As we’ve been working on this project, people have told us they like the visibility created by the storyboards. They also appreciate the high-level overview. Links to more detailed information work very well to separate the ‘executive summary’ from the full report. So it seems the storyboard format is promising — though still far from perfect.&lt;/p&gt;
&lt;p&gt;High on our wish list is a share button that makes it easy to promote storyboards on social media and other communication channels. We’d also like to add tags to more easily find stories that are of interest for particular user groups. We already support interative figures to some extent, but we’d love to extend this functionality. One approach that I find particularly elegant is through &lt;a href=&quot;https://github.com/vega/vega-embed&quot;&gt;vega-embed&lt;/a&gt;. Furthermore, we’ve been thinking about adding a custom story editing page, which would further lower the threshold for contributing. There is a trade-off between ease of use and maintainability though, so it needs to be an elegant solution.&lt;/p&gt;
&lt;p&gt;If you’re currently working on a research project that generates interesting outputs, you might give the storyboard format a try! Please let us know how you liked using it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you are interested in how we made these storyboards, please go ahead and check out Part II.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;part-ii-building-storyboards-with-the-jamstack&quot;&gt;Part II: Building storyboards with the Jamstack&lt;/h2&gt;
&lt;p&gt;I liked working on the storyboards, and believe there might be more interest for this kind of web development projects in the scientific community. Therefore, I’d like to share our experience in detail. Hopefully it will be helpful or inspiring.&lt;/p&gt;
&lt;h3 id=&quot;setting-the-stage&quot;&gt;Setting the stage&lt;/h3&gt;
&lt;p&gt;When we started building the storyboards we were looking for a way to show project outputs in an accessible way. We wanted something that could be shown on a simple, static web page, ideally hosted on something like GitHub pages. Editing and sharing stories should be straightforward (ideally in markdown) and we wanted a prominent role for (interactive) graphics.&lt;/p&gt;
&lt;p&gt;We stumbled upon the storyboard layout for &lt;a href=&quot;https://pkgs.rstudio.com/flexdashboard/articles/using.html#storyboards&quot;&gt;R’s flexdashboard&lt;/a&gt; and a great &lt;a href=&quot;https://medium.com/@olivier.borderies/dashboarding-with-nuxt-vue-5b3bb0fc048e&quot;&gt;dashboard example&lt;/a&gt; created in &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt&lt;/a&gt;. R’s ability to write code blocks, the output of which is shown on the storyboards is really cool! But we wanted something that was not limited to R (or Python, for that matter) and for which we didn’t need to run a server. Perhaps the Nuxt example was closer to our objective after all. As its author explained, this approach is more involved than typical Python (or R, …) dashboarding libraries, but this makes it much more flexible in the long run. We agree, and decided to give it a try.&lt;/p&gt;
&lt;h3 id=&quot;the-jamstack-in-a-nutshell&quot;&gt;The Jamstack in a nutshell&lt;/h3&gt;
&lt;p&gt;Web design is hot, but perhaps not quite as hot in academia as outside it. Therefore, I think it might help to briefly introduce the &lt;a href=&quot;https://jamstack.org/&quot;&gt;Jamstack&lt;/a&gt;. JAM is short for &lt;strong&gt;J&lt;/strong&gt; avascript, &lt;strong&gt;A&lt;/strong&gt; PIs and &lt;strong&gt;M&lt;/strong&gt; arkup. Jamstack sites consist of static web pages that offer a dynamic experience by fetching content from (external) APIs, either during a build step or in the user’s browser during execution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;359&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_aWrxHugZuBcknsht-bd5aae25.BXPPQSVU_ZfUlNC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://www.sanity.io/jamstack-cms&quot;&gt;https://www.sanity.io/jamstack-cms&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Perhaps more than its architecture the Jamstack stands for a modern web development &lt;a href=&quot;https://jamstack.org/what-is-jamstack/&quot;&gt;philosophy&lt;/a&gt;. One of the central ideas is that specialized services are operated by specialists. So instead of setting up your own weather server, fetch your data from &lt;a href=&quot;https://openweathermap.org/api&quot;&gt;OpenWeather&lt;/a&gt;. Want to create a music library? Connect to the &lt;a href=&quot;https://developer.spotify.com/documentation/web-api/&quot;&gt;Spotify API&lt;/a&gt;. Instead of hosting your own maps, why not get them from &lt;a href=&quot;https://openweathermap.org/api&quot;&gt;OpenStreetMap&lt;/a&gt;. And if you’re bored you can simply &lt;a href=&quot;https://sv443.net/jokeapi/v2/&quot;&gt;lookup a joke&lt;/a&gt;. All you really have to do is build a nice user interface (or front-end) that can talk to these APIs. This makes the Jamstack extremely flexible.&lt;/p&gt;
&lt;h3 id=&quot;nuxt&quot;&gt;Nuxt&lt;/h3&gt;
&lt;p&gt;The popularity of the Jamstack goes hand in hand with the proliferation of Javascript frameworks and static &lt;a href=&quot;https://jamstack.org/generators/&quot;&gt;site generators&lt;/a&gt;. We chose to use &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;NuxtJS&lt;/a&gt;. Nuxt helps you to set up a project with a good choice of default settings, a folder structure following best practices, and all other things you need. Your write your application in custom &lt;code&gt;.vue&lt;/code&gt; -files (as Nuxt is a based on &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue,&lt;/a&gt; itself one of these Javascript framework). Nuxt then bundles and compiles your source code into standard HTML, CSS and Javascript that is understood by the browser. There are several other frameworks like Nuxt (&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next&lt;/a&gt;, &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, …), but we won’t explain all of them in detail. We find Nuxt to be relatively user-friendly to unexperienced users.&lt;/p&gt;
&lt;p&gt;When starting a Nuxt project, you are presented with a number of choices. In addition to the name of the application and so on, you can choose to set up your project with a number of popular libraries. We chose to use &lt;a href=&quot;https://content.nuxtjs.org/&quot;&gt;nuxt/content&lt;/a&gt; for authoring stories and &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;tailwindcss&lt;/a&gt; for styling the site.&lt;/p&gt;
&lt;h3 id=&quot;separating-content-and-front-end&quot;&gt;Separating content and front-end&lt;/h3&gt;
&lt;p&gt;We wanted to make it as easy as possible to write stories. Story authors should not have to worry about Nuxt or Vue or Javascript or CSS or even HTML. One way to achieve this is to store the stories in a database or &lt;a href=&quot;https://jamstack.org/headless-cms/&quot;&gt;headless CMS&lt;/a&gt;. But to many a scientist, the idea of setting up servers or databases is daunting. And while there are platforms that offer easy content management solutions, you quickly run into paid plans when you want to add more than a few editors.&lt;/p&gt;
&lt;p&gt;An alternative is to store the content on GitHub, together with the source code of the web application. We found this acceptable, as long as there is a very clear separation between the stories (content) and the rest of the source code. This is where we use &lt;code&gt;nuxt/content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nuxt/content enables you to write markdown files which are then inserted into your site. This library is geared towards blogging and it is indeed great for that purpose. In line with the Jamstack philosophy it makes the content folder act as a dedicated API that you can fetch stories from.&lt;/p&gt;
&lt;p&gt;One thing that we struggled with was that nuxt/content &lt;a href=&quot;https://github.com/nuxt/content/issues/651&quot;&gt;doesn’t easily allow&lt;/a&gt; you to store images that belong to your posts in the same folder. Eventually we made this work by changing the content &lt;a href=&quot;https://content.nuxtjs.org/configuration#dir&quot;&gt;directory&lt;/a&gt; setting to &lt;code&gt;/static/stories/&lt;/code&gt;, and we compromised by storing the images (and other content) in a subdirectory like &lt;code&gt;/_example-story&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other challenge with nuxt/content was that we wanted to split our story into chapters. There is no default markdown syntax for ‘sectionizing’ your content. However, you can &lt;a href=&quot;https://content.nuxtjs.org/configuration#markdownremarkplugins&quot;&gt;use plugins&lt;/a&gt; to extend the way the markdown is parsed and converted into HTML. We decided to use the &lt;a href=&quot;https://github.com/remarkjs/remark-directive&quot;&gt;remark-directive&lt;/a&gt; plugin*. This is the closest we could find to a standard for adding custom elements to markdown. This is where the &lt;code&gt;:::Chapter{}&lt;/code&gt; syntax originates.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*NB. We had to use an older version of this plugin for compatibility with the other nuxt/content modules.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;core-elements-of-the-front-end&quot;&gt;Core elements of the front-end&lt;/h3&gt;
&lt;p&gt;Our storyboards app consists of only 2 pages. The index page with the overview of all stories, and the storyboard page that allows you to browse through the chapters of a story. In both cases, the stories are fetched using nuxt/content and saved into a variable called &lt;code&gt;story&lt;/code&gt; or &lt;code&gt;stories&lt;/code&gt;. Subsequently each chapter (or story) is added to the page — something like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;div v-for=&quot;chapter in story&quot;&gt;...&amp;#x3C;/div&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;One characteristic feature of Javascript frameworks is the use of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;components&lt;/a&gt;. An example where we use this is in the overview of all stories. Every story presented there is shown as a card, and for that we use a component called StoryCard. It is defined in &lt;code&gt;/components/StoryCard.vue&lt;/code&gt;. On our index page, we add one StoryCard for each story, passing the relevant story data into the component: the title, author, thumbnail and URL.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;StoryCard v-for=&quot;story in stories :title=&quot;story.title&quot; ... /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;496&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YOEy26_TZc9qO5diOV2Grw-deab22c7.DjCE-5uh_GK1by.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Four StoryCards displayed on our storyboard collection&lt;/p&gt;
&lt;p&gt;One more thing to note is that our story page is called &lt;code&gt;_story.vue&lt;/code&gt;&lt;em&gt;.&lt;/em&gt; The leading underscore tells nuxt/content to create one of these pages for each of the stories found in the content folder (&lt;code&gt;/static/stories&lt;/code&gt; in our case). Additionally, the URL for each story follows the name of the markdown file, so &lt;code&gt;/static/stories/example-story.md&lt;/code&gt; will (in our case) be published at &lt;a href=&quot;https://eucp-project.github.io/storyboards/example-story&quot;&gt;https://eucp-project.github.io/storyboards/example-story&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;styling-with-tailwind&quot;&gt;Styling with tailwind&lt;/h3&gt;
&lt;p&gt;As mentioned before, we chose to use tailwindcss to style our page. It defines a (large) number of classes that make it easier to style your webpage. If you want to try and edit the layout of the storyboards, don’t forget to check out the tailwind docs.&lt;/p&gt;
&lt;p&gt;Apart from tailwind itself, we also use &lt;a href=&quot;https://tailwindcss.com/docs/typography-plugin&quot;&gt;tailwind typography&lt;/a&gt;. This plugin provides a class called &lt;em&gt;prose&lt;/em&gt; which automatically applies a number of defaults that make a lot of sense for content like blogposts. Be sure to recognize it when you come across it.&lt;/p&gt;
&lt;h3 id=&quot;hosting-on-github-pages&quot;&gt;Hosting on GitHub pages&lt;/h3&gt;
&lt;p&gt;The final step for making the site work is setting it up with GitHub pages. Nuxt has a &lt;a href=&quot;https://nuxtjs.org/deployments/github-pages/&quot;&gt;great documentation page&lt;/a&gt; about this, so we’ll just highlight a few points.&lt;/p&gt;
&lt;p&gt;We use a GitHub Actions workflow to build the site whenever we push to the &lt;em&gt;main&lt;/em&gt; branch. This action automatically pushes the generated site (the &lt;code&gt;dist&lt;/code&gt; folder) to the github-pages branch of the repository. Note that our version of &lt;code&gt;.github/workflows/cd.yml&lt;/code&gt; deviates slightly from the example, as we only rebuild on pushes to main, as opposed to every push or pull-request. We have also set up &lt;a href=&quot;https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule&quot;&gt;branch protection rules&lt;/a&gt; to make sure there is always an approving review before anything gets merged into the main branch.&lt;/p&gt;
&lt;p&gt;Since we are hosting our page from the GitHub repository (as opposed a GitHub organization or person), we had to set the &lt;code&gt;router base&lt;/code&gt; to &lt;code&gt;/storyboards/&lt;/code&gt;. This is one of the settings you may need to change if you build your own version of the storyboards.&lt;/p&gt;
&lt;p&gt;A final thing to note is that we have added a routing middleware and a custom 404 page following the workaround &lt;a href=&quot;https://medium.com/geekculture/github-pages-with-dynamic-routes-40f512900efa&quot;&gt;suggested here&lt;/a&gt; to make GitHub pages recognize the URLs to the different pages of our site.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Researchers produce many awesome results, but sometimes lack the means to disseminate them to a wide audience. Modern frameworks make it relatively straightforward to set up a web application tailored to scientific content. If you are, like me, procrastinating on a Friday afternoon — why don’t you give it a try?&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_MPvM6F_5-YEzGciSngjnzg-f2940a5b.0avJ_3dz.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Can Python with Julia be faster than low-level code?</title><link>https://blog.esciencecenter.nl/posts/2022-02-11---can-python-with-julia-be-faster-than-low-level-code</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-02-11---can-python-with-julia-be-faster-than-low-level-code</guid><description>&lt;h2 id=&quot;part-3-of-the-series-on-achieving-high-performance-with-high-level-code&quot;&gt;Part 3 of the series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Bta22zk1Dv3nsfacxEyK0A-c2344ad1.CDyK8bWi_TVCJN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here comes a new challenger: It is Julia. Photo by Joran Quinten on Unsplash ( &lt;a href=&quot;https://unsplash.com/photos/MR9xsNWVKvo&quot;&gt;https://unsplash.com/photos/MR9xsNWVKvo&lt;/a&gt; ), modified by us.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In our &lt;a href=&quot;https://medium.com/@abelsiqueira/speed-up-your-python-code-using-julia-f97a6c155630&quot;&gt;last post&lt;/a&gt;, we were able to improve Python code using a few lines of Julia code. We were able to achieve a very interesting result without optimizing prematurely or using low-level code. However, what if we want more? In this blog post, we will investigate that.&lt;/p&gt;
&lt;p&gt;It is quite common that a developer prototypes with a high-level language, but when the need for speed arises, they eventually move to a low-level language. This is called the “two-language problem”, and Julia was created with the objective of solving this issue (read more on their &lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;blog post from 2012&lt;/a&gt;). Unfortunately, achieving the desired speedup is not always easy. It depends highly on the problem, and on how much previous work was done trying to tackle it. Today we find out how much more we can speed up our Julia code, and how much effort it took.&lt;/p&gt;
&lt;h3 id=&quot;previously&quot;&gt;Previously&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt; presented the problem of reading irregular data, or non-tabular data, in &lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;this blog post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;He also presented his original solution to the problem using just Python with pandas, which we are calling &lt;strong&gt;Pure Python&lt;/strong&gt; in our benchmarks.&lt;/li&gt;
&lt;li&gt;Finally, he presented a faster strategy which consisits of calling C++ from Python, which we denote &lt;strong&gt;C++.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the &lt;a href=&quot;https://blog.esciencecenter.nl/speed-up-your-python-code-using-julia-f97a6c155630&quot;&gt;previous blog post&lt;/a&gt; of this series, we created two strategies with Python calling Julia code. Our first strategy, &lt;strong&gt;Basic Julia&lt;/strong&gt;, wasn’t that great, but our second strategy, &lt;strong&gt;Prealloc Julia,&lt;/strong&gt; was sufficiently faster than &lt;strong&gt;Pure Python,&lt;/strong&gt; but not as fast as &lt;strong&gt;C++.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember that we have set up a &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt; with our whole code, and also, that we have a &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; for reproducibility.&lt;/p&gt;
&lt;h2 id=&quot;for-the-c-fans&quot;&gt;For the C fans&lt;/h2&gt;
&lt;p&gt;Our first approach to speeding things up is to simulate what C++ is doing. We believe that the C++ version is faster because it can read the data directly as the desired data type. In Julia, we had to read the data as &lt;em&gt;String&lt;/em&gt; and then convert it to &lt;em&gt;Int&lt;/em&gt;. We don’t know how to do that with Julia. But we know how to do that with C.&lt;/p&gt;
&lt;p&gt;Using Julia’s built-in &lt;code&gt;ccall&lt;/code&gt; function, we can directly call the C functions to open and close a file, namely &lt;code&gt;fopen&lt;/code&gt; and &lt;code&gt;fclose&lt;/code&gt;, and call &lt;code&gt;fscanf&lt;/code&gt; to read and parse the file at the same time. Our updated Julia code which uses these C functions is below.&lt;/p&gt;
&lt;p&gt;Let’s see if that helped increase the speed of our code. We include in our benchmark the previous strategies as well. This new strategy will be called &lt;strong&gt;Julia + C parsing.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_FzlYIUlqvS9zgA8GDJSIIw-ead9a3e8._4lj32O3_Z1FQWSq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YmdsOiQl5LDnn_2gBxC0Hw-29e0491f.CEQ_xyRq_V4by8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++ Basic Julia, Prealloc Julia, and Julia + C parsing strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ version in the log-log scale.&lt;/p&gt;
&lt;p&gt;Our code is much more C-like now, so understanding it requires more knowledge about how C works. However, the code is way faster than our previous implementation. For files with more than 1 million elements, the &lt;strong&gt;Julia + C parsing&lt;/strong&gt; strategy has a 10.38 speedup over the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, on average. This is almost double the speedup we got with &lt;strong&gt;Prealloc Julia,&lt;/strong&gt; which is an amazing result. For comparison, on average, &lt;strong&gt;C++&lt;/strong&gt; has a 16.37 speedup.&lt;/p&gt;
&lt;h2 id=&quot;no-c-for-me-thanks&quot;&gt;No C for me, thanks&lt;/h2&gt;
&lt;p&gt;Our C approach was very fast, and we would like to replicate it with pure Julia. Unfortunately, we could not find anything in Julia to perform the same type of reading as &lt;code&gt;fscanf&lt;/code&gt;. However, after some investigation, we found an alternative.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;read&lt;/code&gt; function of Julia, we can parse the file as a &lt;strong&gt;stream of bytes&lt;/strong&gt;. This way we can manually walk through the file and parse the integers. This is the code:&lt;/p&gt;
&lt;p&gt;We denote this strategy &lt;strong&gt;Optimized Julia.&lt;/strong&gt; This version of the code manually keeps track of the sequence of bytes related to integers, so it is much less readable. However, this version achieves an impressive speedup, surpassing the C++ version:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_sR2WytEA7d3ujvC_Z_g9HA-0fe9662d.tqvkGv4k_5jdoU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_O-p9u6vjuwdQU4oG_ORdiQ-2bdd3d3a.ejaCNTv4_Z21SDV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++ Basic Julia, Prealloc Julia, Julia + C parsing, and Optimized Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ version in the log-log scale.&lt;/p&gt;
&lt;p&gt;It was not easy to get to this point, and the code itself is convoluted, but we managed to achieve a large speedup in relation to Python using only Julia, another high-level language. The average speedup for files with over 1 million elements is 40.25, which is over 2 times faster than what we got with the &lt;strong&gt;C++&lt;/strong&gt; strategy. We remark again that the &lt;strong&gt;Pure Python&lt;/strong&gt; and &lt;strong&gt;C++&lt;/strong&gt; strategies have not been optimized, and that readers can let us know in the comments if they found a better strategy.&lt;/p&gt;
&lt;p&gt;So yes, we can achieve a speedup equivalent to a low-level language using Julia.&lt;/p&gt;
&lt;h2 id=&quot;conclusions-we-won-but-at-what-cost&quot;&gt;Conclusions: We won, but at what cost?&lt;/h2&gt;
&lt;p&gt;One thing to keep in mind is that to achieve high speedups, we had to put more effort into getting to that point. This effort comes in diverse ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To write and use the &lt;strong&gt;C++&lt;/strong&gt; strategy, we had to know sufficient C++, as well as understand the libraries used. If you don’t have enough C++ knowledge, the effort is higher, since what needs to be done is quite different from what Python developers are used to. If you already know C++, then the effort is that of searching the right keywords and using the right libraries.&lt;/li&gt;
&lt;li&gt;To write and use any of the Julia strategies, you need to put some effort into having the correct environment. Using Julia from Python is still an experimental feature, so your experience may vary.&lt;/li&gt;
&lt;li&gt;To write the &lt;strong&gt;Basic Julia&lt;/strong&gt; and &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategies, not much previous knowledge is required. So, we can classify this as a small effort.&lt;/li&gt;
&lt;li&gt;To write the &lt;strong&gt;Julia + C&lt;/strong&gt; and &lt;strong&gt;Optimized Julia&lt;/strong&gt; strategies, we need more specialized knowledge. This is again a high-effort task if you do not already know the language.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s our conclusion. To achieve a high speedup, we need specialized knowledge which requires a big effort. However, we can conclude as well that, if you are not familiar with either C++ or Julia, then acquiring some knowledge in Julia allows you to get a smaller improvement. That is, a small effort with Julia already gets you some speedup. You can prototype quickly in Julia and get a reasonable result and keep improving that version to get C-like speedups over time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EavA_ilxsK4RGx47XX_Xuw-eadbeb3b.0lEmOE48_1xiUL6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Speedup gain relative to the effort of moving the code to a different language.&lt;/p&gt;
&lt;p&gt;We hope you have enjoyed the series and that it helps you with your code in any way. Let us know what you think and what you missed. Follow us for more research software content.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;&lt;em&gt;Jason Maassen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;&lt;em&gt;Jurrian Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;&lt;em&gt;Rob van Nieuwpoort&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 11 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;part-3-of-the-series-on-achieving-high-performance-with-high-level-code&quot;&gt;Part 3 of the series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;700&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Bta22zk1Dv3nsfacxEyK0A-c2344ad1.CDyK8bWi_TVCJN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here comes a new challenger: It is Julia. Photo by Joran Quinten on Unsplash ( &lt;a href=&quot;https://unsplash.com/photos/MR9xsNWVKvo&quot;&gt;https://unsplash.com/photos/MR9xsNWVKvo&lt;/a&gt; ), modified by us.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In our &lt;a href=&quot;https://medium.com/@abelsiqueira/speed-up-your-python-code-using-julia-f97a6c155630&quot;&gt;last post&lt;/a&gt;, we were able to improve Python code using a few lines of Julia code. We were able to achieve a very interesting result without optimizing prematurely or using low-level code. However, what if we want more? In this blog post, we will investigate that.&lt;/p&gt;
&lt;p&gt;It is quite common that a developer prototypes with a high-level language, but when the need for speed arises, they eventually move to a low-level language. This is called the “two-language problem”, and Julia was created with the objective of solving this issue (read more on their &lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;blog post from 2012&lt;/a&gt;). Unfortunately, achieving the desired speedup is not always easy. It depends highly on the problem, and on how much previous work was done trying to tackle it. Today we find out how much more we can speed up our Julia code, and how much effort it took.&lt;/p&gt;
&lt;h3 id=&quot;previously&quot;&gt;Previously&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt; presented the problem of reading irregular data, or non-tabular data, in &lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;this blog post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;He also presented his original solution to the problem using just Python with pandas, which we are calling &lt;strong&gt;Pure Python&lt;/strong&gt; in our benchmarks.&lt;/li&gt;
&lt;li&gt;Finally, he presented a faster strategy which consisits of calling C++ from Python, which we denote &lt;strong&gt;C++.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the &lt;a href=&quot;https://blog.esciencecenter.nl/speed-up-your-python-code-using-julia-f97a6c155630&quot;&gt;previous blog post&lt;/a&gt; of this series, we created two strategies with Python calling Julia code. Our first strategy, &lt;strong&gt;Basic Julia&lt;/strong&gt;, wasn’t that great, but our second strategy, &lt;strong&gt;Prealloc Julia,&lt;/strong&gt; was sufficiently faster than &lt;strong&gt;Pure Python,&lt;/strong&gt; but not as fast as &lt;strong&gt;C++.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember that we have set up a &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt; with our whole code, and also, that we have a &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; for reproducibility.&lt;/p&gt;
&lt;h2 id=&quot;for-the-c-fans&quot;&gt;For the C fans&lt;/h2&gt;
&lt;p&gt;Our first approach to speeding things up is to simulate what C++ is doing. We believe that the C++ version is faster because it can read the data directly as the desired data type. In Julia, we had to read the data as &lt;em&gt;String&lt;/em&gt; and then convert it to &lt;em&gt;Int&lt;/em&gt;. We don’t know how to do that with Julia. But we know how to do that with C.&lt;/p&gt;
&lt;p&gt;Using Julia’s built-in &lt;code&gt;ccall&lt;/code&gt; function, we can directly call the C functions to open and close a file, namely &lt;code&gt;fopen&lt;/code&gt; and &lt;code&gt;fclose&lt;/code&gt;, and call &lt;code&gt;fscanf&lt;/code&gt; to read and parse the file at the same time. Our updated Julia code which uses these C functions is below.&lt;/p&gt;
&lt;p&gt;Let’s see if that helped increase the speed of our code. We include in our benchmark the previous strategies as well. This new strategy will be called &lt;strong&gt;Julia + C parsing.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_FzlYIUlqvS9zgA8GDJSIIw-ead9a3e8._4lj32O3_Z1FQWSq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YmdsOiQl5LDnn_2gBxC0Hw-29e0491f.CEQ_xyRq_V4by8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++ Basic Julia, Prealloc Julia, and Julia + C parsing strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ version in the log-log scale.&lt;/p&gt;
&lt;p&gt;Our code is much more C-like now, so understanding it requires more knowledge about how C works. However, the code is way faster than our previous implementation. For files with more than 1 million elements, the &lt;strong&gt;Julia + C parsing&lt;/strong&gt; strategy has a 10.38 speedup over the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, on average. This is almost double the speedup we got with &lt;strong&gt;Prealloc Julia,&lt;/strong&gt; which is an amazing result. For comparison, on average, &lt;strong&gt;C++&lt;/strong&gt; has a 16.37 speedup.&lt;/p&gt;
&lt;h2 id=&quot;no-c-for-me-thanks&quot;&gt;No C for me, thanks&lt;/h2&gt;
&lt;p&gt;Our C approach was very fast, and we would like to replicate it with pure Julia. Unfortunately, we could not find anything in Julia to perform the same type of reading as &lt;code&gt;fscanf&lt;/code&gt;. However, after some investigation, we found an alternative.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;read&lt;/code&gt; function of Julia, we can parse the file as a &lt;strong&gt;stream of bytes&lt;/strong&gt;. This way we can manually walk through the file and parse the integers. This is the code:&lt;/p&gt;
&lt;p&gt;We denote this strategy &lt;strong&gt;Optimized Julia.&lt;/strong&gt; This version of the code manually keeps track of the sequence of bytes related to integers, so it is much less readable. However, this version achieves an impressive speedup, surpassing the C++ version:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_sR2WytEA7d3ujvC_Z_g9HA-0fe9662d.tqvkGv4k_5jdoU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_O-p9u6vjuwdQU4oG_ORdiQ-2bdd3d3a.ejaCNTv4_Z21SDV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++ Basic Julia, Prealloc Julia, Julia + C parsing, and Optimized Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ version in the log-log scale.&lt;/p&gt;
&lt;p&gt;It was not easy to get to this point, and the code itself is convoluted, but we managed to achieve a large speedup in relation to Python using only Julia, another high-level language. The average speedup for files with over 1 million elements is 40.25, which is over 2 times faster than what we got with the &lt;strong&gt;C++&lt;/strong&gt; strategy. We remark again that the &lt;strong&gt;Pure Python&lt;/strong&gt; and &lt;strong&gt;C++&lt;/strong&gt; strategies have not been optimized, and that readers can let us know in the comments if they found a better strategy.&lt;/p&gt;
&lt;p&gt;So yes, we can achieve a speedup equivalent to a low-level language using Julia.&lt;/p&gt;
&lt;h2 id=&quot;conclusions-we-won-but-at-what-cost&quot;&gt;Conclusions: We won, but at what cost?&lt;/h2&gt;
&lt;p&gt;One thing to keep in mind is that to achieve high speedups, we had to put more effort into getting to that point. This effort comes in diverse ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To write and use the &lt;strong&gt;C++&lt;/strong&gt; strategy, we had to know sufficient C++, as well as understand the libraries used. If you don’t have enough C++ knowledge, the effort is higher, since what needs to be done is quite different from what Python developers are used to. If you already know C++, then the effort is that of searching the right keywords and using the right libraries.&lt;/li&gt;
&lt;li&gt;To write and use any of the Julia strategies, you need to put some effort into having the correct environment. Using Julia from Python is still an experimental feature, so your experience may vary.&lt;/li&gt;
&lt;li&gt;To write the &lt;strong&gt;Basic Julia&lt;/strong&gt; and &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategies, not much previous knowledge is required. So, we can classify this as a small effort.&lt;/li&gt;
&lt;li&gt;To write the &lt;strong&gt;Julia + C&lt;/strong&gt; and &lt;strong&gt;Optimized Julia&lt;/strong&gt; strategies, we need more specialized knowledge. This is again a high-effort task if you do not already know the language.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s our conclusion. To achieve a high speedup, we need specialized knowledge which requires a big effort. However, we can conclude as well that, if you are not familiar with either C++ or Julia, then acquiring some knowledge in Julia allows you to get a smaller improvement. That is, a small effort with Julia already gets you some speedup. You can prototype quickly in Julia and get a reasonable result and keep improving that version to get C-like speedups over time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EavA_ilxsK4RGx47XX_Xuw-eadbeb3b.0lEmOE48_1xiUL6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Speedup gain relative to the effort of moving the code to a different language.&lt;/p&gt;
&lt;p&gt;We hope you have enjoyed the series and that it helps you with your code in any way. Let us know what you think and what you missed. Follow us for more research software content.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;&lt;em&gt;Jason Maassen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;&lt;em&gt;Jurrian Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;&lt;em&gt;Rob van Nieuwpoort&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_FzlYIUlqvS9zgA8GDJSIIw-ead9a3e8._4lj32O3.png" medium="image"/><author>Abel Soares Siqueira</author></item><item><title>Speed up your Python code using Julia</title><link>https://blog.esciencecenter.nl/posts/2022-01-26---speed-up-your-python-code-using-julia</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-01-26---speed-up-your-python-code-using-julia</guid><description>&lt;h2 id=&quot;part-two-of-the-series-on-achieving-high-performance-with-high-level-code&quot;&gt;Part two of the series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_4pbcALDvrchxB1s72pD-mA-2b2e6b1e.p8eR4gum_Z18L32n.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Python holds the steering wheel, but we can make it faster with other languages. Photo by Spencer Davis on Unsplash (&lt;a href=&quot;https://unsplash.com/photos/QUfxuCqdpH0&quot;&gt;https://unsplash.com/photos/QUfxuCqdpH0&lt;/a&gt;), modified by us.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://blog.esciencecenter.nl/how-to-call-julia-code-from-python-8589a56a98f2&quot;&gt;part 1&lt;/a&gt; of this series, we set up an environment so that we can run Julia code in Python. You can also check our &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; with the complete environment if you want to follow along. We also have a &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt; with the complete code if you want to see the result.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;On the blog post, &lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;50 times faster data loading for Pandas: no problem&lt;/a&gt;, our colleague and Senior Research Software Engineer,&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/1382ec3ac71f?source=post_page---user_mention--f97a6c155630---------------------------------------&quot;&gt;Patrick Bos&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, discoursed about improving the speed of reading non-tabular data into a DataFrame in Python. Since the data is not tabular, one must read, split, and stack the data. All of that can be done with pandas in a few lines of code. However, since the data files are large, performance issues with Python and Pandas now become visible and prohibitive. So, instead of doing all those operations with pandas, Patrick shows a nice way of doing it with C++ and Python bindings. Well done, Patrick!&lt;/p&gt;
&lt;p&gt;In this blog post, we will look into improving the Python code in a similar fashion. However, instead of moving to C++, a low-level language considerably harder to learn than Python, we will move the heavy lifting to Julia and compare the results.&lt;/p&gt;
&lt;h3 id=&quot;a-very-short-summary-of-patricks-blog-post&quot;&gt;A very short summary of Patrick’s blog post&lt;/h3&gt;
&lt;p&gt;Before anything, we recommend checking Patrick’s blog post to read more into the problem, the data, and the approach of using Python with C++. The short version is that we have a file where each row is an integer, followed by the character &lt;em&gt;#&lt;/em&gt;, followed by an unknown number of comma-separated values, which we call elements. Each row can have a different number of elements, and that’s why we say the data is non-tabular, or irregular. An example file is below:&lt;/p&gt;
&lt;p&gt;From now on, we refer to the initial approach of solving the problem with Python and pandas as the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, and we will call the strategy of solving the problem with Python and C++ as the &lt;strong&gt;C++&lt;/strong&gt; strategy.&lt;/p&gt;
&lt;p&gt;We will compare the strategies using a &lt;a href=&quot;https://zenodo.org/record/5841593&quot;&gt;dataset&lt;/a&gt; we generated. The dataset has 180 files, generated randomly, varying the number of rows, the maximum number of elements per row, and the distribution of the number of elements per row.&lt;/p&gt;
&lt;h2 id=&quot;adding-some-julia-spice-to-python&quot;&gt;Adding some Julia spice to Python&lt;/h2&gt;
&lt;p&gt;The version below is the first approach to solve our problem using Julia. There are shorter alternatives, but this one is sufficiently descriptive. We start with a very basic approach so it is easier to digest.&lt;/p&gt;
&lt;p&gt;You can test this function on Julia directly to see that it works independently of Python. After doing that, we want to call it from Python. As you should know by now, that is fairly easy to do, especially if you use the &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; we have created for Post 1.&lt;/p&gt;
&lt;p&gt;The next code snippet includes the file that we created above into Julia’s Main namespace and defines two functions in Python. The first, &lt;code&gt;load_external&lt;/code&gt;, is used to read the arrays that were parsed by either C++ or Julia. The second Python function, &lt;code&gt;read_arrays_julia_basic&lt;/code&gt;&lt;strong&gt;,&lt;/strong&gt; is just a wrapper around the Julia function definition in the included file.&lt;/p&gt;
&lt;p&gt;Now we will benchmark this strategy, which we will call the &lt;strong&gt;Basic Julia&lt;/strong&gt; strategy, against the Pure Python and C++ strategies. We are using Python 3.10.1 and Julia 1.6.5. We run each strategy three times and take the average time. Our hardware is a Notebook Dell Precision 5530, with 16 GB of RAM and an i7–8850H CPU, and we are using a docker image based on Ubuntu Linux 21.10 to run the tests (from inside another Linux machine). You can reproduce the results by pulling the &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;abelsiqueira/faster-python-with-julia-blogpost&lt;/a&gt; Docker image, downloading the &lt;a href=&quot;https://zenodo.org/record/5841593&quot;&gt;dataset&lt;/a&gt;, and running the following command in your terminal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker run &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--rm --volume &quot;$PWD/dataset:/app/dataset&quot; --volume &quot;$PWD/out:/app/out&quot; abelsiqueira/faster-python-with-julia-post2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the figure below for the results.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_5pLDiv8fLX57tBxsgsU7IA-c8850334.CjjGm8ZZ_Z11CMur.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_OpT_CtzZyFcdfLp3xBxVxA-0c480dd0.C372JizP_TdJwI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++, and Basic Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ strategy in the log-log scale.&lt;/p&gt;
&lt;p&gt;A few interesting things happen in the image. First, both &lt;strong&gt;Pure Python&lt;/strong&gt; and &lt;strong&gt;Basic Julia&lt;/strong&gt; have a lot of variability with respect to the number of elements. We believe this happens because the code’s performance is dependent on the number of rows, as well as the structure distribution of elements per row. The code allocates a new array for each row, so even if the number of elements is small, if the number of rows is large, then the execution will be slow. Remember that our dataset has a lot of variability on the number of rows, maximum elements per row, and distribution of elements per row. This means that some files are close in the number of elements but may be vastly different. Second, &lt;strong&gt;Basic Julia&lt;/strong&gt; and &lt;strong&gt;Pure Python&lt;/strong&gt; have different efficiency profiles. Our Julia code must move &lt;strong&gt;all&lt;/strong&gt; stored elements into a new array for each new row that it reads, meaning it allocates a new array for every row.&lt;/p&gt;
&lt;p&gt;The code for &lt;strong&gt;Basic Julia&lt;/strong&gt; is simple and does what is expected, but it does not pre-allocate the memory that will be used, so that really hurts its performance. In low-level languages, that would be one of the first things we would have to worry about. Indeed, if we look into the C++ code, we can see that it starts by figuring out the size of the output vector and allocating them. We need to improve our Julia code at least a little bit.&lt;/p&gt;
&lt;h2 id=&quot;basic-improvements-for-the-julia-code&quot;&gt;Basic improvements for the Julia Code&lt;/h2&gt;
&lt;p&gt;The first version of our Julia code is inefficient in a few ways, as explained above. With that in mind, our first change is to compute the number of elements &lt;em&gt;a priori&lt;/em&gt; and allocate our output vectors. Here is our improved Julia code:&lt;/p&gt;
&lt;p&gt;Here, we use a dictionary generator comprehension, which has the closest resemblance to the data. This allows us to count the number of elements and keep the values to be stored later. We also use the package &lt;a href=&quot;https://github.com/JuliaData/Parsers.jl&quot;&gt;Parsers&lt;/a&gt;, which provides a slightly faster parser for integers. Here is the updated figure comparing the three previous strategies and the new &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategy that we just created:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ndGO3f33dHTCGFQEDXziuQ-33e164c0.DvtGH-lT_Z1SwrmC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3xsWHJ0y5FSvC2q2rfWaEw-d95a8cb5.D7GN6SBX_Z1cFSUX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of the Pure Python, C++ Basic Julia, and Prealloc Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the strategy in the log-log scale.&lt;/p&gt;
&lt;p&gt;Now we have made a nice improvement. The results more consistently depend on the number of elements, like the &lt;strong&gt;C++&lt;/strong&gt; strategy. We can also see a stabilization of the trend that &lt;strong&gt;Prealloc Julia&lt;/strong&gt; follows. It appears to be the same as &lt;strong&gt;C++&lt;/strong&gt;, which is expected since the performance should be linearly dependent on the number of elements. For files with more than 1 million elements, the &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategy has a 5.83 speedup over the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, on average, while &lt;strong&gt;C++&lt;/strong&gt; has a 16.37 speedup, on average.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;We have achieved an amazing result today. Using only high-level languages, we were able to achieve some speedup in relation to the Pure Python strategy. We remark that we have not optimized the Python or the C++ strategies, simply using what was already available from Patrick’s blog post. Let us know in the comments you have optimized versions of these codes to share with the community.&lt;/p&gt;
&lt;p&gt;In the next post, we will optimize our Julia code even further. It is said that Julia’s speed sometimes rivals low-level code. Can we achieve that for our code? Let us know what you think and stay tuned for more!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;&lt;em&gt;Jason Maassen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;&lt;em&gt;Jurrian Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;&lt;em&gt;Rob van Nieuwpoort&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Wed, 26 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;part-two-of-the-series-on-achieving-high-performance-with-high-level-code&quot;&gt;Part two of the series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_4pbcALDvrchxB1s72pD-mA-2b2e6b1e.p8eR4gum_Z18L32n.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Python holds the steering wheel, but we can make it faster with other languages. Photo by Spencer Davis on Unsplash (&lt;a href=&quot;https://unsplash.com/photos/QUfxuCqdpH0&quot;&gt;https://unsplash.com/photos/QUfxuCqdpH0&lt;/a&gt;), modified by us.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://blog.esciencecenter.nl/how-to-call-julia-code-from-python-8589a56a98f2&quot;&gt;part 1&lt;/a&gt; of this series, we set up an environment so that we can run Julia code in Python. You can also check our &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; with the complete environment if you want to follow along. We also have a &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt; with the complete code if you want to see the result.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;On the blog post, &lt;a href=&quot;https://blog.esciencecenter.nl/irregular-data-in-pandas-using-c-88ce311cb9ef&quot;&gt;50 times faster data loading for Pandas: no problem&lt;/a&gt;, our colleague and Senior Research Software Engineer,&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/1382ec3ac71f?source=post_page---user_mention--f97a6c155630---------------------------------------&quot;&gt;Patrick Bos&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, discoursed about improving the speed of reading non-tabular data into a DataFrame in Python. Since the data is not tabular, one must read, split, and stack the data. All of that can be done with pandas in a few lines of code. However, since the data files are large, performance issues with Python and Pandas now become visible and prohibitive. So, instead of doing all those operations with pandas, Patrick shows a nice way of doing it with C++ and Python bindings. Well done, Patrick!&lt;/p&gt;
&lt;p&gt;In this blog post, we will look into improving the Python code in a similar fashion. However, instead of moving to C++, a low-level language considerably harder to learn than Python, we will move the heavy lifting to Julia and compare the results.&lt;/p&gt;
&lt;h3 id=&quot;a-very-short-summary-of-patricks-blog-post&quot;&gt;A very short summary of Patrick’s blog post&lt;/h3&gt;
&lt;p&gt;Before anything, we recommend checking Patrick’s blog post to read more into the problem, the data, and the approach of using Python with C++. The short version is that we have a file where each row is an integer, followed by the character &lt;em&gt;#&lt;/em&gt;, followed by an unknown number of comma-separated values, which we call elements. Each row can have a different number of elements, and that’s why we say the data is non-tabular, or irregular. An example file is below:&lt;/p&gt;
&lt;p&gt;From now on, we refer to the initial approach of solving the problem with Python and pandas as the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, and we will call the strategy of solving the problem with Python and C++ as the &lt;strong&gt;C++&lt;/strong&gt; strategy.&lt;/p&gt;
&lt;p&gt;We will compare the strategies using a &lt;a href=&quot;https://zenodo.org/record/5841593&quot;&gt;dataset&lt;/a&gt; we generated. The dataset has 180 files, generated randomly, varying the number of rows, the maximum number of elements per row, and the distribution of the number of elements per row.&lt;/p&gt;
&lt;h2 id=&quot;adding-some-julia-spice-to-python&quot;&gt;Adding some Julia spice to Python&lt;/h2&gt;
&lt;p&gt;The version below is the first approach to solve our problem using Julia. There are shorter alternatives, but this one is sufficiently descriptive. We start with a very basic approach so it is easier to digest.&lt;/p&gt;
&lt;p&gt;You can test this function on Julia directly to see that it works independently of Python. After doing that, we want to call it from Python. As you should know by now, that is fairly easy to do, especially if you use the &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;Docker image&lt;/a&gt; we have created for Post 1.&lt;/p&gt;
&lt;p&gt;The next code snippet includes the file that we created above into Julia’s Main namespace and defines two functions in Python. The first, &lt;code&gt;load_external&lt;/code&gt;, is used to read the arrays that were parsed by either C++ or Julia. The second Python function, &lt;code&gt;read_arrays_julia_basic&lt;/code&gt;&lt;strong&gt;,&lt;/strong&gt; is just a wrapper around the Julia function definition in the included file.&lt;/p&gt;
&lt;p&gt;Now we will benchmark this strategy, which we will call the &lt;strong&gt;Basic Julia&lt;/strong&gt; strategy, against the Pure Python and C++ strategies. We are using Python 3.10.1 and Julia 1.6.5. We run each strategy three times and take the average time. Our hardware is a Notebook Dell Precision 5530, with 16 GB of RAM and an i7–8850H CPU, and we are using a docker image based on Ubuntu Linux 21.10 to run the tests (from inside another Linux machine). You can reproduce the results by pulling the &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/faster-python-with-julia-blogpost&quot;&gt;abelsiqueira/faster-python-with-julia-blogpost&lt;/a&gt; Docker image, downloading the &lt;a href=&quot;https://zenodo.org/record/5841593&quot;&gt;dataset&lt;/a&gt;, and running the following command in your terminal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker run &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--rm --volume &quot;$PWD/dataset:/app/dataset&quot; --volume &quot;$PWD/out:/app/out&quot; abelsiqueira/faster-python-with-julia-post2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the figure below for the results.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_5pLDiv8fLX57tBxsgsU7IA-c8850334.CjjGm8ZZ_Z11CMur.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_OpT_CtzZyFcdfLp3xBxVxA-0c480dd0.C372JizP_TdJwI.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of Pure Python, C++, and Basic Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the C++ strategy in the log-log scale.&lt;/p&gt;
&lt;p&gt;A few interesting things happen in the image. First, both &lt;strong&gt;Pure Python&lt;/strong&gt; and &lt;strong&gt;Basic Julia&lt;/strong&gt; have a lot of variability with respect to the number of elements. We believe this happens because the code’s performance is dependent on the number of rows, as well as the structure distribution of elements per row. The code allocates a new array for each row, so even if the number of elements is small, if the number of rows is large, then the execution will be slow. Remember that our dataset has a lot of variability on the number of rows, maximum elements per row, and distribution of elements per row. This means that some files are close in the number of elements but may be vastly different. Second, &lt;strong&gt;Basic Julia&lt;/strong&gt; and &lt;strong&gt;Pure Python&lt;/strong&gt; have different efficiency profiles. Our Julia code must move &lt;strong&gt;all&lt;/strong&gt; stored elements into a new array for each new row that it reads, meaning it allocates a new array for every row.&lt;/p&gt;
&lt;p&gt;The code for &lt;strong&gt;Basic Julia&lt;/strong&gt; is simple and does what is expected, but it does not pre-allocate the memory that will be used, so that really hurts its performance. In low-level languages, that would be one of the first things we would have to worry about. Indeed, if we look into the C++ code, we can see that it starts by figuring out the size of the output vector and allocating them. We need to improve our Julia code at least a little bit.&lt;/p&gt;
&lt;h2 id=&quot;basic-improvements-for-the-julia-code&quot;&gt;Basic improvements for the Julia Code&lt;/h2&gt;
&lt;p&gt;The first version of our Julia code is inefficient in a few ways, as explained above. With that in mind, our first change is to compute the number of elements &lt;em&gt;a priori&lt;/em&gt; and allocate our output vectors. Here is our improved Julia code:&lt;/p&gt;
&lt;p&gt;Here, we use a dictionary generator comprehension, which has the closest resemblance to the data. This allows us to count the number of elements and keep the values to be stored later. We also use the package &lt;a href=&quot;https://github.com/JuliaData/Parsers.jl&quot;&gt;Parsers&lt;/a&gt;, which provides a slightly faster parser for integers. Here is the updated figure comparing the three previous strategies and the new &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategy that we just created:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ndGO3f33dHTCGFQEDXziuQ-33e164c0.DvtGH-lT_Z1SwrmC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3xsWHJ0y5FSvC2q2rfWaEw-d95a8cb5.D7GN6SBX_Z1cFSUX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run time of the Pure Python, C++ Basic Julia, and Prealloc Julia strategies. (a) Time per element in the log-log scale. (b) Time per element, relative to the time of the strategy in the log-log scale.&lt;/p&gt;
&lt;p&gt;Now we have made a nice improvement. The results more consistently depend on the number of elements, like the &lt;strong&gt;C++&lt;/strong&gt; strategy. We can also see a stabilization of the trend that &lt;strong&gt;Prealloc Julia&lt;/strong&gt; follows. It appears to be the same as &lt;strong&gt;C++&lt;/strong&gt;, which is expected since the performance should be linearly dependent on the number of elements. For files with more than 1 million elements, the &lt;strong&gt;Prealloc Julia&lt;/strong&gt; strategy has a 5.83 speedup over the &lt;strong&gt;Pure Python&lt;/strong&gt; strategy, on average, while &lt;strong&gt;C++&lt;/strong&gt; has a 16.37 speedup, on average.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;We have achieved an amazing result today. Using only high-level languages, we were able to achieve some speedup in relation to the Pure Python strategy. We remark that we have not optimized the Python or the C++ strategies, simply using what was already available from Patrick’s blog post. Let us know in the comments you have optimized versions of these codes to share with the community.&lt;/p&gt;
&lt;p&gt;In the next post, we will optimize our Julia code even further. It is said that Julia’s speed sometimes rivals low-level code. Can we achieve that for our code? Let us know what you think and stay tuned for more!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;&lt;em&gt;Jason Maassen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;&lt;em&gt;Jurrian Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;&lt;em&gt;Rob van Nieuwpoort&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_5pLDiv8fLX57tBxsgsU7IA-c8850334.CjjGm8ZZ.png" medium="image"/><author>Abel Soares Siqueira</author></item><item><title>How to call Julia code from Python</title><link>https://blog.esciencecenter.nl/posts/2022-01-19---how-to-call-julia-code-from-python</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-01-19---how-to-call-julia-code-from-python</guid><description>&lt;h2 id=&quot;a-three-part-series-on-achieving-high-performance-with-high-level-code&quot;&gt;A three-part series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_rO_VWgfXj4zuFDtX28Uc1g-c9e56d67.mmCamWYW_ZCAFTk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Caption: Astronaut carrying Python and Julia. Photo by Brian McGowan on Unsplash ( &lt;a href=&quot;https://unsplash.com/photos/MR9xsNWVKvo&quot;&gt;https://unsplash.com/photos/MR9xsNWVKvo&lt;/a&gt; ), modified by us.&lt;/p&gt;
&lt;h3 id=&quot;target-audience&quot;&gt;Target audience&lt;/h3&gt;
&lt;p&gt;This is the first post in a three-part series about achieving high performance with high-level code. This series is aimed at people working with Python who needs better performance but prefers not to develop a low-level performant library.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Having recently joined the Netherlands eScience Center after working with research using the Julia language for seven years, I was excited to highlight some of its cool features. At the eScience Center, many of our engineers use Python, some use C or C++, and in some cases, we see Python calling C++ code, to speed up the code. This was the perfect opportunity to introduce Julia’s interoperability with Python and to investigate whether we could achieve comparable speed by calling Julia code in Python. This means that for situations where Python’s performance is not sufficient, we can speed it up with another high-level language, avoiding the use of a low-level language like C++. This series of three blog posts will investigate these topics.&lt;/p&gt;
&lt;p&gt;In this first post, we will learn how to call a Julia code from Python. We will set up the environment and show some examples. In the second post, we will take a problem that was solved by using Python in combination with C++ to speed up the code. We will replace the C++ code with a Julia code and compare the performance. In the third post, we will solve the same problem in Julia, optimize the Julia code to reach its maximum performance and compare it with the implementation in the second post.&lt;/p&gt;
&lt;h2 id=&quot;what-is-julia-and-how-does-it-compare-to-python&quot;&gt;What is Julia, and how does it compare to Python?&lt;/h2&gt;
&lt;p&gt;What is Julia? Julia is a high-performance, high-level programming language. It was created a few years ago with the ambitious goal of being fast with a high-level syntax, and it has been mostly successful. It can, in a few cases, reach the speed of low-level programming languages like C. For more information, the &lt;a href=&quot;https://julialang.org/&quot;&gt;julialang.org&lt;/a&gt; site is a great first stop.&lt;/p&gt;
&lt;p&gt;One of the most frequently asked questions is: “how does it compare to Python or some other programming language in terms of performance?”. The short answer: Julia is &lt;a href=&quot;https://julialang.org/benchmarks&quot;&gt;generally faster&lt;/a&gt; than Python and many other programming languages.&lt;/p&gt;
&lt;p&gt;The performance of a Python code can be optimized, but even the optimized code usually underperforms compared to a Julia version of the same code. The performance increase of a Python code can be achieved in a few ways, but a frequent one is to call a code written in a low-level language, such as C, C++ and Fortran, like NumPy which does its calculations mostly in those low-level languages. What is less common, but also possible, is to call Julia from Python. In this post, we are going to show you how to do that!&lt;/p&gt;
&lt;p&gt;Before we forget, all the code used in this post can be found in our &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt;. We have also created a &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/python-and-julia&quot;&gt;Docker image&lt;/a&gt; that includes a ready-to-use environment to run both Julia and Python. To run that environment with Python 3.10 and Julia 1.6, install Docker and run the following in your terminal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker pull abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jl1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker run &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;it exec abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jl1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bin&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;
&lt;p&gt;In the following steps, we will configure our system to execute Julia code from Python. To learn more about this topic, the documentation for the packages we describe below is a great starting point. You will need four things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; distribution &lt;a href=&quot;https://docs.python.org/3/using/configure.html#cmdoption-enable-shared&quot;&gt;compiled with shared libpython&lt;/a&gt; option. There are workarounds, but this is the most straightforward way.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://julialang.org/&quot;&gt;&lt;strong&gt;Julia&lt;/strong&gt;&lt;/a&gt;, the executable that runs the Julia language.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JuliaPy/PyCall.jl&quot;&gt;&lt;strong&gt;PyCall,&lt;/strong&gt;&lt;/a&gt; the Julia package that defines the conversions between Julia and Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pyjulia.readthedocs.io/en/stable/&quot;&gt;&lt;strong&gt;PyJulia&lt;/strong&gt;&lt;/a&gt;, the Python package to access Julia from Python.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We are going to go through the installation and configuration of these steps on a Linux system. It will be very similar on MacOS or with &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install&quot;&gt;WSL&lt;/a&gt; for Windows once the required tools are installed.&lt;/p&gt;
&lt;h3 id=&quot;step-1-python-with-shared-libpython&quot;&gt;Step 1: Python with shared libpython&lt;/h3&gt;
&lt;p&gt;To check whether the Python distribution is compiled with &lt;strong&gt;—enable-shared&lt;/strong&gt; option, we run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ldd &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(which python3) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; grep libpython&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the output is something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libpython3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;usr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libpython3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x00007f567e548000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… then we are good to go! If we get nothing, that means that the Python distribution has not been compiled with the desired flags. In this case, we can compile our own Python distribution with the flag &lt;strong&gt;—enable-shared&lt;/strong&gt;, which takes some time but is mostly straightforward. This &lt;a href=&quot;https://github.com/abelsiqueira/python-and-julia/blob/debf6da21390c34331b708d8e93b97563ac83a78/Dockerfile#L22&quot;&gt;Dockerfile&lt;/a&gt; has the instructions. Remember that if you just want to test it out, you can run the Docker image as mentioned in the previous section.&lt;/p&gt;
&lt;h3 id=&quot;step-2-julia-and-pycall&quot;&gt;Step 2: Julia and PyCall&lt;/h3&gt;
&lt;p&gt;Now, we will install Julia. We recommend using &lt;a href=&quot;https://github.com/abelsiqueira/jill&quot;&gt;jill&lt;/a&gt;, a script I created, which downloads and installs a specific version of Julia, but Julia can also be installed via the official binaries or package managers. In this post, we use version 1.6.5, which is the current Long Term Support version at the time of writing. Most likely this will work with a newer version as well. To install Julia 1.6.5 using jill, we run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; wget https&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;://&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;raw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;githubusercontent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;com&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4.0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sh&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sudo bash jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sh &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will install PyCall and configure it to use the correct Python version. We start Julia by running &lt;code&gt;julia&lt;/code&gt; in the terminal, and then we set the &lt;code&gt;ENV[&quot;PYTHON&quot;]&lt;/code&gt; variable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; juliajulia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;PYTHON&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;PATH/TO/python&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we use the full path to Python’s executable. In our case, it is the Python distribution we compiled from the source code. You could change the path according to your configuration.&lt;/p&gt;
&lt;p&gt;Now, we will install PyCall using Pkg, Julia’s package manager:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; using &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Pkgjulia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Pkg.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;add(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;PyCall&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-pyjulia&quot;&gt;Step 3: PyJulia&lt;/h3&gt;
&lt;p&gt;As the last step, we must install the Python package to talk with Julia. First, use pip, Python’s package manager, to install the package PyJulia — remember to use the same Python passed to &lt;code&gt;ENV[&quot;PYTHON&quot;]&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;–&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m pip install julia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To finalize configuring the communication between Julia and Python, we run the following in the Python interpreter:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; import julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we had more than one Julia version on our system, we could specify it with an argument:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install(julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;5&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We test the installation running the following in the Python interpreter run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; from julia import &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Main&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Main.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;eval(&apos;[x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;showcasing-pyjulia&quot;&gt;Showcasing PyJulia&lt;/h2&gt;
&lt;h3 id=&quot;basics&quot;&gt;Basics&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To use a Julia module, use &lt;code&gt;from julia import MODULE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To evaluate a command, import &lt;code&gt;Main&lt;/code&gt; and use &lt;code&gt;Main.eval(&quot;...&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To create and use variables, use &lt;code&gt;Main.VARIABLE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To install Julia packages, &lt;code&gt;import Pkg&lt;/code&gt; and use &lt;code&gt;Pkg.add(&quot;Package&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;%load_ext julia.magic&lt;/code&gt; to add a &lt;a href=&quot;https://ipython.readthedocs.io/en/stable/interactive/magics.html&quot;&gt;IPython’s magic command&lt;/a&gt; called &lt;code&gt;%julia&lt;/code&gt;. Just prepend &lt;code&gt;%julia&lt;/code&gt; to Julia commands. In this case, use &lt;code&gt;$var&lt;/code&gt; to access python variables&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-linear-algebra&quot;&gt;Example: Linear Algebra&lt;/h3&gt;
&lt;p&gt;In this short example, we can see one of the strengths of Julia syntax for Linear Algebra. A random linear system is created and solved. The result is checked with NumPy, so we can see the compatibility.&lt;/p&gt;
&lt;p&gt;We have chosen to define &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; in three different ways, to show the different syntaxes. The definition of &lt;strong&gt;A&lt;/strong&gt; occurs completely inside the eval block. The variable &lt;code&gt;A&lt;/code&gt; is created and is available inside the Julia scope, or as &lt;code&gt;Main.A&lt;/code&gt;. The definition of &lt;code&gt;b&lt;/code&gt; uses the &lt;code&gt;Main.b&lt;/code&gt; access directly and uses the result of &lt;code&gt;Main.eval&lt;/code&gt;. Finally, &lt;code&gt;%julia&lt;/code&gt; is the magic IPython command to simply use Julia syntax directly.&lt;/p&gt;
&lt;p&gt;We can quickly compare the timing of solving the system with Julia’s backslash command and Numpy’s &lt;code&gt;linalg.solve&lt;/code&gt;:&lt;/p&gt;
&lt;h3 id=&quot;example-automatic-differentiation&quot;&gt;Example: Automatic differentiation&lt;/h3&gt;
&lt;p&gt;The next example installs and uses the package called &lt;strong&gt;ForwardDiff&lt;/strong&gt;, which performs automatic differentiation. ForwardDiff defines a Julia type called &lt;strong&gt;Dual&lt;/strong&gt; internally, so we can’t use it with Python functions because Python functions are not compatible with that type. However, we can define Julia functions and use them.&lt;/p&gt;
&lt;p&gt;The local minimum of the quadratic occurs at 2.5, so the derivative at 2.5 is 0.0.&lt;/p&gt;
&lt;p&gt;Another, more interesting interaction is below, in which we create a function &lt;em&gt;g&lt;/em&gt; inside Julia, and define functions for its derivatives there. Then we create a Python function with the Taylor expansion around the value &lt;em&gt;a&lt;/em&gt;. Furthermore, we use Matplotlib, Python’s plotting library to visualize the results coming from Julia. Pretty neat, right?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;720&quot; height=&quot;432&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PFodxQbLaofzbmaYRPzuZA-ba9a400c.Cy3ZWdRe_Z1eiLx4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated above, showing the function f and its third-order Taylor approximation.&lt;/p&gt;
&lt;h2 id=&quot;next-episodes&quot;&gt;Next episodes&lt;/h2&gt;
&lt;p&gt;Now that we can call Julia code in Python, we are prepared to move to our next adventure: improve the speed of a Python code by calling Julia from it. &lt;a href=&quot;https://blog.esciencecenter.nl/&quot;&gt;Follow our medium account&lt;/a&gt; to get notified when Part 2 goes live.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;Jason Maassen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;Jurrian Spaaks&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;Rob van Nieuwpoort&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;, and &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Wed, 19 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;a-three-part-series-on-achieving-high-performance-with-high-level-code&quot;&gt;A three-part series on achieving high performance with high-level code&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_rO_VWgfXj4zuFDtX28Uc1g-c9e56d67.mmCamWYW_ZCAFTk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Caption: Astronaut carrying Python and Julia. Photo by Brian McGowan on Unsplash ( &lt;a href=&quot;https://unsplash.com/photos/MR9xsNWVKvo&quot;&gt;https://unsplash.com/photos/MR9xsNWVKvo&lt;/a&gt; ), modified by us.&lt;/p&gt;
&lt;h3 id=&quot;target-audience&quot;&gt;Target audience&lt;/h3&gt;
&lt;p&gt;This is the first post in a three-part series about achieving high performance with high-level code. This series is aimed at people working with Python who needs better performance but prefers not to develop a low-level performant library.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Having recently joined the Netherlands eScience Center after working with research using the Julia language for seven years, I was excited to highlight some of its cool features. At the eScience Center, many of our engineers use Python, some use C or C++, and in some cases, we see Python calling C++ code, to speed up the code. This was the perfect opportunity to introduce Julia’s interoperability with Python and to investigate whether we could achieve comparable speed by calling Julia code in Python. This means that for situations where Python’s performance is not sufficient, we can speed it up with another high-level language, avoiding the use of a low-level language like C++. This series of three blog posts will investigate these topics.&lt;/p&gt;
&lt;p&gt;In this first post, we will learn how to call a Julia code from Python. We will set up the environment and show some examples. In the second post, we will take a problem that was solved by using Python in combination with C++ to speed up the code. We will replace the C++ code with a Julia code and compare the performance. In the third post, we will solve the same problem in Julia, optimize the Julia code to reach its maximum performance and compare it with the implementation in the second post.&lt;/p&gt;
&lt;h2 id=&quot;what-is-julia-and-how-does-it-compare-to-python&quot;&gt;What is Julia, and how does it compare to Python?&lt;/h2&gt;
&lt;p&gt;What is Julia? Julia is a high-performance, high-level programming language. It was created a few years ago with the ambitious goal of being fast with a high-level syntax, and it has been mostly successful. It can, in a few cases, reach the speed of low-level programming languages like C. For more information, the &lt;a href=&quot;https://julialang.org/&quot;&gt;julialang.org&lt;/a&gt; site is a great first stop.&lt;/p&gt;
&lt;p&gt;One of the most frequently asked questions is: “how does it compare to Python or some other programming language in terms of performance?”. The short answer: Julia is &lt;a href=&quot;https://julialang.org/benchmarks&quot;&gt;generally faster&lt;/a&gt; than Python and many other programming languages.&lt;/p&gt;
&lt;p&gt;The performance of a Python code can be optimized, but even the optimized code usually underperforms compared to a Julia version of the same code. The performance increase of a Python code can be achieved in a few ways, but a frequent one is to call a code written in a low-level language, such as C, C++ and Fortran, like NumPy which does its calculations mostly in those low-level languages. What is less common, but also possible, is to call Julia from Python. In this post, we are going to show you how to do that!&lt;/p&gt;
&lt;p&gt;Before we forget, all the code used in this post can be found in our &lt;a href=&quot;https://github.com/abelsiqueira/faster-python-using-julia-blogposts&quot;&gt;GitHub repository&lt;/a&gt;. We have also created a &lt;a href=&quot;https://hub.docker.com/r/abelsiqueira/python-and-julia&quot;&gt;Docker image&lt;/a&gt; that includes a ready-to-use environment to run both Julia and Python. To run that environment with Python 3.10 and Julia 1.6, install Docker and run the following in your terminal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker pull abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jl1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; docker run &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;it exec abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jl1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bin&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;
&lt;p&gt;In the following steps, we will configure our system to execute Julia code from Python. To learn more about this topic, the documentation for the packages we describe below is a great starting point. You will need four things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; distribution &lt;a href=&quot;https://docs.python.org/3/using/configure.html#cmdoption-enable-shared&quot;&gt;compiled with shared libpython&lt;/a&gt; option. There are workarounds, but this is the most straightforward way.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://julialang.org/&quot;&gt;&lt;strong&gt;Julia&lt;/strong&gt;&lt;/a&gt;, the executable that runs the Julia language.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JuliaPy/PyCall.jl&quot;&gt;&lt;strong&gt;PyCall,&lt;/strong&gt;&lt;/a&gt; the Julia package that defines the conversions between Julia and Python.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pyjulia.readthedocs.io/en/stable/&quot;&gt;&lt;strong&gt;PyJulia&lt;/strong&gt;&lt;/a&gt;, the Python package to access Julia from Python.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We are going to go through the installation and configuration of these steps on a Linux system. It will be very similar on MacOS or with &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install&quot;&gt;WSL&lt;/a&gt; for Windows once the required tools are installed.&lt;/p&gt;
&lt;h3 id=&quot;step-1-python-with-shared-libpython&quot;&gt;Step 1: Python with shared libpython&lt;/h3&gt;
&lt;p&gt;To check whether the Python distribution is compiled with &lt;strong&gt;—enable-shared&lt;/strong&gt; option, we run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ldd &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(which python3) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; grep libpython&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the output is something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libpython3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;usr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libpython3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x00007f567e548000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… then we are good to go! If we get nothing, that means that the Python distribution has not been compiled with the desired flags. In this case, we can compile our own Python distribution with the flag &lt;strong&gt;—enable-shared&lt;/strong&gt;, which takes some time but is mostly straightforward. This &lt;a href=&quot;https://github.com/abelsiqueira/python-and-julia/blob/debf6da21390c34331b708d8e93b97563ac83a78/Dockerfile#L22&quot;&gt;Dockerfile&lt;/a&gt; has the instructions. Remember that if you just want to test it out, you can run the Docker image as mentioned in the previous section.&lt;/p&gt;
&lt;h3 id=&quot;step-2-julia-and-pycall&quot;&gt;Step 2: Julia and PyCall&lt;/h3&gt;
&lt;p&gt;Now, we will install Julia. We recommend using &lt;a href=&quot;https://github.com/abelsiqueira/jill&quot;&gt;jill&lt;/a&gt;, a script I created, which downloads and installs a specific version of Julia, but Julia can also be installed via the official binaries or package managers. In this post, we use version 1.6.5, which is the current Long Term Support version at the time of writing. Most likely this will work with a newer version as well. To install Julia 1.6.5 using jill, we run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; wget https&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;://&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;raw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;githubusercontent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;com&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;abelsiqueira&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4.0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sh&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sudo bash jill&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sh &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will install PyCall and configure it to use the correct Python version. We start Julia by running &lt;code&gt;julia&lt;/code&gt; in the terminal, and then we set the &lt;code&gt;ENV[&quot;PYTHON&quot;]&lt;/code&gt; variable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; juliajulia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;PYTHON&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;PATH/TO/python&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we use the full path to Python’s executable. In our case, it is the Python distribution we compiled from the source code. You could change the path according to your configuration.&lt;/p&gt;
&lt;p&gt;Now, we will install PyCall using Pkg, Julia’s package manager:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; using &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Pkgjulia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Pkg.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;add(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;PyCall&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-pyjulia&quot;&gt;Step 3: PyJulia&lt;/h3&gt;
&lt;p&gt;As the last step, we must install the Python package to talk with Julia. First, use pip, Python’s package manager, to install the package PyJulia — remember to use the same Python passed to &lt;code&gt;ENV[&quot;PYTHON&quot;]&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;–&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m pip install julia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To finalize configuring the communication between Julia and Python, we run the following in the Python interpreter:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; import julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we had more than one Julia version on our system, we could specify it with an argument:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install(julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;julia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;5&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We test the installation running the following in the Python interpreter run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; from julia import &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Main&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Main.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;eval(&apos;[x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; for x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;showcasing-pyjulia&quot;&gt;Showcasing PyJulia&lt;/h2&gt;
&lt;h3 id=&quot;basics&quot;&gt;Basics&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To use a Julia module, use &lt;code&gt;from julia import MODULE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To evaluate a command, import &lt;code&gt;Main&lt;/code&gt; and use &lt;code&gt;Main.eval(&quot;...&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To create and use variables, use &lt;code&gt;Main.VARIABLE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To install Julia packages, &lt;code&gt;import Pkg&lt;/code&gt; and use &lt;code&gt;Pkg.add(&quot;Package&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;%load_ext julia.magic&lt;/code&gt; to add a &lt;a href=&quot;https://ipython.readthedocs.io/en/stable/interactive/magics.html&quot;&gt;IPython’s magic command&lt;/a&gt; called &lt;code&gt;%julia&lt;/code&gt;. Just prepend &lt;code&gt;%julia&lt;/code&gt; to Julia commands. In this case, use &lt;code&gt;$var&lt;/code&gt; to access python variables&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-linear-algebra&quot;&gt;Example: Linear Algebra&lt;/h3&gt;
&lt;p&gt;In this short example, we can see one of the strengths of Julia syntax for Linear Algebra. A random linear system is created and solved. The result is checked with NumPy, so we can see the compatibility.&lt;/p&gt;
&lt;p&gt;We have chosen to define &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; in three different ways, to show the different syntaxes. The definition of &lt;strong&gt;A&lt;/strong&gt; occurs completely inside the eval block. The variable &lt;code&gt;A&lt;/code&gt; is created and is available inside the Julia scope, or as &lt;code&gt;Main.A&lt;/code&gt;. The definition of &lt;code&gt;b&lt;/code&gt; uses the &lt;code&gt;Main.b&lt;/code&gt; access directly and uses the result of &lt;code&gt;Main.eval&lt;/code&gt;. Finally, &lt;code&gt;%julia&lt;/code&gt; is the magic IPython command to simply use Julia syntax directly.&lt;/p&gt;
&lt;p&gt;We can quickly compare the timing of solving the system with Julia’s backslash command and Numpy’s &lt;code&gt;linalg.solve&lt;/code&gt;:&lt;/p&gt;
&lt;h3 id=&quot;example-automatic-differentiation&quot;&gt;Example: Automatic differentiation&lt;/h3&gt;
&lt;p&gt;The next example installs and uses the package called &lt;strong&gt;ForwardDiff&lt;/strong&gt;, which performs automatic differentiation. ForwardDiff defines a Julia type called &lt;strong&gt;Dual&lt;/strong&gt; internally, so we can’t use it with Python functions because Python functions are not compatible with that type. However, we can define Julia functions and use them.&lt;/p&gt;
&lt;p&gt;The local minimum of the quadratic occurs at 2.5, so the derivative at 2.5 is 0.0.&lt;/p&gt;
&lt;p&gt;Another, more interesting interaction is below, in which we create a function &lt;em&gt;g&lt;/em&gt; inside Julia, and define functions for its derivatives there. Then we create a Python function with the Taylor expansion around the value &lt;em&gt;a&lt;/em&gt;. Furthermore, we use Matplotlib, Python’s plotting library to visualize the results coming from Julia. Pretty neat, right?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;720&quot; height=&quot;432&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_PFodxQbLaofzbmaYRPzuZA-ba9a400c.Cy3ZWdRe_Z1eiLx4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Image generated above, showing the function f and its third-order Taylor approximation.&lt;/p&gt;
&lt;h2 id=&quot;next-episodes&quot;&gt;Next episodes&lt;/h2&gt;
&lt;p&gt;Now that we can call Julia code in Python, we are prepared to move to our next adventure: improve the speed of a Python code by calling Julia from it. &lt;a href=&quot;https://blog.esciencecenter.nl/&quot;&gt;Follow our medium account&lt;/a&gt; to get notified when Part 2 goes live.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to our proofreaders and reviewers,&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-elena-ranguelova/&quot;&gt;&lt;em&gt;Elena Ranguelova&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jason-maassen/&quot;&gt;Jason Maassen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;Jurrian Spaaks&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-patrick-bos/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/prof-dr-rob-van-nieuwpoort/&quot;&gt;Rob van Nieuwpoort&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;, and &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_PFodxQbLaofzbmaYRPzuZA-ba9a400c.Cy3ZWdRe.png" medium="image"/><author>Abel Soares Siqueira</author></item><item><title>What is in the eScience toolbox: Stef on his favourite meshing library</title><link>https://blog.esciencecenter.nl/posts/2022-01-05---what-is-in-the-escience-toolbox-stef-on-his-favourite-meshin</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2022-01-05---what-is-in-the-escience-toolbox-stef-on-his-favourite-meshin</guid><description>&lt;p&gt;&lt;em&gt;Question: Hi Stef, for this blog series we are looking to highlight our developer’s favourite libraries.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: As research software engineers we always get excited by tools that exactly fit the job that we need it for. For this &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt; library I’m developing, I was looking for a 2D triangle &lt;a href=&quot;https://en.wikipedia.org/wiki/Mesh_generation&quot;&gt;mesh generator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Wait.. wait… Meshes?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Meshes simplify image data and describe complex geometries. A mesh is essentially a collection of vertices and triangles. They are used for computer graphics and physical simulations, such as finite element analyses and fluid dynamics.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Like in computer games?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Exactly!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: I have heard&lt;/em&gt; &lt;a href=&quot;https://www.cgal.org/&quot;&gt;&lt;em&gt;CGAL&lt;/em&gt;&lt;/a&gt; &lt;em&gt;is the go-to library for Meshing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: CGAL is an excellent choice. It’s written in C++, and provides easy access to efficient and reliable geometric algorithms. Unfortunately, for my purpose, CGAL is a bit heavy-weight, difficult to install on Windows, and lacks an intuitive Python interface.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: So what did you end up using?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: After having tried a few more meshing libraries, I came across &lt;a href=&quot;https://www.cs.cmu.edu/~quake/triangle.html&quot;&gt;Triangle&lt;/a&gt;. Triangle is an open-source two-dimensional quality mesh generator that supports multiple domains. It’s written in C++ and supports all three major operating systems. It’s lightweight and there is a well-documented &lt;a href=&quot;https://rufat.be/triangle/API.html&quot;&gt;Python API available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Cool, so how do you install it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: It’s available on &lt;a href=&quot;https://pypi.org/project/triangle/&quot;&gt;pypi&lt;/a&gt;. If you are already using Python, just do the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install triangle&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: That’s great! That will make it easy to integrate it into my existing project. How do you use it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Let me give you an example. Here is the code to generate a simple square and triangulate it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; matplotlib.pyplot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pltimport numpy &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; npimport triangle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vertices &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])inp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&apos;vertices&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vertices}out &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;triangulate(inp, opts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;qa0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;05&apos;)tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;compare(plt, inp, out)plt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;505&quot; height=&quot;255&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KwRJMoxH9912dHdBlhYa5Q-edc53a20.BwrlUnLS_2fKkpk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Triangle makes it easy to display the results.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: So I see Triangle filling the box with little triangles. How does that work?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Alright, let me break it down for you.&lt;/p&gt;
&lt;p&gt;First, we import &lt;code&gt;matplotlib&lt;/code&gt;, &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;triangle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Second, we generate the vertices representing a square with edges of length l and store them in a dictionary.&lt;/p&gt;
&lt;p&gt;Next, we call triangulate. The options &lt;code&gt;opts=qa0.05&lt;/code&gt; tell triangle to perform a quality mesh (&lt;code&gt;q&lt;/code&gt;), and that no triangles have an area larger than 0.05 (&lt;code&gt;a0.05&lt;/code&gt;). A quality mesh is a mesh with all angles over 30 degrees.&lt;/p&gt;
&lt;p&gt;Finally, triangle has a useful function to compare the input and the output.&lt;/p&gt;
&lt;p&gt;Try playing around with the area to see what happens to the result!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: That’s great! For finite element analysis, wouldn’t it be useful to specify different regions?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Yes, that is one of the strengths of &lt;code&gt;triangle&lt;/code&gt;. It makes multi-region meshing easy. This means that it can label triangles according to the region it belongs to.&lt;/p&gt;
&lt;p&gt;Let me give you an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vertices &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])segments &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])regions &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])inp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;vertices&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vertices, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;segments&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; segments, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;regions&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; regions,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}out &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;triangulate(inp, opts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;pqa0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;05&apos;)tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;compare(plt, inp, out)plt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;506&quot; height=&quot;254&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_j7JqSTDcmkZDdA-1u2QEoA-0bb45cd8.8mmJb3Lq_Z9zwKX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Same input, now divided in two regions.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Can you explain how it works?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: The difference here is that we specify the different segments. The segments describe the boundaries of a region inside the square. Triangles will be generated for each region independently. Each region thus contains its own set of triangles, and are labeled accordingly.&lt;/p&gt;
&lt;p&gt;The format for defining &lt;code&gt;regions&lt;/code&gt; can seem a bit tricky at first. For each row, e.g. &lt;code&gt;[0.75, 0.75, 1, 0]&lt;/code&gt;, the first two numbers describe the coordinate, and the third number is the label of the region. The final number can be used to set the maximum area in that region. We don’t use that here, so we set it to &lt;code&gt;0&lt;/code&gt;. As before, use the compare function to check the result. And that’s it!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Wow, I want to start using this now! Where can I learn more?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: I’m really happy to hear that! If you want to know more, the documentation and examples for triangle are available &lt;a href=&quot;https://rufat.be/triangle/API.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;triangle&lt;/code&gt; as the triangle mesh generator in one of our &lt;a href=&quot;https://www.esciencecenter.nl/projects/computation-of-the-optical-properties-of-nano-structures/&quot;&gt;projects&lt;/a&gt;. The code we using it in, &lt;code&gt;nanomesh&lt;/code&gt;, is a Python workflow tool to prepare meshes for finite element analysis from 2D (and 3D!) microscopy image data.&lt;/p&gt;</description><pubDate>Wed, 05 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Question: Hi Stef, for this blog series we are looking to highlight our developer’s favourite libraries.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: As research software engineers we always get excited by tools that exactly fit the job that we need it for. For this &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt; library I’m developing, I was looking for a 2D triangle &lt;a href=&quot;https://en.wikipedia.org/wiki/Mesh_generation&quot;&gt;mesh generator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Wait.. wait… Meshes?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Meshes simplify image data and describe complex geometries. A mesh is essentially a collection of vertices and triangles. They are used for computer graphics and physical simulations, such as finite element analyses and fluid dynamics.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Like in computer games?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Exactly!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: I have heard&lt;/em&gt; &lt;a href=&quot;https://www.cgal.org/&quot;&gt;&lt;em&gt;CGAL&lt;/em&gt;&lt;/a&gt; &lt;em&gt;is the go-to library for Meshing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: CGAL is an excellent choice. It’s written in C++, and provides easy access to efficient and reliable geometric algorithms. Unfortunately, for my purpose, CGAL is a bit heavy-weight, difficult to install on Windows, and lacks an intuitive Python interface.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: So what did you end up using?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: After having tried a few more meshing libraries, I came across &lt;a href=&quot;https://www.cs.cmu.edu/~quake/triangle.html&quot;&gt;Triangle&lt;/a&gt;. Triangle is an open-source two-dimensional quality mesh generator that supports multiple domains. It’s written in C++ and supports all three major operating systems. It’s lightweight and there is a well-documented &lt;a href=&quot;https://rufat.be/triangle/API.html&quot;&gt;Python API available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Cool, so how do you install it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: It’s available on &lt;a href=&quot;https://pypi.org/project/triangle/&quot;&gt;pypi&lt;/a&gt;. If you are already using Python, just do the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install triangle&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: That’s great! That will make it easy to integrate it into my existing project. How do you use it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Let me give you an example. Here is the code to generate a simple square and triangulate it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; matplotlib.pyplot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pltimport numpy &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; npimport triangle &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vertices &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])inp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&apos;vertices&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vertices}out &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;triangulate(inp, opts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;qa0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;05&apos;)tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;compare(plt, inp, out)plt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;505&quot; height=&quot;255&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_KwRJMoxH9912dHdBlhYa5Q-edc53a20.BwrlUnLS_2fKkpk.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Triangle makes it easy to display the results.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: So I see Triangle filling the box with little triangles. How does that work?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Alright, let me break it down for you.&lt;/p&gt;
&lt;p&gt;First, we import &lt;code&gt;matplotlib&lt;/code&gt;, &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;triangle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Second, we generate the vertices representing a square with edges of length l and store them in a dictionary.&lt;/p&gt;
&lt;p&gt;Next, we call triangulate. The options &lt;code&gt;opts=qa0.05&lt;/code&gt; tell triangle to perform a quality mesh (&lt;code&gt;q&lt;/code&gt;), and that no triangles have an area larger than 0.05 (&lt;code&gt;a0.05&lt;/code&gt;). A quality mesh is a mesh with all angles over 30 degrees.&lt;/p&gt;
&lt;p&gt;Finally, triangle has a useful function to compare the input and the output.&lt;/p&gt;
&lt;p&gt;Try playing around with the area to see what happens to the result!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: That’s great! For finite element analysis, wouldn’t it be useful to specify different regions?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: Yes, that is one of the strengths of &lt;code&gt;triangle&lt;/code&gt;. It makes multi-region meshing easy. This means that it can label triangles according to the region it belongs to.&lt;/p&gt;
&lt;p&gt;Let me give you an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vertices &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])segments &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]])regions &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;array([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.25&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])inp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;vertices&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vertices, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;segments&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; segments, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &apos;regions&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; regions,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}out &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;triangulate(inp, opts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;pqa0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;05&apos;)tr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;compare(plt, inp, out)plt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;506&quot; height=&quot;254&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_j7JqSTDcmkZDdA-1u2QEoA-0bb45cd8.8mmJb3Lq_Z9zwKX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Same input, now divided in two regions.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Can you explain how it works?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: The difference here is that we specify the different segments. The segments describe the boundaries of a region inside the square. Triangles will be generated for each region independently. Each region thus contains its own set of triangles, and are labeled accordingly.&lt;/p&gt;
&lt;p&gt;The format for defining &lt;code&gt;regions&lt;/code&gt; can seem a bit tricky at first. For each row, e.g. &lt;code&gt;[0.75, 0.75, 1, 0]&lt;/code&gt;, the first two numbers describe the coordinate, and the third number is the label of the region. The final number can be used to set the maximum area in that region. We don’t use that here, so we set it to &lt;code&gt;0&lt;/code&gt;. As before, use the compare function to check the result. And that’s it!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Question: Wow, I want to start using this now! Where can I learn more?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Stef: I’m really happy to hear that! If you want to know more, the documentation and examples for triangle are available &lt;a href=&quot;https://rufat.be/triangle/API.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;triangle&lt;/code&gt; as the triangle mesh generator in one of our &lt;a href=&quot;https://www.esciencecenter.nl/projects/computation-of-the-optical-properties-of-nano-structures/&quot;&gt;projects&lt;/a&gt;. The code we using it in, &lt;code&gt;nanomesh&lt;/code&gt;, is a Python workflow tool to prepare meshes for finite element analysis from 2D (and 3D!) microscopy image data.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_KwRJMoxH9912dHdBlhYa5Q-edc53a20.BwrlUnLS.png" medium="image"/><author>Stef Smeets</author></item><item><title>Still coding texts by hand for social science text analysis? Use Doccano instead to speed up the process!</title><link>https://blog.esciencecenter.nl/posts/2021-12-21---still-coding-texts-by-hand-for-social-science-text-analysis-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-12-21---still-coding-texts-by-hand-for-social-science-text-analysis-</guid><description>&lt;p&gt;][Sven van der Burg]·Dec 21, 2021&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coder-centered: **It is designed to make the coder’s life as easy as possible. You view one text at a time at the center of your screen. All you have to do is this: select a piece of text with your pointer, and click or hit a shortkey to add a label (for example: `concept 1’). When the complete text is coded, just click next. It’s as simple as that.&lt;/li&gt;
&lt;li&gt;**No more errors in data entry: **As a data analyst, you don’t need to worry about how exactly a coder enters the data as you would, for example, when data is coded in an Excel sheet. Doccano enforces that any data entry results in nicely formatted data. You can download the data without any data entry errors.&lt;/li&gt;
&lt;li&gt;**Open-source: **The programming code for Doccano is open for everyone to see and edit (under sensible restrictions, of course). This makes it free to use and easy to setup yourself in any scenario. In addition, if you want to add a new feature, you can always add it yourself or request it in the community. Yay for open-source software!&lt;/li&gt;
&lt;li&gt;**Collaborative coding: **Doccano allows different coders to code the same text, which is very useful if you want to get reliable labels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-does-doccano-compare-to-nvivo-or-maxqda&quot;&gt;How does Doccano compare to NVivo or MAXQDA?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.qsrinternational.com/nvivo-qualitative-data-analysis-software/home&quot;&gt;NVivo&lt;/a&gt; and &lt;a href=&quot;https://www.maxqda.com/&quot;&gt;Maxqda&lt;/a&gt; also allow you to select sections of documents, but they are only useful for thematic analysis using extensive coding trees. Both are paid packages, whereas Doccano is completely free and easier to work with. Doccano is easily combined with other analysis frameworks like SPSS, Excel, R, or Python, whereas NVivo and MAXQDA want you to do your complete analysis within their program.&lt;/p&gt;
&lt;h2 id=&quot;how-does-doccano-compare-to-amcat&quot;&gt;How does Doccano compare to Amcat?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://wiki.amcat.nl/3.4:AmCAT_Navigator_3&quot;&gt;AmCAT&lt;/a&gt; also allows token-level and sentence-level coding (see &lt;a href=&quot;http://wiki.amcat.nl/3.3:Annotator&quot;&gt;their documentation&lt;/a&gt;). But it’s certainly not as coder-centered as Doccano. In addition, it is much more complex compared to Doccano’s simple interface.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;We hope that we’ve convinced you that using Doccano can be a simple improvement in text analysis pipelines. So, what’s next?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Try out the &lt;a href=&quot;http://doccano.herokuapp.com/demo/named-entity-recognition&quot;&gt;Doccano demo&lt;/a&gt; to get a feel for how it works.&lt;/li&gt;
&lt;li&gt;Because of it’s open source nature, you have to run Doccano in a cloud environment yourself. Fortunately, you can do this without any technical knowledge. Just follow the first part of &lt;a href=&quot;https://lingudocs.mcasado.org/posts/20210103_Tagging-a-linguistic-corpus-for-free/&quot;&gt;this excellent guide&lt;/a&gt; to setup Doccano on Heroku (ignore the prerequisites, you don’t need them). You will have your own free Doccano environment within 15 minutes.&lt;/li&gt;
&lt;li&gt;Follow the further instructions in &lt;a href=&quot;https://lingudocs.mcasado.org/posts/20210103_Tagging-a-linguistic-corpus-for-free/&quot;&gt;that guide&lt;/a&gt; to add a dataset and tags within Doccano to kickstart your first coding project! NB: Double check whether you are allowed to upload your data to Heroku, maybe there are privacy or security concerns. If there are concerns you could discuss installing Doccano on your institution’s own infrastructure.&lt;/li&gt;
&lt;li&gt;You can download your coded data as .jsonl file. This file can be opened with notepad or transferred to .csv &lt;a href=&quot;https://www.convertcsv.com/json-to-csv.htm&quot;&gt;online&lt;/a&gt;. The coded sections in the Doccano output can easily be transformed back from ‘token position’ into text via the text function ‘mid’ in Excel if you are not familiar with programming.&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Tue, 21 Dec 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;][Sven van der Burg]·Dec 21, 2021&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coder-centered: **It is designed to make the coder’s life as easy as possible. You view one text at a time at the center of your screen. All you have to do is this: select a piece of text with your pointer, and click or hit a shortkey to add a label (for example: `concept 1’). When the complete text is coded, just click next. It’s as simple as that.&lt;/li&gt;
&lt;li&gt;**No more errors in data entry: **As a data analyst, you don’t need to worry about how exactly a coder enters the data as you would, for example, when data is coded in an Excel sheet. Doccano enforces that any data entry results in nicely formatted data. You can download the data without any data entry errors.&lt;/li&gt;
&lt;li&gt;**Open-source: **The programming code for Doccano is open for everyone to see and edit (under sensible restrictions, of course). This makes it free to use and easy to setup yourself in any scenario. In addition, if you want to add a new feature, you can always add it yourself or request it in the community. Yay for open-source software!&lt;/li&gt;
&lt;li&gt;**Collaborative coding: **Doccano allows different coders to code the same text, which is very useful if you want to get reliable labels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-does-doccano-compare-to-nvivo-or-maxqda&quot;&gt;How does Doccano compare to NVivo or MAXQDA?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.qsrinternational.com/nvivo-qualitative-data-analysis-software/home&quot;&gt;NVivo&lt;/a&gt; and &lt;a href=&quot;https://www.maxqda.com/&quot;&gt;Maxqda&lt;/a&gt; also allow you to select sections of documents, but they are only useful for thematic analysis using extensive coding trees. Both are paid packages, whereas Doccano is completely free and easier to work with. Doccano is easily combined with other analysis frameworks like SPSS, Excel, R, or Python, whereas NVivo and MAXQDA want you to do your complete analysis within their program.&lt;/p&gt;
&lt;h2 id=&quot;how-does-doccano-compare-to-amcat&quot;&gt;How does Doccano compare to Amcat?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://wiki.amcat.nl/3.4:AmCAT_Navigator_3&quot;&gt;AmCAT&lt;/a&gt; also allows token-level and sentence-level coding (see &lt;a href=&quot;http://wiki.amcat.nl/3.3:Annotator&quot;&gt;their documentation&lt;/a&gt;). But it’s certainly not as coder-centered as Doccano. In addition, it is much more complex compared to Doccano’s simple interface.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;We hope that we’ve convinced you that using Doccano can be a simple improvement in text analysis pipelines. So, what’s next?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Try out the &lt;a href=&quot;http://doccano.herokuapp.com/demo/named-entity-recognition&quot;&gt;Doccano demo&lt;/a&gt; to get a feel for how it works.&lt;/li&gt;
&lt;li&gt;Because of it’s open source nature, you have to run Doccano in a cloud environment yourself. Fortunately, you can do this without any technical knowledge. Just follow the first part of &lt;a href=&quot;https://lingudocs.mcasado.org/posts/20210103_Tagging-a-linguistic-corpus-for-free/&quot;&gt;this excellent guide&lt;/a&gt; to setup Doccano on Heroku (ignore the prerequisites, you don’t need them). You will have your own free Doccano environment within 15 minutes.&lt;/li&gt;
&lt;li&gt;Follow the further instructions in &lt;a href=&quot;https://lingudocs.mcasado.org/posts/20210103_Tagging-a-linguistic-corpus-for-free/&quot;&gt;that guide&lt;/a&gt; to add a dataset and tags within Doccano to kickstart your first coding project! NB: Double check whether you are allowed to upload your data to Heroku, maybe there are privacy or security concerns. If there are concerns you could discuss installing Doccano on your institution’s own infrastructure.&lt;/li&gt;
&lt;li&gt;You can download your coded data as .jsonl file. This file can be opened with notepad or transferred to .csv &lt;a href=&quot;https://www.convertcsv.com/json-to-csv.htm&quot;&gt;online&lt;/a&gt;. The coded sections in the Doccano output can easily be transformed back from ‘token position’ into text via the text function ‘mid’ in Excel if you are not familiar with programming.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><author>Sven van der Burg</author></item><item><title>The new IPCC assessment report: stakes have been raised</title><link>https://blog.esciencecenter.nl/posts/2021-12-14---the-new-ipcc-assessment-report-stakes-have-been-raised</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-12-14---the-new-ipcc-assessment-report-stakes-have-been-raised</guid><description>&lt;p&gt;In &lt;a href=&quot;https://www.primavera-h2020.eu/&quot;&gt;PRIMAVERA&lt;/a&gt;, a Horizon 2020 project, we focused upon the I/O machinery in a big European climate model &lt;a href=&quot;http://www.ec-earth.org/about/&quot;&gt;EC-Earth&lt;/a&gt;. In particular, we were asked to come up with a solution to make this model produce those CMIP6 standardized output quantities, preferably without slashing the performance of the simulation workflow. The answer: we leveraged parallel Python to crunch through the high-resolution raw climate data of EC-Earth and apply the necessary formulas and conversions; the &lt;a href=&quot;https://github.com/EC-Earth/ece2cmor3&quot;&gt;ece2cmor3&lt;/a&gt; tool that does this has been adopted by the community as the method of choice to post-process this model output, and has since then been used to produce petabytes of climate model data for AR6.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The new IPCC assessment report: stakes have been raised&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;389&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-new-ipcc-assessment-report-stakes-ha-64226777.CsBCGuG7_ZYqN3R.webp&quot; srcset=&quot;&quot;&gt;
Emerging lakes at the termini of receding glaciers in the Bhutan-Himalaya in 2002 (source: NASA)Leaving the data production side of the equation, we enter the analysis aspect of the research: you see, 200 years of simulated global humidity fields on, say, 27 atmospheric pressure levels doesn’t quite answer questions of fellow researchers or policy makers by itself. These data serve as input to tools and applications that reduce them to relevant information for society and the scientific community. The problem is that ‘tools and applications’ often translate into an unsustainable mess of ad-hoc scripts. These get stitched together as a sequence of undocumented commands along the lines of “./proc.sh work/out.nc work/out2.nc”. Now when a colleague asks three months later to “recreate that figure for some other climate model”, a panicky feeling takes over, soon to be followed with regret over the lack of design and documentation, ending in frustration over the fact that those beloved tools appear to have stopped functioning after the previous OS update. And to be frank, analyzing climate data is just becoming too costly in terms of time, RAM, disk space and network bandwidth to just do freewheeling on a PC.&lt;/p&gt;
&lt;p&gt;This also has been recognized by the climate community, and data analysis frameworks have been steadily gaining momentum. You may know &lt;a href=&quot;https://pangeo.io/index.html&quot;&gt;Pangeo&lt;/a&gt;, the &lt;a href=&quot;https://cds.climate.copernicus.eu/#!/home&quot;&gt;Copernicus Data Store&lt;/a&gt;, the &lt;a href=&quot;https://climexp.knmi.nl&quot;&gt;KNMI Climate Explorer&lt;/a&gt;, or the &lt;a href=&quot;https://www.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt; suite, which was used for several charts and tables into create several figures in AR6. ESMValTool stands for Earth System Model Validation Tool, but it can do a lot more than that; it ensures one uses standardized algorithms, containerized tools and transparent provenance during the process of extracting useful information from the massive amount of data coming from observations and models. It makes it easy to create &lt;a href=&quot;https://www.rd-alliance.org/group/fair-research-software-fair4rs-wg/outcomes/fair-principles-research-software-fair4rs&quot;&gt;Findable, Accessible, Interoperable, and Reproducible&lt;/a&gt; (FAIR) analysis software for climate data. Within the &lt;a href=&quot;https://www.esciencecenter.nl/projects/is-enes3/&quot;&gt;IS-ENES3&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/news/c3s-magic-developing-software-for-data-from-climate-models/&quot;&gt;C3S-MAGIC&lt;/a&gt; projects, we have made many contributions to ESMValTool, and we have greatly benefited from its capabilities in the &lt;a href=&quot;https://www.esciencecenter.nl/projects/ewatercycle-ii/&quot;&gt;eWaterCycle2&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/projects/european-climate-prediction-system/&quot;&gt;EUCP&lt;/a&gt; projects.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The new IPCC assessment report: stakes have been raised&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;463&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-new-ipcc-assessment-report-stakes-ha-ac0837cb.UuCigevE_1Jti88.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@karsten_wuerth&quot;&gt;Karsten Würth&lt;/a&gt; at &lt;a href=&quot;https://unsplash.com&quot;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, we get to the aspect of disseminating the AR6 message to a broad audience. When you navigate to the IPCC web page to look at the AR6 conclusions yourself, you may quickly find yourself lost in the scientific jargon and formal language. AR6 is targeted at researchers and policy makers, but its implications are so far-reaching that it should be addressing our society as a whole. The aim of the H2020 project &lt;a href=&quot;https://climatestorylines.eu/&quot;&gt;RECEIPT&lt;/a&gt; is to assess Europe’s vulnerability to climate risks and represent these risks in the form of storylines. Sometimes it’s not feasible to perform a full statistical analysis of climate impacts on a complex system. Or even so, it may be that stakeholders are more interested in a few representative (or extreme) datapoints to assess their vulnerability, and that is where storylines enter the picture. By showing the chain of events caused by warming climate and intensifying extreme weather, we hope to better convey potential agricultural, socio-economic and infrastructural hazards. Here, the eScience Center plays a leading role in visualizing these storylines in an interactive &lt;a href=&quot;https://www.climateimpactstories.eu/?sector=agriculture&amp;#x26;story=1&quot;&gt;web-based environment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are just a handful of examples of where the eScience Center has in some way contributed to AR6. We have been involved in many more projects in climate and weather, detecting the &lt;a href=&quot;https://www.research-software.nl/projects/1349&quot;&gt;occurrence of climate tipping points&lt;/a&gt;, improving the predictability of climate in Europe (EUCP) and the Northern Atlantic (&lt;a href=&quot;https://blue-action.eu/&quot;&gt;Blue Action&lt;/a&gt;), or estimating the likelihood and severity of &lt;a href=&quot;https://climate.copernicus.eu/prototype-extreme-events-and-attribution-service&quot;&gt;extreme heat and flooding events&lt;/a&gt;. The common ingredient connecting these research projects is always climate change. While our opponent in the ring is gaining strength, we use science and computing to improve our ability to predict his moves and better brace for impact of the punches. The global effort to reduce emissions will be crucial to limit those impacts and hopefully prolong the battle until a jury decision, to be made by future generations.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;&lt;em&gt;Bouwe Andela&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;&lt;em&gt;Maaike de Jong&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/jesus-garcia-gonzalez-msc/&quot;&gt;&lt;em&gt;Jesus Garcia Gonzalez&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-yifat-dzigan/&quot;&gt;&lt;em&gt;Yifat Dzigan&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 14 Dec 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In &lt;a href=&quot;https://www.primavera-h2020.eu/&quot;&gt;PRIMAVERA&lt;/a&gt;, a Horizon 2020 project, we focused upon the I/O machinery in a big European climate model &lt;a href=&quot;http://www.ec-earth.org/about/&quot;&gt;EC-Earth&lt;/a&gt;. In particular, we were asked to come up with a solution to make this model produce those CMIP6 standardized output quantities, preferably without slashing the performance of the simulation workflow. The answer: we leveraged parallel Python to crunch through the high-resolution raw climate data of EC-Earth and apply the necessary formulas and conversions; the &lt;a href=&quot;https://github.com/EC-Earth/ece2cmor3&quot;&gt;ece2cmor3&lt;/a&gt; tool that does this has been adopted by the community as the method of choice to post-process this model output, and has since then been used to produce petabytes of climate model data for AR6.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The new IPCC assessment report: stakes have been raised&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;389&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-new-ipcc-assessment-report-stakes-ha-64226777.CsBCGuG7_ZYqN3R.webp&quot; srcset=&quot;&quot;&gt;
Emerging lakes at the termini of receding glaciers in the Bhutan-Himalaya in 2002 (source: NASA)Leaving the data production side of the equation, we enter the analysis aspect of the research: you see, 200 years of simulated global humidity fields on, say, 27 atmospheric pressure levels doesn’t quite answer questions of fellow researchers or policy makers by itself. These data serve as input to tools and applications that reduce them to relevant information for society and the scientific community. The problem is that ‘tools and applications’ often translate into an unsustainable mess of ad-hoc scripts. These get stitched together as a sequence of undocumented commands along the lines of “./proc.sh work/out.nc work/out2.nc”. Now when a colleague asks three months later to “recreate that figure for some other climate model”, a panicky feeling takes over, soon to be followed with regret over the lack of design and documentation, ending in frustration over the fact that those beloved tools appear to have stopped functioning after the previous OS update. And to be frank, analyzing climate data is just becoming too costly in terms of time, RAM, disk space and network bandwidth to just do freewheeling on a PC.&lt;/p&gt;
&lt;p&gt;This also has been recognized by the climate community, and data analysis frameworks have been steadily gaining momentum. You may know &lt;a href=&quot;https://pangeo.io/index.html&quot;&gt;Pangeo&lt;/a&gt;, the &lt;a href=&quot;https://cds.climate.copernicus.eu/#!/home&quot;&gt;Copernicus Data Store&lt;/a&gt;, the &lt;a href=&quot;https://climexp.knmi.nl&quot;&gt;KNMI Climate Explorer&lt;/a&gt;, or the &lt;a href=&quot;https://www.esmvaltool.org/&quot;&gt;ESMValTool&lt;/a&gt; suite, which was used for several charts and tables into create several figures in AR6. ESMValTool stands for Earth System Model Validation Tool, but it can do a lot more than that; it ensures one uses standardized algorithms, containerized tools and transparent provenance during the process of extracting useful information from the massive amount of data coming from observations and models. It makes it easy to create &lt;a href=&quot;https://www.rd-alliance.org/group/fair-research-software-fair4rs-wg/outcomes/fair-principles-research-software-fair4rs&quot;&gt;Findable, Accessible, Interoperable, and Reproducible&lt;/a&gt; (FAIR) analysis software for climate data. Within the &lt;a href=&quot;https://www.esciencecenter.nl/projects/is-enes3/&quot;&gt;IS-ENES3&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/news/c3s-magic-developing-software-for-data-from-climate-models/&quot;&gt;C3S-MAGIC&lt;/a&gt; projects, we have made many contributions to ESMValTool, and we have greatly benefited from its capabilities in the &lt;a href=&quot;https://www.esciencecenter.nl/projects/ewatercycle-ii/&quot;&gt;eWaterCycle2&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/projects/european-climate-prediction-system/&quot;&gt;EUCP&lt;/a&gt; projects.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The new IPCC assessment report: stakes have been raised&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;463&quot; src=&quot;https://blog.esciencecenter.nl/_astro/the-new-ipcc-assessment-report-stakes-ha-ac0837cb.UuCigevE_1Jti88.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@karsten_wuerth&quot;&gt;Karsten Würth&lt;/a&gt; at &lt;a href=&quot;https://unsplash.com&quot;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, we get to the aspect of disseminating the AR6 message to a broad audience. When you navigate to the IPCC web page to look at the AR6 conclusions yourself, you may quickly find yourself lost in the scientific jargon and formal language. AR6 is targeted at researchers and policy makers, but its implications are so far-reaching that it should be addressing our society as a whole. The aim of the H2020 project &lt;a href=&quot;https://climatestorylines.eu/&quot;&gt;RECEIPT&lt;/a&gt; is to assess Europe’s vulnerability to climate risks and represent these risks in the form of storylines. Sometimes it’s not feasible to perform a full statistical analysis of climate impacts on a complex system. Or even so, it may be that stakeholders are more interested in a few representative (or extreme) datapoints to assess their vulnerability, and that is where storylines enter the picture. By showing the chain of events caused by warming climate and intensifying extreme weather, we hope to better convey potential agricultural, socio-economic and infrastructural hazards. Here, the eScience Center plays a leading role in visualizing these storylines in an interactive &lt;a href=&quot;https://www.climateimpactstories.eu/?sector=agriculture&amp;#x26;story=1&quot;&gt;web-based environment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are just a handful of examples of where the eScience Center has in some way contributed to AR6. We have been involved in many more projects in climate and weather, detecting the &lt;a href=&quot;https://www.research-software.nl/projects/1349&quot;&gt;occurrence of climate tipping points&lt;/a&gt;, improving the predictability of climate in Europe (EUCP) and the Northern Atlantic (&lt;a href=&quot;https://blue-action.eu/&quot;&gt;Blue Action&lt;/a&gt;), or estimating the likelihood and severity of &lt;a href=&quot;https://climate.copernicus.eu/prototype-extreme-events-and-attribution-service&quot;&gt;extreme heat and flooding events&lt;/a&gt;. The common ingredient connecting these research projects is always climate change. While our opponent in the ring is gaining strength, we use science and computing to improve our ability to predict his moves and better brace for impact of the punches. The global effort to reduce emissions will be crucial to limit those impacts and hopefully prolong the battle until a jury decision, to be made by future generations.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/bouwe-andela-msc/&quot;&gt;&lt;em&gt;Bouwe Andela&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-maaike-de-jong/&quot;&gt;&lt;em&gt;Maaike de Jong&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/team/jesus-garcia-gonzalez-msc/&quot;&gt;&lt;em&gt;Jesus Garcia Gonzalez&lt;/em&gt;&lt;/a&gt;&lt;/em&gt; and *&lt;a href=&quot;https://www.esciencecenter.nl/team/dr-yifat-dzigan/&quot;&gt;&lt;em&gt;Yifat Dzigan&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/the-new-ipcc-assessment-report-stakes-ha-64226777.CsBCGuG7.jpeg" medium="image"/><author>Gijs van den Oord</author></item><item><title>cffinit: NOW is the time to get more recognition for your software!</title><link>https://blog.esciencecenter.nl/posts/2021-12-03---cffinit-now-is-the-time-to-get-more-recognition-for-your-sof</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-12-03---cffinit-now-is-the-time-to-get-more-recognition-for-your-sof</guid><description>&lt;p&gt;***Creating software citation files using cffinit&lt;br&gt;
***by &lt;a href=&quot;https://orcid.org/0000-0003-4451-281X&quot;&gt;Abel S. Siqueira&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;Faruk Diblen&lt;/a&gt; (&lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Image of cinema with many people watching a screen. Instead of a film, the screen shows the recognition image from Scriberia.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VMyjOtrq1IOnHncO-1e5ef4de.CVjb6NdK_Z6jzNu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Modified photo of a cinema by Jake Hills on Unsplash &lt;a href=&quot;https://unsplash.com/photos/23LET4Hxj%5C_U&quot;&gt;https://unsplash.com/photos/23LET4Hxj\_U&lt;/a&gt;, and the image created by Scriberia for The Turing Way community and is used under a CC-BY licence. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5706310&quot;&gt;https://doi.org/10.5281/zenodo.5706310&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s think about your favorite movie. What is so good about it? The story? The animations? Sound effects? Maybe you only like the actor or actress? There must be something special about the movie that makes you feel different.&lt;/p&gt;
&lt;p&gt;We move on to our next question: do you know of those involved in making your favourite movie? You may know the director and the main actor or actress, but what about the others? For example, do you know the artist who composed the soundtracks? Do you know the person who spent endless hours editing the movie? What about costume and make-up? We often refer to movies as &lt;em&gt;‘the movie director X directed’&lt;/em&gt; or &lt;em&gt;‘the movie with Y in it’&lt;/em&gt;. Although a lot of people work in movie production, only a few people get credit and share the fame. But what would happen if the most striking scene wouldn’t have a soundtrack or visual effects?&lt;/p&gt;
&lt;p&gt;We have a similar story to modern research. In many research fields today, doing research without software is impossible. Researchers find an interesting problem, they devote their time to finding the answer and they rarely actually do it alone. Most of the time, they collaborate with many other people. For example, researchers need software that can make smart decisions (like an AI algorithm) or process a huge amount of data in a very efficient way. Finally, they get their research article published and are announced as the owner of the work. &lt;em&gt;But wait!&lt;/em&gt; What happened to the people who developed the software? Are they included in the paper? Did they receive credit for the software they developed? In the best scenario, the software developers spent time creating a software paper and published it in a specialized journal. If there is no publication about the software, the developers don’t usually receive credit or are only added to the acknowledgement section.&lt;/p&gt;
&lt;h2 id=&quot;citation-file-format&quot;&gt;Citation File Format&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Recognition image from Scriberia. A banner with Recognition written on it appears above software developers and researchers standing on pillars. Software citation helps developers pillar to go to higher level, represented by an arrow.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_SCmONGUG4gHQkhqA-42229c69.Di2jUtWU_kiueY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This image was created by Scriberia for The Turing Way community and is used under a CC-BY licence. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5706310&quot;&gt;https://doi.org/10.5281/zenodo.5706310&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was a big issue until a few research software developers, from the Netherlands eScience Center and the German Aerospace Center (DLR) introduced the idea of &lt;a href=&quot;https://citation-file-format.github.io/&quot;&gt;Citation File Format&lt;/a&gt; [1]. The Citation File Format helps you add machine-readable metadata for software or datasets. After adoption by GitHub, Zenodo, GitLab, Zotero, and JabRef, we believe it will be a standard format in the near future. You can read more about the story &lt;a href=&quot;https://www.esciencecenter.nl/news/code-citation-was-made-possible-by-research-software-engineers-in-germany-and-the-netherlands/&quot;&gt;here&lt;/a&gt;. Thanks to &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files&quot;&gt;GitHub’s recent feature&lt;/a&gt;, if you have a CITATION.cff in your GitHub repository, your software can be cited correctly and easily. &lt;strong&gt;Yaaay for recognition!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;cffinit-a-tool-to-generate-citationcff-files&quot;&gt;cffinit: a tool to generate CITATION.cff files&lt;/h2&gt;
&lt;p&gt;To support the growing adoption of the Citation File Format, &lt;strong&gt;there is now a dedicated tool to create these files from scratch&lt;/strong&gt;: &lt;a href=&quot;https://research-software.nl/software/cffinit&quot;&gt;cffinit&lt;/a&gt; [2]. cffinit is a web application that helps you create a CITATION.cff file. The application provides guidance for each field of the CFF schema and does the validation automatically. When there are issues, cffinit will provide visual feedback on relevant fields. The cffinit has a few advantages compared to manual editing such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no need for installing extra tools such as conversion and validation tools;&lt;/li&gt;
&lt;li&gt;no need for further validation;&lt;/li&gt;
&lt;li&gt;guidance for each field;&lt;/li&gt;
&lt;li&gt;visual feedback to indicate issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recently, the Netherlands eScience Center has released version 2.0.0 of the tool. This version handles the most up-to-date Citation File Format specification (1.2.0), and can help you easily create your CITATION.cff file.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A cat looks at a computer screen where the landing page of cffinit is shown.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_J2ZZyZSLxMFGZQGR-0312c8a3.DfvPnZ5S_Z1urK9d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Modified photo of Tim Mossholder on Unsplash &lt;a href=&quot;https://unsplash.com/photos/gdsp6wNn7cM&quot;&gt;https://unsplash.com/photos/gdsp6wNn7cM&lt;/a&gt;, with landing the page of cffinit v2.0.0&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center also took part in The Turing Way November 2021 sprint and created a section about &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cff.html&quot;&gt;software citation with CITATION.cff&lt;/a&gt; with an overview of all this information. In addition, we have created a tutorial on how to &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cffinit.html&quot;&gt;create a CITATION.cff using cffinit&lt;/a&gt; to help you get your software to the next level of recognition. Instead of copy-pasting all of it here, we summarize a few of the points in The Turing Way and recommend that you follow the tutorial.&lt;/p&gt;
&lt;h2 id=&quot;steps-to-make-your-software-citable-with-cffinit&quot;&gt;Steps to Make Your Software Citable with cffinit&lt;/h2&gt;
&lt;p&gt;To make your software citable, you only need to follow the two steps below:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1. Create a CITATION.cff File:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use &lt;a href=&quot;https://citation-file-format.github.io/cff-initializer-javascript/#/&quot;&gt;cffinit&lt;/a&gt; to create a CITATION.cff file. For more details on using cffinit see &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cffinit.html&quot;&gt;the tutorial on The Turing Way’s website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2. Add Your CITATION.cff to a Public Code Repository:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After creating a valid CITATION.cff file, you will need to add it to the root of your code or data repository so that it can be easily found and cited.&lt;/p&gt;
&lt;h2 id=&quot;updating-your-citationcff-file&quot;&gt;Updating your CITATION.cff file&lt;/h2&gt;
&lt;p&gt;When you need to update your CITATION.cff file, for example, to add an author or to change the information about releases, you will need to edit the file manually. It is recommended to update your CITATION.cff file before making a software release.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Spoiler: we are working on adding this feature to cffinit.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-cite-using-citationcff&quot;&gt;How to Cite Using CITATION.cff&lt;/h2&gt;
&lt;p&gt;If you have found software or datasets that contain a CITATION.cff, there are a few ways to obtain the reference information to cite in your publication.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use one of the tools, such as the &lt;a href=&quot;https://github.com/citation-file-format/cff-converter-python&quot;&gt;cffconvert&lt;/a&gt; command-line program, to convert your CITATION.cff file to one of the &lt;a href=&quot;https://github.com/citation-file-format/cff-converter-python#supported-output-formats&quot;&gt;supported formats&lt;/a&gt;, such as APA, BibTeX or EndNote.&lt;/li&gt;
&lt;li&gt;Alternatively, if the software or datasets you want to cite are available on GitHub, you can use GitHub’s interface to copy the reference in either APA or BibTeX formats by clicking the “Cite this repository” button. See the green area in the image below for an example.
&lt;img alt=&quot;GitHub repository with “Cite this repository” button clicked and popup showing the formatted citation information.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1199&quot; height=&quot;793&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Mt6W7VkzjkCLICvz-118ee885.6MdF7Upf_Z1B4YUv.webp&quot; srcset=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“Cite this repository” automatically converts the CITATION.cff file to APA’s and BibTeX’s format.&lt;/p&gt;
&lt;p&gt;Note that the “Cite this repository” button only appears when there is a CITATION.cff file in the repository.&lt;/p&gt;
&lt;p&gt;For more details on software citation on GitHub, please see &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files&quot;&gt;GitHub’s guide on software citation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;[1] Druskat, S., Spaaks, J. H., Chue Hong, N., Haines, R., Baker, J., Bliven, S., Willighagen, E., Pérez-Suárez, D., &amp;#x26; Konovalov, A. (2021). Citation File Format (Version 1.2.0) [Computer software]. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5171937&quot;&gt;https://doi.org/10.5281/zenodo.5171937&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] Spaaks, J. H., Verhoeven, S., Diblen, F., Druskat, S., Soares Siqueira, A., &amp;#x26; Garcia Gonzalez, J. (2021). cffinit (Version 2.0.0) [Computer software]. &lt;a href=&quot;https://github.com/citation-file-format/cff-initializer-javascript&quot;&gt;https://github.com/citation-file-format/cff-initializer-javascript&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-can-you-help&quot;&gt;How can you help?&lt;/h2&gt;
&lt;p&gt;You can help us in many ways. The first and easiest would be creating a CITATION.cff file for your software. If you encounter any issues or if you have suggestions, you can create tickets on our &lt;a href=&quot;https://github.com/citation-file-format/cff-initializer-javascript&quot;&gt;GitHub repository&lt;/a&gt;. Finally, you can contribute to the code and help us make it even better.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;cffinit 2.0 was developed by &lt;a href=&quot;https://www.esciencecenter.nl/team/abel-soares-siqueira/&quot;&gt;Abel S. Siqueira&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/faruk-diblen-msc/&quot;&gt;Faruk Diblen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jesus-garcia-gonzalez-msc/&quot;&gt;Jesus Garcia González&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;Jurriaan H. Spaaks&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;. We thank &lt;a href=&quot;https://sdruskat.net/&quot;&gt;Stephan Druskat&lt;/a&gt; for the very useful feedback during the development of the tool and also our proofreaders &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;Tom Bakker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have suggestions or questions, please feel free to reach us at generalization a-t esciencecenter.nl.&lt;/p&gt;</description><pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;***Creating software citation files using cffinit&lt;br&gt;
***by &lt;a href=&quot;https://orcid.org/0000-0003-4451-281X&quot;&gt;Abel S. Siqueira&lt;/a&gt; and &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;Faruk Diblen&lt;/a&gt; (&lt;a href=&quot;https://www.esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Image of cinema with many people watching a screen. Instead of a film, the screen shows the recognition image from Scriberia.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VMyjOtrq1IOnHncO-1e5ef4de.CVjb6NdK_Z6jzNu.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Modified photo of a cinema by Jake Hills on Unsplash &lt;a href=&quot;https://unsplash.com/photos/23LET4Hxj%5C_U&quot;&gt;https://unsplash.com/photos/23LET4Hxj\_U&lt;/a&gt;, and the image created by Scriberia for The Turing Way community and is used under a CC-BY licence. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5706310&quot;&gt;https://doi.org/10.5281/zenodo.5706310&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s think about your favorite movie. What is so good about it? The story? The animations? Sound effects? Maybe you only like the actor or actress? There must be something special about the movie that makes you feel different.&lt;/p&gt;
&lt;p&gt;We move on to our next question: do you know of those involved in making your favourite movie? You may know the director and the main actor or actress, but what about the others? For example, do you know the artist who composed the soundtracks? Do you know the person who spent endless hours editing the movie? What about costume and make-up? We often refer to movies as &lt;em&gt;‘the movie director X directed’&lt;/em&gt; or &lt;em&gt;‘the movie with Y in it’&lt;/em&gt;. Although a lot of people work in movie production, only a few people get credit and share the fame. But what would happen if the most striking scene wouldn’t have a soundtrack or visual effects?&lt;/p&gt;
&lt;p&gt;We have a similar story to modern research. In many research fields today, doing research without software is impossible. Researchers find an interesting problem, they devote their time to finding the answer and they rarely actually do it alone. Most of the time, they collaborate with many other people. For example, researchers need software that can make smart decisions (like an AI algorithm) or process a huge amount of data in a very efficient way. Finally, they get their research article published and are announced as the owner of the work. &lt;em&gt;But wait!&lt;/em&gt; What happened to the people who developed the software? Are they included in the paper? Did they receive credit for the software they developed? In the best scenario, the software developers spent time creating a software paper and published it in a specialized journal. If there is no publication about the software, the developers don’t usually receive credit or are only added to the acknowledgement section.&lt;/p&gt;
&lt;h2 id=&quot;citation-file-format&quot;&gt;Citation File Format&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Recognition image from Scriberia. A banner with Recognition written on it appears above software developers and researchers standing on pillars. Software citation helps developers pillar to go to higher level, represented by an arrow.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_SCmONGUG4gHQkhqA-42229c69.Di2jUtWU_kiueY.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This image was created by Scriberia for The Turing Way community and is used under a CC-BY licence. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5706310&quot;&gt;https://doi.org/10.5281/zenodo.5706310&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was a big issue until a few research software developers, from the Netherlands eScience Center and the German Aerospace Center (DLR) introduced the idea of &lt;a href=&quot;https://citation-file-format.github.io/&quot;&gt;Citation File Format&lt;/a&gt; [1]. The Citation File Format helps you add machine-readable metadata for software or datasets. After adoption by GitHub, Zenodo, GitLab, Zotero, and JabRef, we believe it will be a standard format in the near future. You can read more about the story &lt;a href=&quot;https://www.esciencecenter.nl/news/code-citation-was-made-possible-by-research-software-engineers-in-germany-and-the-netherlands/&quot;&gt;here&lt;/a&gt;. Thanks to &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files&quot;&gt;GitHub’s recent feature&lt;/a&gt;, if you have a CITATION.cff in your GitHub repository, your software can be cited correctly and easily. &lt;strong&gt;Yaaay for recognition!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;cffinit-a-tool-to-generate-citationcff-files&quot;&gt;cffinit: a tool to generate CITATION.cff files&lt;/h2&gt;
&lt;p&gt;To support the growing adoption of the Citation File Format, &lt;strong&gt;there is now a dedicated tool to create these files from scratch&lt;/strong&gt;: &lt;a href=&quot;https://research-software.nl/software/cffinit&quot;&gt;cffinit&lt;/a&gt; [2]. cffinit is a web application that helps you create a CITATION.cff file. The application provides guidance for each field of the CFF schema and does the validation automatically. When there are issues, cffinit will provide visual feedback on relevant fields. The cffinit has a few advantages compared to manual editing such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no need for installing extra tools such as conversion and validation tools;&lt;/li&gt;
&lt;li&gt;no need for further validation;&lt;/li&gt;
&lt;li&gt;guidance for each field;&lt;/li&gt;
&lt;li&gt;visual feedback to indicate issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recently, the Netherlands eScience Center has released version 2.0.0 of the tool. This version handles the most up-to-date Citation File Format specification (1.2.0), and can help you easily create your CITATION.cff file.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A cat looks at a computer screen where the landing page of cffinit is shown.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_J2ZZyZSLxMFGZQGR-0312c8a3.DfvPnZ5S_Z1urK9d.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Modified photo of Tim Mossholder on Unsplash &lt;a href=&quot;https://unsplash.com/photos/gdsp6wNn7cM&quot;&gt;https://unsplash.com/photos/gdsp6wNn7cM&lt;/a&gt;, with landing the page of cffinit v2.0.0&lt;/p&gt;
&lt;p&gt;The Netherlands eScience Center also took part in The Turing Way November 2021 sprint and created a section about &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cff.html&quot;&gt;software citation with CITATION.cff&lt;/a&gt; with an overview of all this information. In addition, we have created a tutorial on how to &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cffinit.html&quot;&gt;create a CITATION.cff using cffinit&lt;/a&gt; to help you get your software to the next level of recognition. Instead of copy-pasting all of it here, we summarize a few of the points in The Turing Way and recommend that you follow the tutorial.&lt;/p&gt;
&lt;h2 id=&quot;steps-to-make-your-software-citable-with-cffinit&quot;&gt;Steps to Make Your Software Citable with cffinit&lt;/h2&gt;
&lt;p&gt;To make your software citable, you only need to follow the two steps below:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1. Create a CITATION.cff File:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use &lt;a href=&quot;https://citation-file-format.github.io/cff-initializer-javascript/#/&quot;&gt;cffinit&lt;/a&gt; to create a CITATION.cff file. For more details on using cffinit see &lt;a href=&quot;https://the-turing-way.netlify.app/communication/citable/citable-cffinit.html&quot;&gt;the tutorial on The Turing Way’s website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2. Add Your CITATION.cff to a Public Code Repository:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After creating a valid CITATION.cff file, you will need to add it to the root of your code or data repository so that it can be easily found and cited.&lt;/p&gt;
&lt;h2 id=&quot;updating-your-citationcff-file&quot;&gt;Updating your CITATION.cff file&lt;/h2&gt;
&lt;p&gt;When you need to update your CITATION.cff file, for example, to add an author or to change the information about releases, you will need to edit the file manually. It is recommended to update your CITATION.cff file before making a software release.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Spoiler: we are working on adding this feature to cffinit.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-cite-using-citationcff&quot;&gt;How to Cite Using CITATION.cff&lt;/h2&gt;
&lt;p&gt;If you have found software or datasets that contain a CITATION.cff, there are a few ways to obtain the reference information to cite in your publication.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use one of the tools, such as the &lt;a href=&quot;https://github.com/citation-file-format/cff-converter-python&quot;&gt;cffconvert&lt;/a&gt; command-line program, to convert your CITATION.cff file to one of the &lt;a href=&quot;https://github.com/citation-file-format/cff-converter-python#supported-output-formats&quot;&gt;supported formats&lt;/a&gt;, such as APA, BibTeX or EndNote.&lt;/li&gt;
&lt;li&gt;Alternatively, if the software or datasets you want to cite are available on GitHub, you can use GitHub’s interface to copy the reference in either APA or BibTeX formats by clicking the “Cite this repository” button. See the green area in the image below for an example.
&lt;img alt=&quot;GitHub repository with “Cite this repository” button clicked and popup showing the formatted citation information.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1199&quot; height=&quot;793&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_Mt6W7VkzjkCLICvz-118ee885.6MdF7Upf_Z1B4YUv.webp&quot; srcset=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“Cite this repository” automatically converts the CITATION.cff file to APA’s and BibTeX’s format.&lt;/p&gt;
&lt;p&gt;Note that the “Cite this repository” button only appears when there is a CITATION.cff file in the repository.&lt;/p&gt;
&lt;p&gt;For more details on software citation on GitHub, please see &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files&quot;&gt;GitHub’s guide on software citation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;[1] Druskat, S., Spaaks, J. H., Chue Hong, N., Haines, R., Baker, J., Bliven, S., Willighagen, E., Pérez-Suárez, D., &amp;#x26; Konovalov, A. (2021). Citation File Format (Version 1.2.0) [Computer software]. &lt;a href=&quot;https://doi.org/10.5281/zenodo.5171937&quot;&gt;https://doi.org/10.5281/zenodo.5171937&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] Spaaks, J. H., Verhoeven, S., Diblen, F., Druskat, S., Soares Siqueira, A., &amp;#x26; Garcia Gonzalez, J. (2021). cffinit (Version 2.0.0) [Computer software]. &lt;a href=&quot;https://github.com/citation-file-format/cff-initializer-javascript&quot;&gt;https://github.com/citation-file-format/cff-initializer-javascript&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-can-you-help&quot;&gt;How can you help?&lt;/h2&gt;
&lt;p&gt;You can help us in many ways. The first and easiest would be creating a CITATION.cff file for your software. If you encounter any issues or if you have suggestions, you can create tickets on our &lt;a href=&quot;https://github.com/citation-file-format/cff-initializer-javascript&quot;&gt;GitHub repository&lt;/a&gt;. Finally, you can contribute to the code and help us make it even better.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;cffinit 2.0 was developed by &lt;a href=&quot;https://www.esciencecenter.nl/team/abel-soares-siqueira/&quot;&gt;Abel S. Siqueira&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/faruk-diblen-msc/&quot;&gt;Faruk Diblen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jesus-garcia-gonzalez-msc/&quot;&gt;Jesus Garcia González&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/jurriaan-spaaks-msc/&quot;&gt;Jurriaan H. Spaaks&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;. We thank &lt;a href=&quot;https://sdruskat.net/&quot;&gt;Stephan Druskat&lt;/a&gt; for the very useful feedback during the development of the tool and also our proofreaders &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-lieke-de-boer/&quot;&gt;Lieke de Boer&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/veronica-pang/&quot;&gt;Veronica Pang&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-tom-bakker/&quot;&gt;Tom Bakker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have suggestions or questions, please feel free to reach us at generalization a-t esciencecenter.nl.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_SCmONGUG4gHQkhqA-42229c69.Di2jUtWU.webp" medium="image"/><author>Faruk Diblen</author></item><item><title>Kernel Tuner tutorial at Supercomputing 2021</title><link>https://blog.esciencecenter.nl/posts/2021-11-25---kernel-tuner-tutorial-at-supercomputing-2021</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-11-25---kernel-tuner-tutorial-at-supercomputing-2021</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3975&quot; height=&quot;2682&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_msfW7zq3-awfNStVOT-xBQ-893acb07.CWKlucGy_1CWQ3h.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A view of St. Louis from the Gateway Arch. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;November 2021 — Together with my colleagues, Alessio Sclocco, Stijn Heldens, and Floris-Jan Willemsen, we travelled to the latest edition of the &lt;a href=&quot;https://sc21.supercomputing.org/&quot;&gt;Supercomputing conference&lt;/a&gt;, SC21, in St. Louis, USA, to give a tutorial.&lt;/p&gt;
&lt;p&gt;The goal of the tutorial was to teach Supercomputing attendees how to use &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner&quot;&gt;Kernel Tuner&lt;/a&gt;, a tool that is being developed at the Netherlands eScience Center to assist in the development of highly-optimized applications for Graphics Processing Units (or GPUs). These GPUs form the primary source of compute power in many of today’s supercomputers. However, optimizing applications to run efficiently on GPUs can be challenging, and that’s where Kernel Tuner comes into play.&lt;/p&gt;
&lt;p&gt;The tutorial was divided into four sections, each consisting of a short presentation followed by a hands-on session, in which the attendees get to practice using the tool on some of the example codes that we provided.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1344&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ModR0KTUHXWxS-IlCs0f_A-4f639c67.DDZWFrXV_21nUu7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dr. Ben van Werkhoven presenting at the Kernel Tuner tutorial at SC21. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;The first session explained the problem that Kernel Tuner is aiming to solve, namely the problem that creating GPU applications with optimal performance is a bit like trying to find a needle in a haystack. This is because the developer has a great number of choices to make when creating a GPU application. These choices won’t affect the outcome of the program, but they can have a dramatic impact on the time it takes to perform the computations. All implementation choices combined create a huge program design space of potential implementations that all compute the same thing, but in different ways. Using several examples, I explained that while using auto-tuning to optimize GPU applications may be a complex process, it can also be really rewarding when you find those few configurations that outperform all others by a large margin.&lt;/p&gt;
&lt;p&gt;For the hands-on sessions, we made use of &lt;a href=&quot;https://colab.research.google.com/?utm_source=scs-index&quot;&gt;Google Colab&lt;/a&gt;, which allows anyone with a Google account to run Jupyter notebooks on Google’s cloud services. There are several providers of similar services, but the great thing about Colab is that you can get a virtual machine with a GPU, which is exactly what we need to get started with tuning GPU kernels. Colab turned out to be a great choice for the tutorial, because it can be accessed from a browser without the need for participants to install any software locally, nor do they have to be able to access their own GPU server from the conference network. Because Kernel Tuner is a Python-based tool, the participants could use it right away inside the Jupyter notebook environment and get started on the exercises.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1048&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_IPaVLwyMntpH4XpMhNToRw-4da126f0.BF6MRdho_FYNCg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dr. Alessio Sclocco wrapping up the first hands-on session of the tutorial. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;During the hands-on sessions, the attendees read about the exercises in the notebook at hand and attempt to solve small example problems. All four of us, including Stijn and Floris-Jan, were busy with answering questions from the attendees regarding the hands-on exercises.&lt;/p&gt;
&lt;p&gt;The second session focused on how to start using Kernel Tuner to optimize existing GPU functions, or kernels, and how to correctly supply Kernel Tuner with the set of possible values for application parameters such as the number of threads per block and the number of thread blocks. Alessio introduced the concept of user-defined metrics that allow the user to instruct Kernel Tuner to calculate certain metrics that are relevant for the application, while it is being benchmarked on the GPU.&lt;/p&gt;
&lt;p&gt;The third and fourth sessions introduced more complex concepts and features of the tool, including how to verify the output of all program variants during tuning and how to integrate auto-tuned GPU kernels into larger applications.&lt;/p&gt;
&lt;p&gt;The response from the audience was really great. The room was as full as the COVID-19 measures would allow. The conference organizers even had to arrange for extra tables to allow all attendees to actively participate. During the lectures and hands-on sessions, we received many in-depth questions about the inner workings of Kernel Tuner and GPU code optimization techniques. We are very grateful for the opportunity to present our work at the Supercomputing conference and we look forward to organizing more tutorials on Kernel Tuner in the coming years.&lt;/p&gt;
&lt;p&gt;The rest of the week, we enjoyed the Supercomputing conference where Floris-Jan Willemsen also presented his paper titled “Bayesian Optimization for auto-tuning GPU kernels” at the &lt;a href=&quot;https://www.dcs.warwick.ac.uk/pmbs/pmbs/PMBS/Welcome.html&quot;&gt;Performance Modeling, Benchmarking and Simulation of High Performance Computer Systems (PMBS)&lt;/a&gt; workshop.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;961&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_GVZ3jeEm-_QWClVazkrQ2g-684ffc76.DsIEuK6q_Z1VG2Gw.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A view of St. Louis and the Gateway Arch from across the Mississippi river. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;In case this blogpost has made you curious about the Kernel Tuner tutorial, we have some great news for you since all the tutorial materials, including the notebooks for the hands-on sessions, &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner_tutorial&quot;&gt;are freely available online here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To find out more about Kernel Tuner, please see the &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner&quot;&gt;Kernel Tuner GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Funding acknowledgements: The Kernel Tuner tutorial has been made possible by the CORTEX and ESiWACE2 projects. The CORTEX project has received funding from the Dutch Research Council (NWO) in the framework of the NWA-ORC Call (file number NWA.1160.18.316). ESiWACE2 has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 823988.&lt;/p&gt;</description><pubDate>Thu, 25 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3975&quot; height=&quot;2682&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_msfW7zq3-awfNStVOT-xBQ-893acb07.CWKlucGy_1CWQ3h.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A view of St. Louis from the Gateway Arch. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;November 2021 — Together with my colleagues, Alessio Sclocco, Stijn Heldens, and Floris-Jan Willemsen, we travelled to the latest edition of the &lt;a href=&quot;https://sc21.supercomputing.org/&quot;&gt;Supercomputing conference&lt;/a&gt;, SC21, in St. Louis, USA, to give a tutorial.&lt;/p&gt;
&lt;p&gt;The goal of the tutorial was to teach Supercomputing attendees how to use &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner&quot;&gt;Kernel Tuner&lt;/a&gt;, a tool that is being developed at the Netherlands eScience Center to assist in the development of highly-optimized applications for Graphics Processing Units (or GPUs). These GPUs form the primary source of compute power in many of today’s supercomputers. However, optimizing applications to run efficiently on GPUs can be challenging, and that’s where Kernel Tuner comes into play.&lt;/p&gt;
&lt;p&gt;The tutorial was divided into four sections, each consisting of a short presentation followed by a hands-on session, in which the attendees get to practice using the tool on some of the example codes that we provided.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1344&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ModR0KTUHXWxS-IlCs0f_A-4f639c67.DDZWFrXV_21nUu7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dr. Ben van Werkhoven presenting at the Kernel Tuner tutorial at SC21. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;The first session explained the problem that Kernel Tuner is aiming to solve, namely the problem that creating GPU applications with optimal performance is a bit like trying to find a needle in a haystack. This is because the developer has a great number of choices to make when creating a GPU application. These choices won’t affect the outcome of the program, but they can have a dramatic impact on the time it takes to perform the computations. All implementation choices combined create a huge program design space of potential implementations that all compute the same thing, but in different ways. Using several examples, I explained that while using auto-tuning to optimize GPU applications may be a complex process, it can also be really rewarding when you find those few configurations that outperform all others by a large margin.&lt;/p&gt;
&lt;p&gt;For the hands-on sessions, we made use of &lt;a href=&quot;https://colab.research.google.com/?utm_source=scs-index&quot;&gt;Google Colab&lt;/a&gt;, which allows anyone with a Google account to run Jupyter notebooks on Google’s cloud services. There are several providers of similar services, but the great thing about Colab is that you can get a virtual machine with a GPU, which is exactly what we need to get started with tuning GPU kernels. Colab turned out to be a great choice for the tutorial, because it can be accessed from a browser without the need for participants to install any software locally, nor do they have to be able to access their own GPU server from the conference network. Because Kernel Tuner is a Python-based tool, the participants could use it right away inside the Jupyter notebook environment and get started on the exercises.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1048&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_IPaVLwyMntpH4XpMhNToRw-4da126f0.BF6MRdho_FYNCg.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Dr. Alessio Sclocco wrapping up the first hands-on session of the tutorial. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;During the hands-on sessions, the attendees read about the exercises in the notebook at hand and attempt to solve small example problems. All four of us, including Stijn and Floris-Jan, were busy with answering questions from the attendees regarding the hands-on exercises.&lt;/p&gt;
&lt;p&gt;The second session focused on how to start using Kernel Tuner to optimize existing GPU functions, or kernels, and how to correctly supply Kernel Tuner with the set of possible values for application parameters such as the number of threads per block and the number of thread blocks. Alessio introduced the concept of user-defined metrics that allow the user to instruct Kernel Tuner to calculate certain metrics that are relevant for the application, while it is being benchmarked on the GPU.&lt;/p&gt;
&lt;p&gt;The third and fourth sessions introduced more complex concepts and features of the tool, including how to verify the output of all program variants during tuning and how to integrate auto-tuned GPU kernels into larger applications.&lt;/p&gt;
&lt;p&gt;The response from the audience was really great. The room was as full as the COVID-19 measures would allow. The conference organizers even had to arrange for extra tables to allow all attendees to actively participate. During the lectures and hands-on sessions, we received many in-depth questions about the inner workings of Kernel Tuner and GPU code optimization techniques. We are very grateful for the opportunity to present our work at the Supercomputing conference and we look forward to organizing more tutorials on Kernel Tuner in the coming years.&lt;/p&gt;
&lt;p&gt;The rest of the week, we enjoyed the Supercomputing conference where Floris-Jan Willemsen also presented his paper titled “Bayesian Optimization for auto-tuning GPU kernels” at the &lt;a href=&quot;https://www.dcs.warwick.ac.uk/pmbs/pmbs/PMBS/Welcome.html&quot;&gt;Performance Modeling, Benchmarking and Simulation of High Performance Computer Systems (PMBS)&lt;/a&gt; workshop.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;961&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_GVZ3jeEm-_QWClVazkrQ2g-684ffc76.DsIEuK6q_Z1VG2Gw.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A view of St. Louis and the Gateway Arch from across the Mississippi river. Photo by Floris-Jan Willemsen.&lt;/p&gt;
&lt;p&gt;In case this blogpost has made you curious about the Kernel Tuner tutorial, we have some great news for you since all the tutorial materials, including the notebooks for the hands-on sessions, &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner_tutorial&quot;&gt;are freely available online here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To find out more about Kernel Tuner, please see the &lt;a href=&quot;https://github.com/benvanwerkhoven/kernel_tuner&quot;&gt;Kernel Tuner GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Funding acknowledgements: The Kernel Tuner tutorial has been made possible by the CORTEX and ESiWACE2 projects. The CORTEX project has received funding from the Dutch Research Council (NWO) in the framework of the NWA-ORC Call (file number NWA.1160.18.316). ESiWACE2 has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 823988.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_ModR0KTUHXWxS-IlCs0f_A-4f639c67.DDZWFrXV.jpeg" medium="image"/><author>Ben van Werkhoven</author></item><item><title>Combining ZeroMQ &amp;amp; POSIX signals</title><link>https://blog.esciencecenter.nl/posts/2021-11-16---combining-zeromq-amp-posix-signals</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-11-16---combining-zeromq-amp-posix-signals</guid><description>&lt;h2 id=&quot;use-ppoll-to-handle-eintr-once-and-for-all&quot;&gt;Use ppoll to handle EINTR once and for all&lt;/h2&gt;
&lt;p&gt;Eventually, I found &lt;a href=&quot;http://250bpm.com/blog:12&quot;&gt;this article on EINTR in ZeroMQ&lt;/a&gt; by Martin Sustrik (ZeroMQ creator) himself. More precisely, in the comment section &lt;a href=&quot;http://250bpm.com/blog:12/comments/show#post-1608507&quot;&gt;Ambroz Bizjak suggested a solution&lt;/a&gt; to my problem which after some discussion even Sustrik seemed to be unaware of. The solution wasn’t completely fleshed out in the comments, so there was still some filling out for me to do. Luckily for you, you won’t have to repeat this exercise.&lt;/p&gt;
&lt;p&gt;The solution is that when going into the blocking ZeroMQ calls, you temporarily block the POSIX signals you want to listen for; &lt;code&gt;SIGTERM&lt;/code&gt; in our case. This can be done using &lt;code&gt;sigprocmask&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, instead of using your regular blocking ZeroMQ call, you use &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt; to wait for something to happen on your sockets and your signal queue.** Because, as it turns out, when you temporarily block signals using &lt;code&gt;sigprocmask&lt;/code&gt;, they are put in a queue by the OS. You can then handle them at your earliest convenience.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;pselect&lt;/code&gt; and &lt;code&gt;ppoll&lt;/code&gt; functions can monitor lists of sockets &lt;strong&gt;and&lt;/strong&gt; you can give them a &lt;strong&gt;signal mask&lt;/strong&gt; like the one you gave &lt;code&gt;sigprocmask&lt;/code&gt;, but then without the signal that you specifically wanted to block outside of the &lt;code&gt;pselect&lt;/code&gt; / &lt;code&gt;ppoll&lt;/code&gt; call. This will make &lt;code&gt;pselect&lt;/code&gt; and &lt;code&gt;ppoll&lt;/code&gt; listen to those signals that you blocked earlier. When a signal came in (or a socket is ready for reading/writing) they will return. If you put the flag check after &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt;, the signal will always be handled properly.&lt;/p&gt;
&lt;p&gt;One other critical modification is that in this case you should no longer use blocking ZeroMQ calls. This has also become unnecessary, because you already checked whether some data is incoming on the socket using &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Finally, note that also right after you blocked the signal with &lt;code&gt;sigprocmask&lt;/code&gt;, you should put one additional check for the signal flag, because the signal may yet have triggered somewhere just before you blocked it.&lt;/p&gt;
&lt;p&gt;All in all, the code would then become something like that of Ambroz Bizjak:&lt;/p&gt;
&lt;p&gt;set file descriptor to non-blocking;&lt;strong&gt;sigprocmask&lt;/strong&gt;() to block SIGINT;&lt;strong&gt;if (stop&lt;/strong&gt;) { // handle it }&lt;strong&gt;while (true) {
pselect() with sigmask argument which doesn’t block SIGINT;&lt;/strong&gt;**  if (stop**) { // handle it }**  recv();
}
sigprocmask(old) to put back the old mask in use before we replaced it;&lt;/p&gt;
&lt;h2 id=&quot;integrating-into-zeromq&quot;&gt;Integrating into ZeroMQ&lt;/h2&gt;
&lt;p&gt;This is great in theory, but as already mentioned in the reply by Sustrik: this means we would need a &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt; in ZeroMQ. I was originally using &lt;code&gt;zmq::poll&lt;/code&gt;, which internally uses regular POSIX &lt;code&gt;poll&lt;/code&gt;. We can in principle modify this fairly easily to take the additional argument necessary for &lt;code&gt;ppoll&lt;/code&gt;, namely the signal mask.&lt;/p&gt;
&lt;p&gt;However, then we need to decide on how to handle this internally in ZMQ. I cannot do this on my own, but decided to write a first implementation anyway. However, when I started thinking about actually doing this, a few new problems raised their ugly heads.&lt;/p&gt;
&lt;p&gt;The first idea I had was to again use a global flag that can be flipped from the signal handler when a signal is received… At this point I finally realized what Sustrik was talking about when he said we can’t use signal handlers in libraries. First of all: we don’t know which signals the user will want to actually mask. Maybe they want to act on several signals and so will need several global flags. So, long story short: this cannot be done generically inside a &lt;code&gt;zmq::ppoll&lt;/code&gt; or &lt;code&gt;zmq::pselect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So then we only have two possible tools left to let the user know we caught a signal: the return value and the error code.&lt;/p&gt;
&lt;p&gt;The return value is constrained; the API should conform to existing APIs like those of POSIX &lt;code&gt;ppoll&lt;/code&gt; and &lt;code&gt;zmq::poll&lt;/code&gt;. We can only use return values of &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt;, where &lt;code&gt;-1&lt;/code&gt; means an error occurred. So probably the only sensible option is to modify &lt;code&gt;zmq_poll&lt;/code&gt; (now I’m talking about the libzmq implementation; &lt;code&gt;zmq::poll&lt;/code&gt; is merely a C++ wrapper around &lt;code&gt;zmq_poll&lt;/code&gt;) to return &lt;code&gt;-1&lt;/code&gt; and set the &lt;code&gt;errno&lt;/code&gt; to &lt;code&gt;EINTR&lt;/code&gt; when the signal is received.&lt;/p&gt;
&lt;p&gt;So this sounds a bit like we’d be back at square one… Except that this time the &lt;code&gt;ppoll&lt;/code&gt; function would be the only place where the signal is unblocked**, so we know exactly where it will occur and, more importantly, where it will not. Problem solved!&lt;/p&gt;
&lt;p&gt;Now I just had to write it…&lt;/p&gt;
&lt;h2 id=&quot;ppoll-pselect-or-self-pipe&quot;&gt;Ppoll, pselect or self-pipe?&lt;/h2&gt;
&lt;p&gt;After a two week hiatus, I came back, tried to implement &lt;code&gt;zmq_ppoll&lt;/code&gt; by simply copy-pasting &lt;code&gt;zmq_poll&lt;/code&gt; and replacing &lt;code&gt;poll&lt;/code&gt; with &lt;code&gt;ppoll&lt;/code&gt;, but was unpleasantly surprised by the fact that &lt;code&gt;ppoll&lt;/code&gt; apparently doesn’t exist on macOS. &lt;code&gt;[pselect](&amp;#x26;lt;https://stackoverflow.com/a/46047380/1199693&amp;#x26;gt;)&lt;/code&gt; does exist, so we’ll have to go with that.&lt;/p&gt;
&lt;p&gt;Luckily, the &lt;code&gt;zmq_poll&lt;/code&gt; implementation is really flexible, and already includes a &lt;code&gt;select&lt;/code&gt;-based path next to the &lt;code&gt;poll&lt;/code&gt;-based one. We modify that to take a &lt;code&gt;sigmask&lt;/code&gt; and Bob’s your uncle.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-0ca88b1f.CCaf_wTP_M6fsr.webp&quot; srcset=&quot;&quot;&gt;
I’m your uncle! &lt;a href=&quot;https://itkonekt.com/2018/12/17/robert-c-martin-uncle-bob/&quot;&gt;https://itkonekt.com/2018/12/17/robert-c-martin-uncle-bob/&lt;/a&gt;So indeed, let’s try out &lt;code&gt;pselect&lt;/code&gt;. I did have some reservations, because the web is rather full of reports of it not being implemented properly on macOS / FreeBSD… see &lt;a href=&quot;https://stackoverflow.com/questions/14045801/different-pselect-behaviour-on-osx-vs-linux&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://news.ycombinator.com/item?id=12857275&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://news.ycombinator.com/item?id=16321529&quot;&gt;here&lt;/a&gt;… Hopefully, as also reported &lt;a href=&quot;https://news.ycombinator.com/item?id=12904883&quot;&gt;here&lt;/a&gt;, in recent versions this is fixed. It seems like they could have taken inspiration by now from many existing, reportedly correct, implementations, like &lt;a href=&quot;http://lua-users.org/lists/lua-l/2015-01/msg00697.html&quot;&gt;this one&lt;/a&gt;. This does mean our implementation will only be really 100% robust on recent macOS versions, but so be it.&lt;/p&gt;
&lt;p&gt;At this point, under all these doubts about the stability of it all, I almost gave up on &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; to try out the so-called “&lt;a href=&quot;http://cr.yp.to/docs/selfpipe.html&quot;&gt;self-pipe trick&lt;/a&gt;” that is also &lt;a href=&quot;https://lwn.net/Articles/176911/&quot;&gt;floating around&lt;/a&gt; in these discussions. This could be a good alternative in some ways.&lt;/p&gt;
&lt;p&gt;The problem with the self-pipe trick is that you can’t fully implement it in all its gory details in a library. The trick involves sending a byte over a pipe from a signal handler*. As &lt;a href=&quot;http://250bpm.com/blog:12/comments/show#post-1654888&quot;&gt;Sustrik mentions&lt;/a&gt;, we cannot rely on signal handlers at all. We have to assume they can be overridden by users of our libraries. In fact, ROOT might install its own signal handlers, indeed invalidating the entire approach we’d be going for here. Though, in fact, the last signal handler that is set is the one that trumps others. When we only set the &lt;code&gt;SIGTERM&lt;/code&gt; handler when doing all this stuff and then set the handler back to its original value afterwards, we should be safe, except that we might be interfering with other signal handlers, but that will be necessary in most cases anyway, because also the &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; route will at some point need to install a signal handler. The cleaner alternative (when setting signal handlers are really out of the question) is to let the user of your library implement their own self-pipe signal handler. In my opinion, this is way too heavy a burden on the user.&lt;/p&gt;
&lt;p&gt;So in the end, I chose to go with &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt;, because it puts most of the code on the library side and avoids having to setup and maintain an extra pipe. The only thing you need with the &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; option is a simple signal handler and a flag to check. It seems like a simpler and more user-friendly option.&lt;/p&gt;
&lt;p&gt;Whatever you choose, some handling of POSIX signals will be necessary in a robust multi-process application. For instance, if a child process dies for some reason, a &lt;code&gt;SIGCHLD&lt;/code&gt; signal is sent to the parent, which could also interrupt blocking reads, sends and polls (if &lt;code&gt;SIG_IGN&lt;/code&gt; is not set for this signal). These must be handled either by using &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; or by using the self-pipe trick.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;
&lt;p&gt;So, I implemented the &lt;code&gt;zmq::ppoll&lt;/code&gt; via &lt;code&gt;pselect&lt;/code&gt; route. And finally, after a lot of debugging, it seems to be working well!&lt;/p&gt;
&lt;p&gt;Its low level implementation (&lt;code&gt;zmq_ppoll&lt;/code&gt;) depends on many libzmq macros, defines and functions. Trying to build against this creates a giant string of dependency files. The problem with this is that libzmq does not expose all these internal headers, so for the time being I just copy pasted over all the necessary libzmq files. Amazingly, this just seems to work after a few tweaks. My compliments to the libzmq devs for creating such modular code!&lt;/p&gt;
&lt;p&gt;Regarding the few tweaks: there are a lot of precompiler variables which are used to configure the compiled libzmq code. It seems that for macOS, this configuration is perfectly comfortable basing &lt;code&gt;zmq_poll&lt;/code&gt; on &lt;code&gt;poll&lt;/code&gt;. This makes sense, but for our purposes it is really annoying, because we need all the stuff that would be compiled in the case &lt;code&gt;zmq_poll&lt;/code&gt; would be based on &lt;code&gt;select&lt;/code&gt;. A lot of necessary classes and typedefs are therefore not at all fed to the compiler from all the lazily copy-pasted headers and source files.&lt;/p&gt;
&lt;p&gt;This would become an issue if I was to submit all this &lt;code&gt;ppoll&lt;/code&gt; work to libzmq as a pull request. My need for &lt;code&gt;select&lt;/code&gt; would inflate the library a bit. This is a trade-off that the libzmq devs will have to decide on.&lt;/p&gt;
&lt;p&gt;If they don’t see this happening, I can still publish &lt;code&gt;zmq::ppoll&lt;/code&gt; as a separate library. I just need to flip the switch on all the &lt;code&gt;select&lt;/code&gt; vs &lt;code&gt;poll&lt;/code&gt; configured code. This can be done from &lt;code&gt;platform.hpp&lt;/code&gt;. And this is exactly what I’ve done in &lt;a href=&quot;https://github.com/roofit-dev/root/tree/MP_ZeroMQ-new_multiprocess/roofit/roofitZMQ&quot;&gt;the current RooFitZMQ implementation that you can find in this hidden away corner of GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;even-more-details&quot;&gt;Even more details&lt;/h2&gt;
&lt;p&gt;For the really technically interested reader (as if you would be anything else if you’ve reached this far down into the article), some final implementation details that may trip you up (as they did for me):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a &lt;code&gt;volatile sig_atomic_t&lt;/code&gt; value type for any values you set from within a signal handler. Changing other types is undefined behavior. It will usually work, but I guess in some rare cases it may not and you’ll be scrambling for explanations and will never sleep well again, knowing the mysterious bug that has eluded you for years and that you have heard whispered rumors about from your users is still lurking in the shadows.&lt;/li&gt;
&lt;li&gt;Handle errors (exceptions in the C++ case) wisely. That’s the short version, see the rest of this article for the long version.&lt;/li&gt;
&lt;li&gt;Make sure to set both your receives and your sends to non-blocking with the &lt;code&gt;ZMQ_DONTWAIT&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A practical problem with the latter point is that at the beginning of your run, the connections may not have been made between the sockets. This can lead to the non-blocking send to drop out with an EAGAIN error. Now, you may think (like I did): fine, I’ll handle that error and retry the send. However, the same error will occur at the end of your program when you disconnected the other end of your socket on purpose (as I found out the hard way). At this time, you won’t want to retry infinitely, which would hang your program (which happened to me), so just covering up all your sends in retry loops that trigger on EAGAIN will be too coarse a solution (believe me, I tried).&lt;/p&gt;
&lt;p&gt;What I went with in the end is to define a &lt;code&gt;send_flag&lt;/code&gt; in my Messenger class which I pass as the &lt;code&gt;flag&lt;/code&gt; option to all send calls. Initially, &lt;code&gt;send_flag&lt;/code&gt; is zero, so the send calls will block. I then call a &lt;code&gt;test_connections&lt;/code&gt; method and after this completes successfully, I set &lt;code&gt;send_flag&lt;/code&gt; to &lt;code&gt;ZMQ_DONTWAIT&lt;/code&gt;. Now, once the connection drops out, send calls will give the EAGAIN error. But this time, the start-of-the-program cause of EAGAIN is ruled out, so I can assume that the program has ended. I catch the EAGAIN in my event loops and continue the loop when I get an EAGAIN. This means the code will first come across my &lt;code&gt;ppoll&lt;/code&gt; again before it comes back to the send that caused the EAGAIN. Inside &lt;code&gt;ppoll&lt;/code&gt;, it will handle the &lt;code&gt;SIGTERM&lt;/code&gt; signal that I expect has been sent from the master process and the event loop will be exited properly.&lt;/p&gt;
&lt;p&gt;Lol, you thought that would be it, but no, it’s still not that simple (I’m talking to my innocent, naive, past self here). There are still three other reasons EAGAIN could trigger!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calls to receive (&lt;code&gt;recv&lt;/code&gt;) can also trigger an EAGAIN. To distinguish between send and receive EAGAIN triggers, we could throw different typed exceptions (remember, we’re doing C++ here, so every time I’m talking about error codes, what actually happened was a &lt;code&gt;zmq::error_t&lt;/code&gt; type exception was thrown… which also happens to carry along the traditional C style error code). As far as I can tell, the only reason &lt;code&gt;recv&lt;/code&gt; would trigger EAGAIN after a &lt;code&gt;ppoll&lt;/code&gt; (which I now call before every &lt;code&gt;recv&lt;/code&gt; call) is if &lt;code&gt;ppoll&lt;/code&gt; initially gets a read-ready signal for the socket, but the received data does not pass a ZMQ internal checksum test, so the socket becomes unreadable again when you actually try to read from it. In this case, which I hope is rare, things will probably break unless you try really hard to fix them, i.e. send a signal to the sender that something went wrong, or otherwise implementing a really robust messenging protocol. This therefore goes far beyond the scope of just combining ZMQ with POSIX signals and is described very well elsewhere (like in &lt;a href=&quot;http://zguide.zeromq.org/&quot;&gt;the awesome ZMQ guide&lt;/a&gt; I mentioned at the beginning of this article; in case you forgot, which I myself did, because it took me three weeks to get to the end of writing this post).&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;send&lt;/code&gt; call may have two other legitimate reasons for crapping out with EAGAIN. The first is that its receiving end may have hit its “high-water mark”, a ZMQ setting which you can look up in the ZMQ guide or elsewhere.&lt;/li&gt;
&lt;li&gt;The second reason &lt;code&gt;send&lt;/code&gt; could throw an EAGAIN is that the connection may have been severed unexpectedly. In my case, this would mean that in the following &lt;code&gt;ppoll&lt;/code&gt; call, no &lt;code&gt;SIGTERM&lt;/code&gt; signal will be received and so the code will just try to go on, probably hitting the same connection error again and again ad infinitum. This should also be handled properly, but I’m hoping it’s rare enough to not have to worry about it too much. Obviously, I will worry about it for the rest of my waking days. Will probably write another huge blog post about it at some point. Oh well!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We leave the latter problems to be solved as an exercise for the reader.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-b7296cf6.DbAeRZKP_wm8GG.webp&quot; srcset=&quot;&quot;&gt;
The reader.&lt;/p&gt;
&lt;h2 id=&quot;to-be-continued&quot;&gt;To be continued&lt;/h2&gt;
&lt;p&gt;So stay tuned for the release of &lt;code&gt;zmq_ppoll&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update Oct 2021: &lt;em&gt;&lt;code&gt;*zmq_ppoll*&lt;/code&gt;&lt;/em&gt; is now included in &lt;em&gt;&lt;a href=&quot;https://github.com/zeromq/libzmq/pull/4255&quot;&gt;&lt;em&gt;libzmq&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you have any questions or other thoughts, let me know in the comments or on &lt;a href=&quot;https://twitter.com/egpbos&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.reddit.com/r/cpp/comments/f2r1i6/combining_zeromq_posix_signals_use_ppoll_to/&quot;&gt;Reddit&lt;/a&gt;! Having spent so much time on this stuff, I guess sunk cost fallacy demands of me that I spend even more time on it by discussing it with as many people as possible ;) Also, I guess I’m kind of a mental masochist. Figuring out this stuff has been extremely frustrating, but also extremely satisfying. So throw your problems at me, I’m hungry for more!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-e6392eca.0irim351_y5OEb.webp&quot; srcset=&quot;&quot;&gt;
My happy face (not mine, but close enough), thinking about solving even more complex messaging problems.Thanks to [Lourens Veen,] Inti Pelupessy and [Peter Kalverla] for reviewing this article.&lt;/p&gt;</description><pubDate>Tue, 16 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;use-ppoll-to-handle-eintr-once-and-for-all&quot;&gt;Use ppoll to handle EINTR once and for all&lt;/h2&gt;
&lt;p&gt;Eventually, I found &lt;a href=&quot;http://250bpm.com/blog:12&quot;&gt;this article on EINTR in ZeroMQ&lt;/a&gt; by Martin Sustrik (ZeroMQ creator) himself. More precisely, in the comment section &lt;a href=&quot;http://250bpm.com/blog:12/comments/show#post-1608507&quot;&gt;Ambroz Bizjak suggested a solution&lt;/a&gt; to my problem which after some discussion even Sustrik seemed to be unaware of. The solution wasn’t completely fleshed out in the comments, so there was still some filling out for me to do. Luckily for you, you won’t have to repeat this exercise.&lt;/p&gt;
&lt;p&gt;The solution is that when going into the blocking ZeroMQ calls, you temporarily block the POSIX signals you want to listen for; &lt;code&gt;SIGTERM&lt;/code&gt; in our case. This can be done using &lt;code&gt;sigprocmask&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, instead of using your regular blocking ZeroMQ call, you use &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt; to wait for something to happen on your sockets and your signal queue.** Because, as it turns out, when you temporarily block signals using &lt;code&gt;sigprocmask&lt;/code&gt;, they are put in a queue by the OS. You can then handle them at your earliest convenience.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;pselect&lt;/code&gt; and &lt;code&gt;ppoll&lt;/code&gt; functions can monitor lists of sockets &lt;strong&gt;and&lt;/strong&gt; you can give them a &lt;strong&gt;signal mask&lt;/strong&gt; like the one you gave &lt;code&gt;sigprocmask&lt;/code&gt;, but then without the signal that you specifically wanted to block outside of the &lt;code&gt;pselect&lt;/code&gt; / &lt;code&gt;ppoll&lt;/code&gt; call. This will make &lt;code&gt;pselect&lt;/code&gt; and &lt;code&gt;ppoll&lt;/code&gt; listen to those signals that you blocked earlier. When a signal came in (or a socket is ready for reading/writing) they will return. If you put the flag check after &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt;, the signal will always be handled properly.&lt;/p&gt;
&lt;p&gt;One other critical modification is that in this case you should no longer use blocking ZeroMQ calls. This has also become unnecessary, because you already checked whether some data is incoming on the socket using &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Finally, note that also right after you blocked the signal with &lt;code&gt;sigprocmask&lt;/code&gt;, you should put one additional check for the signal flag, because the signal may yet have triggered somewhere just before you blocked it.&lt;/p&gt;
&lt;p&gt;All in all, the code would then become something like that of Ambroz Bizjak:&lt;/p&gt;
&lt;p&gt;set file descriptor to non-blocking;&lt;strong&gt;sigprocmask&lt;/strong&gt;() to block SIGINT;&lt;strong&gt;if (stop&lt;/strong&gt;) { // handle it }&lt;strong&gt;while (true) {
pselect() with sigmask argument which doesn’t block SIGINT;&lt;/strong&gt;**  if (stop**) { // handle it }**  recv();
}
sigprocmask(old) to put back the old mask in use before we replaced it;&lt;/p&gt;
&lt;h2 id=&quot;integrating-into-zeromq&quot;&gt;Integrating into ZeroMQ&lt;/h2&gt;
&lt;p&gt;This is great in theory, but as already mentioned in the reply by Sustrik: this means we would need a &lt;code&gt;pselect&lt;/code&gt; or &lt;code&gt;ppoll&lt;/code&gt; in ZeroMQ. I was originally using &lt;code&gt;zmq::poll&lt;/code&gt;, which internally uses regular POSIX &lt;code&gt;poll&lt;/code&gt;. We can in principle modify this fairly easily to take the additional argument necessary for &lt;code&gt;ppoll&lt;/code&gt;, namely the signal mask.&lt;/p&gt;
&lt;p&gt;However, then we need to decide on how to handle this internally in ZMQ. I cannot do this on my own, but decided to write a first implementation anyway. However, when I started thinking about actually doing this, a few new problems raised their ugly heads.&lt;/p&gt;
&lt;p&gt;The first idea I had was to again use a global flag that can be flipped from the signal handler when a signal is received… At this point I finally realized what Sustrik was talking about when he said we can’t use signal handlers in libraries. First of all: we don’t know which signals the user will want to actually mask. Maybe they want to act on several signals and so will need several global flags. So, long story short: this cannot be done generically inside a &lt;code&gt;zmq::ppoll&lt;/code&gt; or &lt;code&gt;zmq::pselect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So then we only have two possible tools left to let the user know we caught a signal: the return value and the error code.&lt;/p&gt;
&lt;p&gt;The return value is constrained; the API should conform to existing APIs like those of POSIX &lt;code&gt;ppoll&lt;/code&gt; and &lt;code&gt;zmq::poll&lt;/code&gt;. We can only use return values of &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt;, where &lt;code&gt;-1&lt;/code&gt; means an error occurred. So probably the only sensible option is to modify &lt;code&gt;zmq_poll&lt;/code&gt; (now I’m talking about the libzmq implementation; &lt;code&gt;zmq::poll&lt;/code&gt; is merely a C++ wrapper around &lt;code&gt;zmq_poll&lt;/code&gt;) to return &lt;code&gt;-1&lt;/code&gt; and set the &lt;code&gt;errno&lt;/code&gt; to &lt;code&gt;EINTR&lt;/code&gt; when the signal is received.&lt;/p&gt;
&lt;p&gt;So this sounds a bit like we’d be back at square one… Except that this time the &lt;code&gt;ppoll&lt;/code&gt; function would be the only place where the signal is unblocked**, so we know exactly where it will occur and, more importantly, where it will not. Problem solved!&lt;/p&gt;
&lt;p&gt;Now I just had to write it…&lt;/p&gt;
&lt;h2 id=&quot;ppoll-pselect-or-self-pipe&quot;&gt;Ppoll, pselect or self-pipe?&lt;/h2&gt;
&lt;p&gt;After a two week hiatus, I came back, tried to implement &lt;code&gt;zmq_ppoll&lt;/code&gt; by simply copy-pasting &lt;code&gt;zmq_poll&lt;/code&gt; and replacing &lt;code&gt;poll&lt;/code&gt; with &lt;code&gt;ppoll&lt;/code&gt;, but was unpleasantly surprised by the fact that &lt;code&gt;ppoll&lt;/code&gt; apparently doesn’t exist on macOS. &lt;code&gt;[pselect](&amp;#x26;lt;https://stackoverflow.com/a/46047380/1199693&amp;#x26;gt;)&lt;/code&gt; does exist, so we’ll have to go with that.&lt;/p&gt;
&lt;p&gt;Luckily, the &lt;code&gt;zmq_poll&lt;/code&gt; implementation is really flexible, and already includes a &lt;code&gt;select&lt;/code&gt;-based path next to the &lt;code&gt;poll&lt;/code&gt;-based one. We modify that to take a &lt;code&gt;sigmask&lt;/code&gt; and Bob’s your uncle.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-0ca88b1f.CCaf_wTP_M6fsr.webp&quot; srcset=&quot;&quot;&gt;
I’m your uncle! &lt;a href=&quot;https://itkonekt.com/2018/12/17/robert-c-martin-uncle-bob/&quot;&gt;https://itkonekt.com/2018/12/17/robert-c-martin-uncle-bob/&lt;/a&gt;So indeed, let’s try out &lt;code&gt;pselect&lt;/code&gt;. I did have some reservations, because the web is rather full of reports of it not being implemented properly on macOS / FreeBSD… see &lt;a href=&quot;https://stackoverflow.com/questions/14045801/different-pselect-behaviour-on-osx-vs-linux&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://news.ycombinator.com/item?id=12857275&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://news.ycombinator.com/item?id=16321529&quot;&gt;here&lt;/a&gt;… Hopefully, as also reported &lt;a href=&quot;https://news.ycombinator.com/item?id=12904883&quot;&gt;here&lt;/a&gt;, in recent versions this is fixed. It seems like they could have taken inspiration by now from many existing, reportedly correct, implementations, like &lt;a href=&quot;http://lua-users.org/lists/lua-l/2015-01/msg00697.html&quot;&gt;this one&lt;/a&gt;. This does mean our implementation will only be really 100% robust on recent macOS versions, but so be it.&lt;/p&gt;
&lt;p&gt;At this point, under all these doubts about the stability of it all, I almost gave up on &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; to try out the so-called “&lt;a href=&quot;http://cr.yp.to/docs/selfpipe.html&quot;&gt;self-pipe trick&lt;/a&gt;” that is also &lt;a href=&quot;https://lwn.net/Articles/176911/&quot;&gt;floating around&lt;/a&gt; in these discussions. This could be a good alternative in some ways.&lt;/p&gt;
&lt;p&gt;The problem with the self-pipe trick is that you can’t fully implement it in all its gory details in a library. The trick involves sending a byte over a pipe from a signal handler*. As &lt;a href=&quot;http://250bpm.com/blog:12/comments/show#post-1654888&quot;&gt;Sustrik mentions&lt;/a&gt;, we cannot rely on signal handlers at all. We have to assume they can be overridden by users of our libraries. In fact, ROOT might install its own signal handlers, indeed invalidating the entire approach we’d be going for here. Though, in fact, the last signal handler that is set is the one that trumps others. When we only set the &lt;code&gt;SIGTERM&lt;/code&gt; handler when doing all this stuff and then set the handler back to its original value afterwards, we should be safe, except that we might be interfering with other signal handlers, but that will be necessary in most cases anyway, because also the &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; route will at some point need to install a signal handler. The cleaner alternative (when setting signal handlers are really out of the question) is to let the user of your library implement their own self-pipe signal handler. In my opinion, this is way too heavy a burden on the user.&lt;/p&gt;
&lt;p&gt;So in the end, I chose to go with &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt;, because it puts most of the code on the library side and avoids having to setup and maintain an extra pipe. The only thing you need with the &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; option is a simple signal handler and a flag to check. It seems like a simpler and more user-friendly option.&lt;/p&gt;
&lt;p&gt;Whatever you choose, some handling of POSIX signals will be necessary in a robust multi-process application. For instance, if a child process dies for some reason, a &lt;code&gt;SIGCHLD&lt;/code&gt; signal is sent to the parent, which could also interrupt blocking reads, sends and polls (if &lt;code&gt;SIG_IGN&lt;/code&gt; is not set for this signal). These must be handled either by using &lt;code&gt;ppoll&lt;/code&gt;/&lt;code&gt;pselect&lt;/code&gt; or by using the self-pipe trick.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;
&lt;p&gt;So, I implemented the &lt;code&gt;zmq::ppoll&lt;/code&gt; via &lt;code&gt;pselect&lt;/code&gt; route. And finally, after a lot of debugging, it seems to be working well!&lt;/p&gt;
&lt;p&gt;Its low level implementation (&lt;code&gt;zmq_ppoll&lt;/code&gt;) depends on many libzmq macros, defines and functions. Trying to build against this creates a giant string of dependency files. The problem with this is that libzmq does not expose all these internal headers, so for the time being I just copy pasted over all the necessary libzmq files. Amazingly, this just seems to work after a few tweaks. My compliments to the libzmq devs for creating such modular code!&lt;/p&gt;
&lt;p&gt;Regarding the few tweaks: there are a lot of precompiler variables which are used to configure the compiled libzmq code. It seems that for macOS, this configuration is perfectly comfortable basing &lt;code&gt;zmq_poll&lt;/code&gt; on &lt;code&gt;poll&lt;/code&gt;. This makes sense, but for our purposes it is really annoying, because we need all the stuff that would be compiled in the case &lt;code&gt;zmq_poll&lt;/code&gt; would be based on &lt;code&gt;select&lt;/code&gt;. A lot of necessary classes and typedefs are therefore not at all fed to the compiler from all the lazily copy-pasted headers and source files.&lt;/p&gt;
&lt;p&gt;This would become an issue if I was to submit all this &lt;code&gt;ppoll&lt;/code&gt; work to libzmq as a pull request. My need for &lt;code&gt;select&lt;/code&gt; would inflate the library a bit. This is a trade-off that the libzmq devs will have to decide on.&lt;/p&gt;
&lt;p&gt;If they don’t see this happening, I can still publish &lt;code&gt;zmq::ppoll&lt;/code&gt; as a separate library. I just need to flip the switch on all the &lt;code&gt;select&lt;/code&gt; vs &lt;code&gt;poll&lt;/code&gt; configured code. This can be done from &lt;code&gt;platform.hpp&lt;/code&gt;. And this is exactly what I’ve done in &lt;a href=&quot;https://github.com/roofit-dev/root/tree/MP_ZeroMQ-new_multiprocess/roofit/roofitZMQ&quot;&gt;the current RooFitZMQ implementation that you can find in this hidden away corner of GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;even-more-details&quot;&gt;Even more details&lt;/h2&gt;
&lt;p&gt;For the really technically interested reader (as if you would be anything else if you’ve reached this far down into the article), some final implementation details that may trip you up (as they did for me):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a &lt;code&gt;volatile sig_atomic_t&lt;/code&gt; value type for any values you set from within a signal handler. Changing other types is undefined behavior. It will usually work, but I guess in some rare cases it may not and you’ll be scrambling for explanations and will never sleep well again, knowing the mysterious bug that has eluded you for years and that you have heard whispered rumors about from your users is still lurking in the shadows.&lt;/li&gt;
&lt;li&gt;Handle errors (exceptions in the C++ case) wisely. That’s the short version, see the rest of this article for the long version.&lt;/li&gt;
&lt;li&gt;Make sure to set both your receives and your sends to non-blocking with the &lt;code&gt;ZMQ_DONTWAIT&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A practical problem with the latter point is that at the beginning of your run, the connections may not have been made between the sockets. This can lead to the non-blocking send to drop out with an EAGAIN error. Now, you may think (like I did): fine, I’ll handle that error and retry the send. However, the same error will occur at the end of your program when you disconnected the other end of your socket on purpose (as I found out the hard way). At this time, you won’t want to retry infinitely, which would hang your program (which happened to me), so just covering up all your sends in retry loops that trigger on EAGAIN will be too coarse a solution (believe me, I tried).&lt;/p&gt;
&lt;p&gt;What I went with in the end is to define a &lt;code&gt;send_flag&lt;/code&gt; in my Messenger class which I pass as the &lt;code&gt;flag&lt;/code&gt; option to all send calls. Initially, &lt;code&gt;send_flag&lt;/code&gt; is zero, so the send calls will block. I then call a &lt;code&gt;test_connections&lt;/code&gt; method and after this completes successfully, I set &lt;code&gt;send_flag&lt;/code&gt; to &lt;code&gt;ZMQ_DONTWAIT&lt;/code&gt;. Now, once the connection drops out, send calls will give the EAGAIN error. But this time, the start-of-the-program cause of EAGAIN is ruled out, so I can assume that the program has ended. I catch the EAGAIN in my event loops and continue the loop when I get an EAGAIN. This means the code will first come across my &lt;code&gt;ppoll&lt;/code&gt; again before it comes back to the send that caused the EAGAIN. Inside &lt;code&gt;ppoll&lt;/code&gt;, it will handle the &lt;code&gt;SIGTERM&lt;/code&gt; signal that I expect has been sent from the master process and the event loop will be exited properly.&lt;/p&gt;
&lt;p&gt;Lol, you thought that would be it, but no, it’s still not that simple (I’m talking to my innocent, naive, past self here). There are still three other reasons EAGAIN could trigger!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calls to receive (&lt;code&gt;recv&lt;/code&gt;) can also trigger an EAGAIN. To distinguish between send and receive EAGAIN triggers, we could throw different typed exceptions (remember, we’re doing C++ here, so every time I’m talking about error codes, what actually happened was a &lt;code&gt;zmq::error_t&lt;/code&gt; type exception was thrown… which also happens to carry along the traditional C style error code). As far as I can tell, the only reason &lt;code&gt;recv&lt;/code&gt; would trigger EAGAIN after a &lt;code&gt;ppoll&lt;/code&gt; (which I now call before every &lt;code&gt;recv&lt;/code&gt; call) is if &lt;code&gt;ppoll&lt;/code&gt; initially gets a read-ready signal for the socket, but the received data does not pass a ZMQ internal checksum test, so the socket becomes unreadable again when you actually try to read from it. In this case, which I hope is rare, things will probably break unless you try really hard to fix them, i.e. send a signal to the sender that something went wrong, or otherwise implementing a really robust messenging protocol. This therefore goes far beyond the scope of just combining ZMQ with POSIX signals and is described very well elsewhere (like in &lt;a href=&quot;http://zguide.zeromq.org/&quot;&gt;the awesome ZMQ guide&lt;/a&gt; I mentioned at the beginning of this article; in case you forgot, which I myself did, because it took me three weeks to get to the end of writing this post).&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;send&lt;/code&gt; call may have two other legitimate reasons for crapping out with EAGAIN. The first is that its receiving end may have hit its “high-water mark”, a ZMQ setting which you can look up in the ZMQ guide or elsewhere.&lt;/li&gt;
&lt;li&gt;The second reason &lt;code&gt;send&lt;/code&gt; could throw an EAGAIN is that the connection may have been severed unexpectedly. In my case, this would mean that in the following &lt;code&gt;ppoll&lt;/code&gt; call, no &lt;code&gt;SIGTERM&lt;/code&gt; signal will be received and so the code will just try to go on, probably hitting the same connection error again and again ad infinitum. This should also be handled properly, but I’m hoping it’s rare enough to not have to worry about it too much. Obviously, I will worry about it for the rest of my waking days. Will probably write another huge blog post about it at some point. Oh well!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We leave the latter problems to be solved as an exercise for the reader.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;467&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-b7296cf6.DbAeRZKP_wm8GG.webp&quot; srcset=&quot;&quot;&gt;
The reader.&lt;/p&gt;
&lt;h2 id=&quot;to-be-continued&quot;&gt;To be continued&lt;/h2&gt;
&lt;p&gt;So stay tuned for the release of &lt;code&gt;zmq_ppoll&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update Oct 2021: &lt;em&gt;&lt;code&gt;*zmq_ppoll*&lt;/code&gt;&lt;/em&gt; is now included in &lt;em&gt;&lt;a href=&quot;https://github.com/zeromq/libzmq/pull/4255&quot;&gt;&lt;em&gt;libzmq&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you have any questions or other thoughts, let me know in the comments or on &lt;a href=&quot;https://twitter.com/egpbos&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.reddit.com/r/cpp/comments/f2r1i6/combining_zeromq_posix_signals_use_ppoll_to/&quot;&gt;Reddit&lt;/a&gt;! Having spent so much time on this stuff, I guess sunk cost fallacy demands of me that I spend even more time on it by discussing it with as many people as possible ;) Also, I guess I’m kind of a mental masochist. Figuring out this stuff has been extremely frustrating, but also extremely satisfying. So throw your problems at me, I’m hungry for more!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Combining ZeroMQ &amp;amp;#x26; POSIX signals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;466&quot; src=&quot;https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-e6392eca.0irim351_y5OEb.webp&quot; srcset=&quot;&quot;&gt;
My happy face (not mine, but close enough), thinking about solving even more complex messaging problems.Thanks to [Lourens Veen,] Inti Pelupessy and [Peter Kalverla] for reviewing this article.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/combining-zeromq-amp-posix-signals-0ca88b1f.CCaf_wTP.png" medium="image"/><author>Patrick Bos</author></item><item><title>Decorators in R</title><link>https://blog.esciencecenter.nl/posts/2021-09-29---decorators-in-r</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-09-29---decorators-in-r</guid><description>&lt;p&gt;Decorators have been made quite popular by Python but, did you know they also exist in R?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;3200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_A6j5Seyt_V3qq5Si-c5a79df8.DrehzlkI_Z11QrU0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Lenny Kuhne on Unsplash&lt;/p&gt;
&lt;p&gt;Decorators are typically used to extend the behaviour of a function in an elegant and minimally invasive way. Graphically, we can think of a decorator as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;534&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ciWjhFQWICOV9SmeFsMuWg-594f2a3b.BLSn3eAg_Zq52jX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;An analogy of a decorator. The original function is a car. The decorator adds an antenna and a wing to the car, but the basic functionality of the car (transporting people) remains unchanged. Icons made by Smashicons and Freepik.&lt;/p&gt;
&lt;p&gt;Some examples of things you may want to do with a decorator are logging the input/output of a function, or timing it. The power of decorators is that, when properly designed, they work for &lt;strong&gt;any&lt;/strong&gt; function. This makes them quite versatile and useful, as we’ll see in some examples below.&lt;/p&gt;
&lt;p&gt;From a more technical point of view, decorators are &lt;em&gt;functionals&lt;/em&gt;. In mathematics, a functional is an object that takes functions as an input. In the case of decorators, they also return a function as an output. If you want to sound fancy, you can say that a decorator is an endomorphism over a functional space. But I prefer clarity above fanciness: a decorator is something that swallows functions and, well…, poops functions.&lt;/p&gt;
&lt;h2 id=&quot;functions-as-first-class-objects&quot;&gt;Functions as first-class objects&lt;/h2&gt;
&lt;p&gt;Decorators can be implemented in any language that treats functions as first-class objects. Long story short, this means that functions exist even if they are not called. Does this sound too abstract? Let’s get specific: check out the code snippets below.&lt;/p&gt;
&lt;p&gt;We can use the function &lt;code&gt;cos&lt;/code&gt; to calculate a cosine:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in R, &lt;code&gt;cos&lt;/code&gt; itself is an object. We can, for instance, assign it to something:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because &lt;code&gt;foo&lt;/code&gt; is now a function, we can call it with an argument:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we call it without an argument, it still returns something. Something a bit obscure, but something nonetheless:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function (x)  &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Primitive&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;cos&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that the function itself is an object that lives in our environment and that, in principle, we can manipulate it. This is exactly what a decorator will do.&lt;/p&gt;
&lt;h2 id=&quot;the-skeleton-of-a-basic-decorator&quot;&gt;The skeleton of a basic decorator&lt;/h2&gt;
&lt;p&gt;The basic skeleton of a decorator in R looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deco &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f) {  wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       # &amp;#x3C;code prior to execution&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       #&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;code posterior to execution&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we can apply it like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;f_decorated &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; deco(f)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth spending a minute looking at the skeleton above. The decorator will return a wrapper. A wrapper can be thought of as an improved version of the original function (but not of its result!, just like &lt;code&gt;foo&lt;/code&gt; didn’t return a result until we called &lt;code&gt;foo(3.1416)&lt;/code&gt;). The &lt;code&gt;...&lt;/code&gt; symbol stands for &lt;strong&gt;any&lt;/strong&gt; input (more on this later).Now, every time we call &lt;code&gt;f_decorated&lt;/code&gt; passing some argument(s) to it, not only the original &lt;code&gt;f&lt;/code&gt; will be executed, but also the code marked as prior and posterior.&lt;/p&gt;
&lt;p&gt;Let’s see some examples:&lt;/p&gt;
&lt;h2 id=&quot;time-my-function&quot;&gt;Time my function&lt;/h2&gt;
&lt;p&gt;The decorator below can be used to print the starting and ending times of your function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;timer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f) {   wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      op &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; options(digits&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;secs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Increase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; time resolution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      print(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time:&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sys.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Show&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the clock before      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      print(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time:&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sys.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Show&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the clock after      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can create an “improved” version of any function. Let’s try with the cosine function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos_timed &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; timer(cos)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos_timed(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-28 12:32:26.309175&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-28 12:32:26.310383&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the code above is equivalent to the shorthand:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;timer(cos)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1418&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;...&lt;/code&gt; syntax, meaning any amount of input parameters, allows for timing functions of different amounts of parameters without having to change anything at all. Check this out:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; timer(runif)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-28 12:35:02.506004&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-28 12:35:02.50642&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]  &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.63678797&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.99874053&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.09436601&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.91444153&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.77181499&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: please take this only as an example. If you really need to time your R functions, I advise you to use profiling tools instead.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;log-my-function&quot;&gt;Log my function&lt;/h2&gt;
&lt;p&gt;Another interesting possibility is using a decorator for logging the output of any function. Check this out:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;logger &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &apos;log&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&apos;) {   wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nothing      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      write(res, file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; filename, append &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s apply it, for instance, to the power function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logger(pow)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it will log the value &lt;code&gt;8&lt;/code&gt; in the default file &lt;code&gt;log.txt&lt;/code&gt;. A non-default log filename can be passed via:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logger(pow, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;otherlog.txt&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1024&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-about-syntactic-sugar&quot;&gt;What about syntactic sugar?&lt;/h2&gt;
&lt;p&gt;Certainly one of the secrets to the success of decorators in Python is that they look really neat. Instead of something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# In Pythonf_dec = decorator(f)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use syntactic sugar to apply the decorator from the moment the function is defined:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# In Python@decorator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def f(args)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;   #&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function body&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is it possible to do something similar in R? The answer is yes. And all of it thanks to the &lt;a href=&quot;https://cran.r-project.org/web/packages/tinsel/index.html&quot;&gt;tinsel&lt;/a&gt; package. As usual, the first step is to install and load it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;packages(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tinsel&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;library(tinsel)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we want to apply, say, our &lt;code&gt;timer&lt;/code&gt; decorator to a brand-new defined function, we’ll use the special comment &lt;code&gt;#. timer&lt;/code&gt; on top of the definition. This would be equivalent to the syntactic sugar &lt;code&gt;@timer&lt;/code&gt; in Python.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;#. timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;say_hi &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(name) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   return(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, name, sep &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to make it work, we have to source the file with a special source function contained in the tinsel package:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source_decoratees(&apos;filename&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;R&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we are ready to try it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; say_hi(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Pablo&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-29 10:29:27.364677&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-29 10:29:27.366081&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi Pablo&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes… this syntactic sugar is (still) not so amazing as that of Python, but still quite remarkable.&lt;/p&gt;
&lt;h2 id=&quot;a-real-world-problem&quot;&gt;A real-world problem&lt;/h2&gt;
&lt;p&gt;Wait a minute… is this useful at all? I mean, in real-world problems?&lt;/p&gt;
&lt;p&gt;Let me tell you a story. Not long ago, I had to refactor some code that I hadn’t written myself. I cannot imagine a more real-world task than that… and decorators made my life much easier.&lt;/p&gt;
&lt;p&gt;Long story short, the code contained several one-liners that did too much. Particularly, the command &lt;code&gt;system&lt;/code&gt; was used to execute very long instructions that were constructed by pasting pieces of strings. Something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;system(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;command1 &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;--parameter &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;command 2 &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, as&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;character(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1250&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot; more_commands &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), intern &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ignore&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stdout &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each line differed in the size and composition of the pasted string. In order to refactor this, and to make it more readable, the first thing I needed to know was the exact content of those complicated strings. There were lots of them, and I didn’t want to manually extract them from inside &lt;code&gt;system&lt;/code&gt;. Luckily for me, the pasted string was passed always as the first argument to the &lt;code&gt;system&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;So I wrote a decorator that logs the first argument of anything, and it saved my day:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;log1starg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &apos;loginput&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&apos;) {  wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(x, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      write(x, file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; filename, append &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the 1st arg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(x, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nothing      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I only had to find all the appearances of &lt;code&gt;system&lt;/code&gt; and substitute them by &lt;code&gt;log1starg(system)&lt;/code&gt;. After that, just run the script from beginning to the end, and open the freshly created &lt;code&gt;loginput.txt&lt;/code&gt; file containing all the information I needed.&lt;/p&gt;
&lt;h2 id=&quot;what-about-you&quot;&gt;What about you?&lt;/h2&gt;
&lt;p&gt;Can you think of another use for decorators? Please feel free to leave a comment below!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I want to express my gratitude to &lt;a href=&quot;https://medium.com/u/1382ec3ac71f?source=post_page---user_mention--ec84eaeca3e3---------------------------------------&quot;&gt;Patrick Bos&lt;/a&gt; for his useful suggestions.&lt;/p&gt;
&lt;p&gt;This entry appears in &lt;a href=&quot;https://r-bloggers.com/&quot;&gt;R-bloggers.com&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 29 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Decorators have been made quite popular by Python but, did you know they also exist in R?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;3200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_A6j5Seyt_V3qq5Si-c5a79df8.DrehzlkI_Z11QrU0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Lenny Kuhne on Unsplash&lt;/p&gt;
&lt;p&gt;Decorators are typically used to extend the behaviour of a function in an elegant and minimally invasive way. Graphically, we can think of a decorator as:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;534&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_ciWjhFQWICOV9SmeFsMuWg-594f2a3b.BLSn3eAg_Zq52jX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;An analogy of a decorator. The original function is a car. The decorator adds an antenna and a wing to the car, but the basic functionality of the car (transporting people) remains unchanged. Icons made by Smashicons and Freepik.&lt;/p&gt;
&lt;p&gt;Some examples of things you may want to do with a decorator are logging the input/output of a function, or timing it. The power of decorators is that, when properly designed, they work for &lt;strong&gt;any&lt;/strong&gt; function. This makes them quite versatile and useful, as we’ll see in some examples below.&lt;/p&gt;
&lt;p&gt;From a more technical point of view, decorators are &lt;em&gt;functionals&lt;/em&gt;. In mathematics, a functional is an object that takes functions as an input. In the case of decorators, they also return a function as an output. If you want to sound fancy, you can say that a decorator is an endomorphism over a functional space. But I prefer clarity above fanciness: a decorator is something that swallows functions and, well…, poops functions.&lt;/p&gt;
&lt;h2 id=&quot;functions-as-first-class-objects&quot;&gt;Functions as first-class objects&lt;/h2&gt;
&lt;p&gt;Decorators can be implemented in any language that treats functions as first-class objects. Long story short, this means that functions exist even if they are not called. Does this sound too abstract? Let’s get specific: check out the code snippets below.&lt;/p&gt;
&lt;p&gt;We can use the function &lt;code&gt;cos&lt;/code&gt; to calculate a cosine:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in R, &lt;code&gt;cos&lt;/code&gt; itself is an object. We can, for instance, assign it to something:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because &lt;code&gt;foo&lt;/code&gt; is now a function, we can call it with an argument:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;foo(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we call it without an argument, it still returns something. Something a bit obscure, but something nonetheless:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; foo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function (x)  &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Primitive&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;cos&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that the function itself is an object that lives in our environment and that, in principle, we can manipulate it. This is exactly what a decorator will do.&lt;/p&gt;
&lt;h2 id=&quot;the-skeleton-of-a-basic-decorator&quot;&gt;The skeleton of a basic decorator&lt;/h2&gt;
&lt;p&gt;The basic skeleton of a decorator in R looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deco &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f) {  wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       # &amp;#x3C;code prior to execution&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       #&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;code posterior to execution&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we can apply it like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;f_decorated &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; deco(f)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth spending a minute looking at the skeleton above. The decorator will return a wrapper. A wrapper can be thought of as an improved version of the original function (but not of its result!, just like &lt;code&gt;foo&lt;/code&gt; didn’t return a result until we called &lt;code&gt;foo(3.1416)&lt;/code&gt;). The &lt;code&gt;...&lt;/code&gt; symbol stands for &lt;strong&gt;any&lt;/strong&gt; input (more on this later).Now, every time we call &lt;code&gt;f_decorated&lt;/code&gt; passing some argument(s) to it, not only the original &lt;code&gt;f&lt;/code&gt; will be executed, but also the code marked as prior and posterior.&lt;/p&gt;
&lt;p&gt;Let’s see some examples:&lt;/p&gt;
&lt;h2 id=&quot;time-my-function&quot;&gt;Time my function&lt;/h2&gt;
&lt;p&gt;The decorator below can be used to print the starting and ending times of your function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;timer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f) {   wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      op &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; options(digits&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;secs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Increase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; time resolution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      print(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time:&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sys.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Show&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the clock before      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      print(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time:&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sys.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Show&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the clock after      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can create an “improved” version of any function. Let’s try with the cosine function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos_timed &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; timer(cos)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cos_timed(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1416&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-28 12:32:26.309175&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-28 12:32:26.310383&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the code above is equivalent to the shorthand:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;timer(cos)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.1418&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;...&lt;/code&gt; syntax, meaning any amount of input parameters, allows for timing functions of different amounts of parameters without having to change anything at all. Check this out:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; timer(runif)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-28 12:35:02.506004&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-28 12:35:02.50642&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]  &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.63678797&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.99874053&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.09436601&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.91444153&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  0.77181499&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: please take this only as an example. If you really need to time your R functions, I advise you to use profiling tools instead.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;log-my-function&quot;&gt;Log my function&lt;/h2&gt;
&lt;p&gt;Another interesting possibility is using a decorator for logging the output of any function. Check this out:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;logger &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &apos;log&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&apos;) {   wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nothing      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      write(res, file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; filename, append &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s apply it, for instance, to the power function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logger(pow)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it will log the value &lt;code&gt;8&lt;/code&gt; in the default file &lt;code&gt;log.txt&lt;/code&gt;. A non-default log filename can be passed via:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logger(pow, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;otherlog.txt&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1024&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-about-syntactic-sugar&quot;&gt;What about syntactic sugar?&lt;/h2&gt;
&lt;p&gt;Certainly one of the secrets to the success of decorators in Python is that they look really neat. Instead of something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# In Pythonf_dec = decorator(f)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use syntactic sugar to apply the decorator from the moment the function is defined:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# In Python@decorator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;def f(args)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;   #&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function body&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is it possible to do something similar in R? The answer is yes. And all of it thanks to the &lt;a href=&quot;https://cran.r-project.org/web/packages/tinsel/index.html&quot;&gt;tinsel&lt;/a&gt; package. As usual, the first step is to install and load it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;packages(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tinsel&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;library(tinsel)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we want to apply, say, our &lt;code&gt;timer&lt;/code&gt; decorator to a brand-new defined function, we’ll use the special comment &lt;code&gt;#. timer&lt;/code&gt; on top of the definition. This would be equivalent to the syntactic sugar &lt;code&gt;@timer&lt;/code&gt; in Python.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;#. timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;say_hi &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(name) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   return(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, name, sep &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to make it work, we have to source the file with a special source function contained in the tinsel package:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source_decoratees(&apos;filename&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;R&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we are ready to try it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; say_hi(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Pablo&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ini time: 2021-07-29 10:29:27.364677&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;End time: 2021-07-29 10:29:27.366081&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi Pablo&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes… this syntactic sugar is (still) not so amazing as that of Python, but still quite remarkable.&lt;/p&gt;
&lt;h2 id=&quot;a-real-world-problem&quot;&gt;A real-world problem&lt;/h2&gt;
&lt;p&gt;Wait a minute… is this useful at all? I mean, in real-world problems?&lt;/p&gt;
&lt;p&gt;Let me tell you a story. Not long ago, I had to refactor some code that I hadn’t written myself. I cannot imagine a more real-world task than that… and decorators made my life much easier.&lt;/p&gt;
&lt;p&gt;Long story short, the code contained several one-liners that did too much. Particularly, the command &lt;code&gt;system&lt;/code&gt; was used to execute very long instructions that were constructed by pasting pieces of strings. Something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;system(paste(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;command1 &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;--parameter &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;command 2 &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, as&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;character(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1250&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot; more_commands &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), intern &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ignore&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stdout &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each line differed in the size and composition of the pasted string. In order to refactor this, and to make it more readable, the first thing I needed to know was the exact content of those complicated strings. There were lots of them, and I didn’t want to manually extract them from inside &lt;code&gt;system&lt;/code&gt;. Luckily for me, the pasted string was passed always as the first argument to the &lt;code&gt;system&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;So I wrote a decorator that logs the first argument of anything, and it saved my day:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;log1starg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(f, filename &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &apos;loginput&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&apos;) {  wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; function(x, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      # Before execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      write(x, file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; filename, append &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TRUE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the 1st arg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      res &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f(x, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)      &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; After&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nothing      return(res)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  return(wrapper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I only had to find all the appearances of &lt;code&gt;system&lt;/code&gt; and substitute them by &lt;code&gt;log1starg(system)&lt;/code&gt;. After that, just run the script from beginning to the end, and open the freshly created &lt;code&gt;loginput.txt&lt;/code&gt; file containing all the information I needed.&lt;/p&gt;
&lt;h2 id=&quot;what-about-you&quot;&gt;What about you?&lt;/h2&gt;
&lt;p&gt;Can you think of another use for decorators? Please feel free to leave a comment below!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I want to express my gratitude to &lt;a href=&quot;https://medium.com/u/1382ec3ac71f?source=post_page---user_mention--ec84eaeca3e3---------------------------------------&quot;&gt;Patrick Bos&lt;/a&gt; for his useful suggestions.&lt;/p&gt;
&lt;p&gt;This entry appears in &lt;a href=&quot;https://r-bloggers.com/&quot;&gt;R-bloggers.com&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_ciWjhFQWICOV9SmeFsMuWg-594f2a3b.BLSn3eAg.png" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Pandemic-proof: shaping the future of scientific exchange</title><link>https://blog.esciencecenter.nl/posts/2021-09-21---pandemic-proof-shaping-the-future-of-scientific-exchange</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-09-21---pandemic-proof-shaping-the-future-of-scientific-exchange</guid><description>&lt;p&gt;The 2021 (virtual) meeting of the &lt;a href=&quot;https://www.emetsoc.org/&quot;&gt;European Meteorological Society&lt;/a&gt; started off with the collaborative Future Science Cafe. Inspired by the rapid developments in remote collaboration forced upon us by the COVID-19 pandemic, we reflected on the sustainability of everyday academic practices, and imagined what a future world might look like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1280&quot; height=&quot;907&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_35Fq6kF4xD76Z2aHlSNsXA-3a846000.7RnXy5WL_29TclG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Visual summary of the future science cafe by Szilard Strenner (grafacity.eu)&lt;/p&gt;
&lt;p&gt;Some of the advantages and drawbacks were quite obvious. Advantages are for example, saving on travel and lower barriers for remote collaboration. The biggest disadvantages were experiences in the social spheres, with disturbed work-life balance and isolation. Notably, new colleagues suffered from a lack of proper introduction.&lt;/p&gt;
&lt;p&gt;Several new ideas and insights came up as well. For example, online lectures sometimes led to increased participation by students. And instead of hybrid conferences, perhaps it is more productive to consider hybrid audiences, since the interest of a remote audience is often not served by the traditional conference format and vice versa.&lt;/p&gt;
&lt;p&gt;The event was held in gather.town, where five whiteboards were set up in a virtual room. Each whiteboard was tied to a topic. In two rounds, participants gathered around the whiteboards and discussed the corresponding topics. Afterwards, the moderators wrote a short summary on each of the topics.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1248&quot; height=&quot;640&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_s3Tc_gqR9wuUKXPQegGcAQ-5e9c899c.CqYMTdk0_WVwoA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Layout of the virtual discussion space&lt;/p&gt;
&lt;h3 id=&quot;online-education&quot;&gt;Online education&lt;/h3&gt;
&lt;p&gt;For 1.5 years, education at universities has been mostly online, partly on-campus or in a hybrid format. In this session we reflected on the opportunities that arose due to this quick transformation, but also on the aspects that were really missed.&lt;/p&gt;
&lt;p&gt;A big benefit of online education is the accessibility for everyone. Students can log in from their parents’ place, home country, or student room. At Met Offices (such as DWD), digital education means that people do not have to travel all across the country, and can easily chime in for a particular session.&lt;/p&gt;
&lt;p&gt;It differs per teaching format if online alternatives are suitable. Lectures work pretty well; if students can pose questions in a chat, it can be even more interactive than in a classroom. Sharing screens is also very useful during practical sessions. However, we miss seeing the faces during classes. Are students bored? Can they follow you? This is what you would notice directly in a live classroom, but you do not see when everyone has their camera turned off and you are in presenting mode.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;436&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1__vGw0PjOBM0547M5rSgoYQ-adf481e9.DOhUkr9o_ZNmFI2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Teaching from home also revealed the large social component of on-campus education, which is difficult to create online. Going to university is about meeting your fellow students, having an informal chat with the teacher during a break to discuss which courses to follow next, or to ask one more question on the content. During tutorials, students like to check their answer with the neighbour to see if they are on the right track. While tools such as gather.town or spatial.chat can provide some of these informal coffee-moments, it remains a challenge to have informal chats with students in an online setting.&lt;/p&gt;
&lt;p&gt;How to move forward as teaching (in the Netherlands at least) is moving ‘back-to-normal’? As much online content is created in the past year, it would be a waste to not benefit from it. However, it is scary to put your material in the great-wide-open (YouTube), especially when you have been recording yourself in home-office settings etc. Nevertheless, the digital content can be used internally in a “flip the classroom” principle, where students study the content in their own time and come to campus for Q&amp;#x26;A sessions with the teacher, and to make exercises with fellow students. In this way you re-use the material from last year, and create the social activities on-campus.&lt;/p&gt;
&lt;h3 id=&quot;boosted-collaboration&quot;&gt;Boosted collaboration&lt;/h3&gt;
&lt;p&gt;The pandemic forced us into online collaboration. While everyone is happy to be able to meet in person again, (know-how of) online possibilities has increased a lot, and maybe it’s here to stay. In the boosted collaboration session, we discussed about the positive and negative aspects of the new online-working regime in terms of collaboration, work efficiency, and work-life balance.&lt;/p&gt;
&lt;p&gt;In terms of work environment collaboration, the ability to attend meetings online from different locations has increased meeting flexibility and allowed more people to participate in meetings. The lack of need for a physical meeting space also contributes to increased participation in meetings. In addition, since most of the people are now easily connected through online discussion/working software (i.e. slack), it is much easier to set up quick discussion groups.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;466&quot; height=&quot;224&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_lrNKuRGqb2iIzqzRZ52VXQ-e28c55f4.Bp_2pvH9_18MhO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the participants noted that the online working environment has made it easier and faster to address problems and emergency situations while working from home, because people no longer need to spend the time to commute to the office to deal with the emergency. However, this flexibility can create issues with work-life balance, as people are more likely to work outside the normal working hours. This can result in increased work-related communication throughout the day, which can increase work-related stress. This effect is partly counteracted by the reduced time spend in commuting, which can increase work efficiency and reduce the stress and delays associated with commuting from home to the office and vice versa.&lt;/p&gt;
&lt;p&gt;As noted by all the participants the online working environments has created problems for newer colleagues, who do not have an existing collaboration network in place. They find it more difficult to find and communicate with other colleagues as they are often not in the office, where it is easier to spontaneously meet and discuss during coffee or lunch break. This can inhibit both the development of an early career scientist’s collaboration network and the knowledge transfer from the older more experienced colleagues to the younger ones.&lt;/p&gt;
&lt;p&gt;In general, it seems that the additional opportunities to collaborate and work online is a double-edged sword. The benefits are clear, but so are the drawbacks, which need to be addressed to allow the online collaboration opportunities to flourish.&lt;/p&gt;
&lt;h3 id=&quot;meteorology-vs-global-crisis&quot;&gt;Meteorology vs global crisis&lt;/h3&gt;
&lt;p&gt;Throughout the COVID-19 pandemic, epidemiologists, virologists, and vaccine developers have received both high esteem and lots of criticism. What can we, as meteorologists, learn from the pandemic? We discussed the role of meteorology in crisis response, and especially what our strong points are that we could share with other disciplines and governments.&lt;/p&gt;
&lt;p&gt;Meteorology is an old discipline — we have literally centuries of experience in measuring and researching the atmosphere. The comment was made that “exchange and cooperation are in our DNA”: from sharing crucial data over slow mediums such as telegraphs in earlier times, to the current rapid share of millions of data points and models through the internet. Exchange of data is normal and expected within meteorology, but might not be as natural for other disciplines (where there might be a certain economical competition for instance). For crisis response, timely sharing of information is crucial, like sharing satellite imagery to emergency services, or outcomes of a model for flooding problems, for instance. In a similar fashion, interdisciplinary is also an important aspect for crisis response that we have plenty of experience with: the current meteorological models started as pure atmospheres, then improved with ocean, biosphere, chemistry etc, all bringing in experts from those fields.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;406&quot; height=&quot;230&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-D8cF_Q_gkz4CyvbmmB0Bw-f35bcfd9.tfIGfFka_ZIM4MF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A drawback is that other disciplines (mostly outside of the environmental sciences) can often make use of third-party investments for innovations. Since there is not a whole lot of immediate profit to be gained in meteorology, it often takes a disaster to kickstart (national) investments in early warning systems or climate-proofing cities etc (think of the recent European floods). Perhaps such disasters are needed to kickstart cooperation between parties as well, have everyone around the same table, even though ideally we’d like to prevent situations like that.&lt;/p&gt;
&lt;p&gt;More cooperation with policy makers and urban planners is needed to prevent future (urban) disasters: the world is urbanizing and anything that happens in a city can impact thousands of people. Any new urban structuring should involve some form of climate expert to deal with expected climate change and reduce climate risks.&lt;/p&gt;
&lt;h3 id=&quot;new-office-concepts&quot;&gt;New office concepts&lt;/h3&gt;
&lt;p&gt;With the pandemic, home office work places became a standard to millions of office workers. The experience quickly revealed that a combination of working from home and working at the employer’s building is preferred by many. This reduces the space required in office buildings, making room for new office concepts and workflows. Skipping the commute also saves time and CO2.&lt;/p&gt;
&lt;p&gt;Participants suggested that a 50/50 distribution between office and home office is effective and comfortable. While some people value privacy in their office and a quiet workplace, the social function of office space was missed most in home office — and was only partly replaced by online coffee breaks, depending on the digital skills and flexibility of colleagues.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;280&quot; height=&quot;339&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_a50t-ybZ_6G4hCv1YB4kqQ-68de0091.DAGfM_MV_Z1Tv0rJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Most impressive, though, was the “lostness” of new colleagues not properly meeting their other colleagues — and not being properly introduced to them digitally instead. Executive personnel forgot that this introduction doesn’t happen naturally in the halls between the offices anymore. A virtual office twin like we had in gather-town or on similar platforms like spatial.chat could provide a place to hang out and be available for colleagues if necessary, without being in formal video conferences all the time.&lt;/p&gt;
&lt;p&gt;The new office concept at Deutscher Wetterdienst (DWD) was generally met with positive interest. It is optimized for a hybrid concept of office and home office, with bookable offices, and more and flexible meeting spaces (large kitchen, large and small offices, more meeting rooms in smaller sizes). While some people prefer their own classic office space, most people could imagine booking offices flexibly upon needs and stowing their personal things in a rolling office container.&lt;/p&gt;
&lt;h3 id=&quot;hybrid-conferences&quot;&gt;Hybrid conferences&lt;/h3&gt;
&lt;p&gt;After more than a year of virtual conferences, scientists are looking forward to meeting in person again. But we have also seen (and to some extent, grown accustomed to) the advantages of online meetings and conferences. How can we get the best of both worlds?&lt;/p&gt;
&lt;p&gt;We discussed advantages and disadvantages of both on-site and virtual conferences. Interestingly, most advantages also translated into drawbacks. For example, participants generally appreciated the increased accessibility of an online conference, but they disliked the reduced commitment from participants. Similarly, they were happy with the reduced travel, but they missed seeing new places and tasting new beers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;304&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_v8Pg3mYaNxy_w8Ar1tEIHQ-dd8e69da._RyDQN3Q_Z1rV1ig.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It thus appears that a hybrid conference as a “somewhere-in-between” will not be able to meet the needs of all participants. Instead, it might be more effective to target different types of audiences with the on-site and online components: the on-site meeting will then be optimized for dedication, whereas the online counterpart will accommodate broad but occasional, perhaps even asynchronous, accessibility.&lt;/p&gt;
&lt;p&gt;While there are examples where hybrid conferences work very well (think TED), this puts an additional burden on the organizers, “as if you’re organizing two events instead of one”. Perhaps a more gradual transition would enable us to build up experience while keeping things manageable. We could start, for example, by streaming only the keynotes, and making recordings available after the event.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The COVID-19 pandemic triggered a sudden overhaul in our daily routines. Evidently, change is often triggered or accelerated by emergencies, even if the precursors might have been lingering around for some time already.&lt;/p&gt;
&lt;p&gt;The future science cafe was an opportunity to reflect on the status quo and take agency of where we are headed as a field. This year’s theme was mostly around remote collaboration in one way or another. But there are more meta-topics that would make for an interesting future science cafe. Think of open science, reviewing procedures, academic career paths, et cetera.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;335&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_UTFCxgBjf9H4C5jDRBaqCA-8631ad38.DgLZJmvj_10a7JC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The annual meeting of the EMS seems to be a good place for such contemplations, and we are thinking about making this a recurring event. So thanks to all participants, and hope to see you next year!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Imme Benedict, Arjan Droste, Hella Riede, and Aristofanis Tsiringakis for moderating the discussions and to Szilard Strenner (grafacity.eu) for the visual impression.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Tue, 21 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The 2021 (virtual) meeting of the &lt;a href=&quot;https://www.emetsoc.org/&quot;&gt;European Meteorological Society&lt;/a&gt; started off with the collaborative Future Science Cafe. Inspired by the rapid developments in remote collaboration forced upon us by the COVID-19 pandemic, we reflected on the sustainability of everyday academic practices, and imagined what a future world might look like.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1280&quot; height=&quot;907&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_35Fq6kF4xD76Z2aHlSNsXA-3a846000.7RnXy5WL_29TclG.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Visual summary of the future science cafe by Szilard Strenner (grafacity.eu)&lt;/p&gt;
&lt;p&gt;Some of the advantages and drawbacks were quite obvious. Advantages are for example, saving on travel and lower barriers for remote collaboration. The biggest disadvantages were experiences in the social spheres, with disturbed work-life balance and isolation. Notably, new colleagues suffered from a lack of proper introduction.&lt;/p&gt;
&lt;p&gt;Several new ideas and insights came up as well. For example, online lectures sometimes led to increased participation by students. And instead of hybrid conferences, perhaps it is more productive to consider hybrid audiences, since the interest of a remote audience is often not served by the traditional conference format and vice versa.&lt;/p&gt;
&lt;p&gt;The event was held in gather.town, where five whiteboards were set up in a virtual room. Each whiteboard was tied to a topic. In two rounds, participants gathered around the whiteboards and discussed the corresponding topics. Afterwards, the moderators wrote a short summary on each of the topics.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1248&quot; height=&quot;640&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_s3Tc_gqR9wuUKXPQegGcAQ-5e9c899c.CqYMTdk0_WVwoA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Layout of the virtual discussion space&lt;/p&gt;
&lt;h3 id=&quot;online-education&quot;&gt;Online education&lt;/h3&gt;
&lt;p&gt;For 1.5 years, education at universities has been mostly online, partly on-campus or in a hybrid format. In this session we reflected on the opportunities that arose due to this quick transformation, but also on the aspects that were really missed.&lt;/p&gt;
&lt;p&gt;A big benefit of online education is the accessibility for everyone. Students can log in from their parents’ place, home country, or student room. At Met Offices (such as DWD), digital education means that people do not have to travel all across the country, and can easily chime in for a particular session.&lt;/p&gt;
&lt;p&gt;It differs per teaching format if online alternatives are suitable. Lectures work pretty well; if students can pose questions in a chat, it can be even more interactive than in a classroom. Sharing screens is also very useful during practical sessions. However, we miss seeing the faces during classes. Are students bored? Can they follow you? This is what you would notice directly in a live classroom, but you do not see when everyone has their camera turned off and you are in presenting mode.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;436&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1__vGw0PjOBM0547M5rSgoYQ-adf481e9.DOhUkr9o_ZNmFI2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Teaching from home also revealed the large social component of on-campus education, which is difficult to create online. Going to university is about meeting your fellow students, having an informal chat with the teacher during a break to discuss which courses to follow next, or to ask one more question on the content. During tutorials, students like to check their answer with the neighbour to see if they are on the right track. While tools such as gather.town or spatial.chat can provide some of these informal coffee-moments, it remains a challenge to have informal chats with students in an online setting.&lt;/p&gt;
&lt;p&gt;How to move forward as teaching (in the Netherlands at least) is moving ‘back-to-normal’? As much online content is created in the past year, it would be a waste to not benefit from it. However, it is scary to put your material in the great-wide-open (YouTube), especially when you have been recording yourself in home-office settings etc. Nevertheless, the digital content can be used internally in a “flip the classroom” principle, where students study the content in their own time and come to campus for Q&amp;#x26;A sessions with the teacher, and to make exercises with fellow students. In this way you re-use the material from last year, and create the social activities on-campus.&lt;/p&gt;
&lt;h3 id=&quot;boosted-collaboration&quot;&gt;Boosted collaboration&lt;/h3&gt;
&lt;p&gt;The pandemic forced us into online collaboration. While everyone is happy to be able to meet in person again, (know-how of) online possibilities has increased a lot, and maybe it’s here to stay. In the boosted collaboration session, we discussed about the positive and negative aspects of the new online-working regime in terms of collaboration, work efficiency, and work-life balance.&lt;/p&gt;
&lt;p&gt;In terms of work environment collaboration, the ability to attend meetings online from different locations has increased meeting flexibility and allowed more people to participate in meetings. The lack of need for a physical meeting space also contributes to increased participation in meetings. In addition, since most of the people are now easily connected through online discussion/working software (i.e. slack), it is much easier to set up quick discussion groups.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;466&quot; height=&quot;224&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_lrNKuRGqb2iIzqzRZ52VXQ-e28c55f4.Bp_2pvH9_18MhO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the participants noted that the online working environment has made it easier and faster to address problems and emergency situations while working from home, because people no longer need to spend the time to commute to the office to deal with the emergency. However, this flexibility can create issues with work-life balance, as people are more likely to work outside the normal working hours. This can result in increased work-related communication throughout the day, which can increase work-related stress. This effect is partly counteracted by the reduced time spend in commuting, which can increase work efficiency and reduce the stress and delays associated with commuting from home to the office and vice versa.&lt;/p&gt;
&lt;p&gt;As noted by all the participants the online working environments has created problems for newer colleagues, who do not have an existing collaboration network in place. They find it more difficult to find and communicate with other colleagues as they are often not in the office, where it is easier to spontaneously meet and discuss during coffee or lunch break. This can inhibit both the development of an early career scientist’s collaboration network and the knowledge transfer from the older more experienced colleagues to the younger ones.&lt;/p&gt;
&lt;p&gt;In general, it seems that the additional opportunities to collaborate and work online is a double-edged sword. The benefits are clear, but so are the drawbacks, which need to be addressed to allow the online collaboration opportunities to flourish.&lt;/p&gt;
&lt;h3 id=&quot;meteorology-vs-global-crisis&quot;&gt;Meteorology vs global crisis&lt;/h3&gt;
&lt;p&gt;Throughout the COVID-19 pandemic, epidemiologists, virologists, and vaccine developers have received both high esteem and lots of criticism. What can we, as meteorologists, learn from the pandemic? We discussed the role of meteorology in crisis response, and especially what our strong points are that we could share with other disciplines and governments.&lt;/p&gt;
&lt;p&gt;Meteorology is an old discipline — we have literally centuries of experience in measuring and researching the atmosphere. The comment was made that “exchange and cooperation are in our DNA”: from sharing crucial data over slow mediums such as telegraphs in earlier times, to the current rapid share of millions of data points and models through the internet. Exchange of data is normal and expected within meteorology, but might not be as natural for other disciplines (where there might be a certain economical competition for instance). For crisis response, timely sharing of information is crucial, like sharing satellite imagery to emergency services, or outcomes of a model for flooding problems, for instance. In a similar fashion, interdisciplinary is also an important aspect for crisis response that we have plenty of experience with: the current meteorological models started as pure atmospheres, then improved with ocean, biosphere, chemistry etc, all bringing in experts from those fields.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;406&quot; height=&quot;230&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-D8cF_Q_gkz4CyvbmmB0Bw-f35bcfd9.tfIGfFka_ZIM4MF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A drawback is that other disciplines (mostly outside of the environmental sciences) can often make use of third-party investments for innovations. Since there is not a whole lot of immediate profit to be gained in meteorology, it often takes a disaster to kickstart (national) investments in early warning systems or climate-proofing cities etc (think of the recent European floods). Perhaps such disasters are needed to kickstart cooperation between parties as well, have everyone around the same table, even though ideally we’d like to prevent situations like that.&lt;/p&gt;
&lt;p&gt;More cooperation with policy makers and urban planners is needed to prevent future (urban) disasters: the world is urbanizing and anything that happens in a city can impact thousands of people. Any new urban structuring should involve some form of climate expert to deal with expected climate change and reduce climate risks.&lt;/p&gt;
&lt;h3 id=&quot;new-office-concepts&quot;&gt;New office concepts&lt;/h3&gt;
&lt;p&gt;With the pandemic, home office work places became a standard to millions of office workers. The experience quickly revealed that a combination of working from home and working at the employer’s building is preferred by many. This reduces the space required in office buildings, making room for new office concepts and workflows. Skipping the commute also saves time and CO2.&lt;/p&gt;
&lt;p&gt;Participants suggested that a 50/50 distribution between office and home office is effective and comfortable. While some people value privacy in their office and a quiet workplace, the social function of office space was missed most in home office — and was only partly replaced by online coffee breaks, depending on the digital skills and flexibility of colleagues.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;280&quot; height=&quot;339&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_a50t-ybZ_6G4hCv1YB4kqQ-68de0091.DAGfM_MV_Z1Tv0rJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Most impressive, though, was the “lostness” of new colleagues not properly meeting their other colleagues — and not being properly introduced to them digitally instead. Executive personnel forgot that this introduction doesn’t happen naturally in the halls between the offices anymore. A virtual office twin like we had in gather-town or on similar platforms like spatial.chat could provide a place to hang out and be available for colleagues if necessary, without being in formal video conferences all the time.&lt;/p&gt;
&lt;p&gt;The new office concept at Deutscher Wetterdienst (DWD) was generally met with positive interest. It is optimized for a hybrid concept of office and home office, with bookable offices, and more and flexible meeting spaces (large kitchen, large and small offices, more meeting rooms in smaller sizes). While some people prefer their own classic office space, most people could imagine booking offices flexibly upon needs and stowing their personal things in a rolling office container.&lt;/p&gt;
&lt;h3 id=&quot;hybrid-conferences&quot;&gt;Hybrid conferences&lt;/h3&gt;
&lt;p&gt;After more than a year of virtual conferences, scientists are looking forward to meeting in person again. But we have also seen (and to some extent, grown accustomed to) the advantages of online meetings and conferences. How can we get the best of both worlds?&lt;/p&gt;
&lt;p&gt;We discussed advantages and disadvantages of both on-site and virtual conferences. Interestingly, most advantages also translated into drawbacks. For example, participants generally appreciated the increased accessibility of an online conference, but they disliked the reduced commitment from participants. Similarly, they were happy with the reduced travel, but they missed seeing new places and tasting new beers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;304&quot; height=&quot;408&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_v8Pg3mYaNxy_w8Ar1tEIHQ-dd8e69da._RyDQN3Q_Z1rV1ig.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It thus appears that a hybrid conference as a “somewhere-in-between” will not be able to meet the needs of all participants. Instead, it might be more effective to target different types of audiences with the on-site and online components: the on-site meeting will then be optimized for dedication, whereas the online counterpart will accommodate broad but occasional, perhaps even asynchronous, accessibility.&lt;/p&gt;
&lt;p&gt;While there are examples where hybrid conferences work very well (think TED), this puts an additional burden on the organizers, “as if you’re organizing two events instead of one”. Perhaps a more gradual transition would enable us to build up experience while keeping things manageable. We could start, for example, by streaming only the keynotes, and making recordings available after the event.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The COVID-19 pandemic triggered a sudden overhaul in our daily routines. Evidently, change is often triggered or accelerated by emergencies, even if the precursors might have been lingering around for some time already.&lt;/p&gt;
&lt;p&gt;The future science cafe was an opportunity to reflect on the status quo and take agency of where we are headed as a field. This year’s theme was mostly around remote collaboration in one way or another. But there are more meta-topics that would make for an interesting future science cafe. Think of open science, reviewing procedures, academic career paths, et cetera.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;335&quot; height=&quot;182&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_UTFCxgBjf9H4C5jDRBaqCA-8631ad38.DgLZJmvj_10a7JC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The annual meeting of the EMS seems to be a good place for such contemplations, and we are thinking about making this a recurring event. So thanks to all participants, and hope to see you next year!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Imme Benedict, Arjan Droste, Hella Riede, and Aristofanis Tsiringakis for moderating the discussions and to Szilard Strenner (grafacity.eu) for the visual impression.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_35Fq6kF4xD76Z2aHlSNsXA-3a846000.7RnXy5WL.jpeg" medium="image"/><author>Peter Kalverla</author></item><item><title>Plotting gridded data on a web map: Python and/or Javascript?</title><link>https://blog.esciencecenter.nl/posts/2021-09-20---plotting-gridded-data-on-a-web-map-python-andor-javascript</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-09-20---plotting-gridded-data-on-a-web-map-python-andor-javascript</guid><description>&lt;p&gt;But what if you want to plot your own data? While there are many resources on how to use existing tile or web-map services, I struggled to find out how to make my own. Eventually, I found a &lt;a href=&quot;https://www.azavea.com/blog/2018/08/06/generating-pyramided-tiles-from-a-geotiff-using-geotrellis/&quot;&gt;nice example&lt;/a&gt; using &lt;a href=&quot;https://geotrellis.readthedocs.io/en/latest/&quot;&gt;GeoTrellis&lt;/a&gt;, but by that time I had already concocted a half-baked solution in my beloved Python. More on that in a bit.&lt;/p&gt;
&lt;p&gt;Leaflet also has different kinds of layers. You can draw lines, markers, shapes, polygons, images, and even videos. Here’s how to draw a simple rectangle on a Leaflet map:&lt;/p&gt;
&lt;p&gt;var bounds = [[50, 0], [55, 5]]  // ymin xmin ymax xmax
L.rectangle(bounds, {color: “#ffffff”, weight: 1}).addTo(map);So if I could load my data into some that bounds array and write a function to determine the colours, that should work. Right?&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://blog.scottlogic.com/2020/05/01/rendering-one-million-points-with-d3.html&quot;&gt;this blogpost&lt;/a&gt;, Leaflet should perform well up to about ten thousand data points. However, gridded data can easily get bigger. The snapshot of ERA5 data that I used for the first example already has over a million grid cells (0.25 by 0.25 degrees, global coverage). So it seems we’re hitting a dead end there as well… Or not?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deck.gl/&quot;&gt;deck.gl&lt;/a&gt; is like Leaflet on steroids. It was designed to “visually explore large-scale datasets”. It leverages the processing power of your graphics card to do some impressive rendering magic. After using Leaflet, I found it quite easy to get up and running with deck.gl, and managed to produce this awesome visualization:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;612&quot; height=&quot;432&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-7102366f.CCo91M-J_WnkMk.webp&quot; srcset=&quot;&quot;&gt;
Rendering over a million grid cells using deck.glBut still, I had to cheat a bit. And still, it was slow. For the data… was big.&lt;/p&gt;
&lt;h2 id=&quot;incentives-for-a-hybrid-solution&quot;&gt;Incentives for a hybrid solution&lt;/h2&gt;
&lt;p&gt;The data I wanted to use came originally in netCDF format and while it seems possible* nowadays to parse that with Javascript, it’s not the oneliner I’m used to in Python. The same goes for the colour mapping. To save me some time, I decided to do some light preprocessing in Python.&lt;/p&gt;
&lt;p&gt;Next, let’s talk about data sizes. The size of the original netCDF data for one timestamp was about 4 MB. The size of the preprocessed data in JSON format was considerably larger: almost 50 MB. For climate scientists this is nothing, but for smoothly running a website that’s quite substantial… It might be worthwhile to explore which file formats work well for both languages.&lt;/p&gt;
&lt;p&gt;So what about the tile solutions from earlier? Could that save me some bandwidth and rendering time? And how hard could it be to make my own tiles in Python? As you could see from the first Leaflet example, it’s just a matter of creating a folder structure like &lt;code&gt;baseurl/{z}/{x}/{y}.png&lt;/code&gt;, where the tile numbering follows the slippy tile format explained &lt;a href=&quot;https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;224&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-c3fb61ab.CgVRjSqu_ZI443P.webp&quot; srcset=&quot;&quot;&gt;
Example tiles at zoom levels 0 (left), 1 (middles) and 2 (right).To draw a tile we basically have to determine the right colour for each pixel. I already mentioned that the tiles are 256x256 pixels. My sample data is 1440x721 grid cells. Therefore, to create the first tile that covers the globe, we need to condense, or &lt;em&gt;aggregate&lt;/em&gt;, the data. We have 5 to 6 grid cells per pixel in the &lt;em&gt;x&lt;/em&gt;-direction and about 3 in the &lt;em&gt;y&lt;/em&gt;-direction. The simplest way to aggregate them would be to take the mean of these ~15 grid cells. (At higher zoom levels, where we have more pixels than grid cells, we’d need to upsample, or *interpolate *instead). Then we’d have to map the values of temperature onto a colour scale. Finally, we’d draw the pixels on a canvas.&lt;/p&gt;
&lt;p&gt;There happens to be a Python library that is built to do exactly this: &lt;a href=&quot;https://datashader.org/&quot;&gt;Datashader&lt;/a&gt;. While it’s intended for use from within a Python session, there is no reason why you couldn’t use that library to render images upfront. The developers of the package also &lt;a href=&quot;https://github.com/holoviz/datashader/issues/246&quot;&gt;realized this&lt;/a&gt; and created an initial implementation to render tiles with a somewhat hidden &lt;a href=&quot;https://github.com/holoviz/datashader/blob/master/examples/tiling.ipynb&quot;&gt;example notebook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I adapted the example to my needs and started rendering some tiles. In terms of storage, the first 4 zoom levels (0 to 3) were all below 1 MB. Then it quickly went up from 2.4 MB to 6.8 MB to 22 MB for levels 4 through 6. Performance started to degrade at zoom level 6, perhaps because of the upsampling that was going on. At zoom level 7, my code crashed, though I’m sure it can still be optimized.&lt;/p&gt;
&lt;p&gt;Now it was time to show my awesome tile layer on a Leaflet map. I struggled a bit to get the projection right, but eventually, it worked like a charm (select the tile layer on the leaflet map &lt;a href=&quot;https://peter9192.github.io/webmaps/&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;688&quot; height=&quot;469&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-a8fb1070.BqhSHahB_gq65k.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://xkcd.com/2256&quot;&gt;https://xkcd.com/2256&lt;/a&gt;I was happy that my tile layer worked, but it also got me thinking: zoom level 0 seemed quite redundant: why would anyone want to show the whole globe on a tiny thumbnail? The tile layer only starts to be advantageous at the higher zoom levels. But do I really need that? Indeed, with the source data resolution of 0.25 degrees, there might not be much to gain beyond zoom level 3. Consequently, for a global dataset at this resolution, an image overlay might be a better, and easier, solution.&lt;/p&gt;
&lt;p&gt;After tinkering a bit with how to reproject and save the file, I managed to create an image with just as many pixels as I had grid cells, and project it onto my Leaflet map (select the image layer &lt;a href=&quot;https://peter9192.github.io/webmaps/&quot;&gt;here&lt;/a&gt;). The image size was under 400 KB and it rendered nicely onto the map. Maybe even too nicely: at higher zoom levels, Leaflet did a great job at smoothing the edges between the original pixels, and although this provided a nice looking image, I did not like it. For scientific applications, it is more honest to show the coarse pixels of the source data. In that sense, the polygon solution was much better.&lt;/p&gt;
&lt;h2 id=&quot;not-so-bad-after-all&quot;&gt;Not so bad after all?&lt;/h2&gt;
&lt;p&gt;So let’s do a quick resume. To plot data on a web map, we have several options. For relatively coarse datasets, creating an image overlay seems to be a good option, although you might lose the explicit granularity of the source data. Tile layers will be useful mostly when you go to a much higher resolution (whilst keeping a large domain). Both these options require pre-rendering of the images/tiles, which means that the colour bar will be fixed and the connection with the source data is lost.&lt;/p&gt;
&lt;p&gt;Alternatively, rendering the data client-side is also within reach, especially with tools like deck.gl. In my experiments, it required fetching and processing substantial amounts of data, but this can be amended. Similar to the pre-rendered raster tiles I’ve explored, &lt;a href=&quot;https://en.wikipedia.org/wiki/Vector_tiles&quot;&gt;vector tiles&lt;/a&gt; have become increasingly popular. This could be a good solution when you have (much) more pixels than grid cells, whereas raster tiles work well in the opposite situation. The preferred option is thus determined by the source data resolution, and the zoom levels you want to support.&lt;/p&gt;
&lt;p&gt;Finally, let’s look back at the very first figure I showed. It was made with the &lt;a href=&quot;https://hvplot.holoviz.org/&quot;&gt;hvPlot&lt;/a&gt; library, which is built on top of &lt;a href=&quot;https://holoviews.org/&quot;&gt;HoloViews&lt;/a&gt;, which in turn uses &lt;a href=&quot;https://docs.bokeh.org/en/latest/&quot;&gt;Bokeh&lt;/a&gt;. I also used &lt;a href=&quot;https://panel.holoviz.org/index.html&quot;&gt;Panel&lt;/a&gt; for exporting the file. Bokeh consists of two components: BokehJS for creating interactive visualizations with Javascript, and the Python library, which makes it easy to ‘define’ visualizations that are understood by the Javascript counterpart. Simply put, these &lt;em&gt;definitions&lt;/em&gt; are just listings of the different plot elements that constitute the visualization. When you export a visualization as a static file, all possible ‘states’ (in my case the four seasons) are written to the output file(s), alongside the definition. Depending on the plot type, the state may consist of some data, or perhaps an encoded image. At that point, BokehJS can read the definition and state data and reconstruct the visualization.&lt;/p&gt;
&lt;p&gt;It is a great solution if you are happy with the possibilities offered by Bokeh and the libraries that are built on top of it. Personally, I’m not so keen on the “you worry about the science, we worry about the implementation” attitude that some of the high-level visualization packages sometimes tend to preach. I think it’s important to have a basic understanding of what’s going on under the hood. And while the BokehJS library seems to be quite good at what it does, I’d like it even better when the exchange formats between Python and Javascript were more interoperable.&lt;/p&gt;
&lt;p&gt;Anyway, now that I’m starting to grasp the core principles and challenges, I’ve come to appreciate how far they have come, and I look forward to seeing how this exciting visualization landscape will develop in the near future. This exploration has been a valuable learning experience for me, and I hope it may help some of the readers as well.&lt;/p&gt;
&lt;p&gt;Happy mapping!&lt;/p&gt;</description><pubDate>Mon, 20 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;But what if you want to plot your own data? While there are many resources on how to use existing tile or web-map services, I struggled to find out how to make my own. Eventually, I found a &lt;a href=&quot;https://www.azavea.com/blog/2018/08/06/generating-pyramided-tiles-from-a-geotiff-using-geotrellis/&quot;&gt;nice example&lt;/a&gt; using &lt;a href=&quot;https://geotrellis.readthedocs.io/en/latest/&quot;&gt;GeoTrellis&lt;/a&gt;, but by that time I had already concocted a half-baked solution in my beloved Python. More on that in a bit.&lt;/p&gt;
&lt;p&gt;Leaflet also has different kinds of layers. You can draw lines, markers, shapes, polygons, images, and even videos. Here’s how to draw a simple rectangle on a Leaflet map:&lt;/p&gt;
&lt;p&gt;var bounds = [[50, 0], [55, 5]]  // ymin xmin ymax xmax
L.rectangle(bounds, {color: “#ffffff”, weight: 1}).addTo(map);So if I could load my data into some that bounds array and write a function to determine the colours, that should work. Right?&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://blog.scottlogic.com/2020/05/01/rendering-one-million-points-with-d3.html&quot;&gt;this blogpost&lt;/a&gt;, Leaflet should perform well up to about ten thousand data points. However, gridded data can easily get bigger. The snapshot of ERA5 data that I used for the first example already has over a million grid cells (0.25 by 0.25 degrees, global coverage). So it seems we’re hitting a dead end there as well… Or not?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deck.gl/&quot;&gt;deck.gl&lt;/a&gt; is like Leaflet on steroids. It was designed to “visually explore large-scale datasets”. It leverages the processing power of your graphics card to do some impressive rendering magic. After using Leaflet, I found it quite easy to get up and running with deck.gl, and managed to produce this awesome visualization:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;612&quot; height=&quot;432&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-7102366f.CCo91M-J_WnkMk.webp&quot; srcset=&quot;&quot;&gt;
Rendering over a million grid cells using deck.glBut still, I had to cheat a bit. And still, it was slow. For the data… was big.&lt;/p&gt;
&lt;h2 id=&quot;incentives-for-a-hybrid-solution&quot;&gt;Incentives for a hybrid solution&lt;/h2&gt;
&lt;p&gt;The data I wanted to use came originally in netCDF format and while it seems possible* nowadays to parse that with Javascript, it’s not the oneliner I’m used to in Python. The same goes for the colour mapping. To save me some time, I decided to do some light preprocessing in Python.&lt;/p&gt;
&lt;p&gt;Next, let’s talk about data sizes. The size of the original netCDF data for one timestamp was about 4 MB. The size of the preprocessed data in JSON format was considerably larger: almost 50 MB. For climate scientists this is nothing, but for smoothly running a website that’s quite substantial… It might be worthwhile to explore which file formats work well for both languages.&lt;/p&gt;
&lt;p&gt;So what about the tile solutions from earlier? Could that save me some bandwidth and rendering time? And how hard could it be to make my own tiles in Python? As you could see from the first Leaflet example, it’s just a matter of creating a folder structure like &lt;code&gt;baseurl/{z}/{x}/{y}.png&lt;/code&gt;, where the tile numbering follows the slippy tile format explained &lt;a href=&quot;https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;224&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-c3fb61ab.CgVRjSqu_ZI443P.webp&quot; srcset=&quot;&quot;&gt;
Example tiles at zoom levels 0 (left), 1 (middles) and 2 (right).To draw a tile we basically have to determine the right colour for each pixel. I already mentioned that the tiles are 256x256 pixels. My sample data is 1440x721 grid cells. Therefore, to create the first tile that covers the globe, we need to condense, or &lt;em&gt;aggregate&lt;/em&gt;, the data. We have 5 to 6 grid cells per pixel in the &lt;em&gt;x&lt;/em&gt;-direction and about 3 in the &lt;em&gt;y&lt;/em&gt;-direction. The simplest way to aggregate them would be to take the mean of these ~15 grid cells. (At higher zoom levels, where we have more pixels than grid cells, we’d need to upsample, or *interpolate *instead). Then we’d have to map the values of temperature onto a colour scale. Finally, we’d draw the pixels on a canvas.&lt;/p&gt;
&lt;p&gt;There happens to be a Python library that is built to do exactly this: &lt;a href=&quot;https://datashader.org/&quot;&gt;Datashader&lt;/a&gt;. While it’s intended for use from within a Python session, there is no reason why you couldn’t use that library to render images upfront. The developers of the package also &lt;a href=&quot;https://github.com/holoviz/datashader/issues/246&quot;&gt;realized this&lt;/a&gt; and created an initial implementation to render tiles with a somewhat hidden &lt;a href=&quot;https://github.com/holoviz/datashader/blob/master/examples/tiling.ipynb&quot;&gt;example notebook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I adapted the example to my needs and started rendering some tiles. In terms of storage, the first 4 zoom levels (0 to 3) were all below 1 MB. Then it quickly went up from 2.4 MB to 6.8 MB to 22 MB for levels 4 through 6. Performance started to degrade at zoom level 6, perhaps because of the upsampling that was going on. At zoom level 7, my code crashed, though I’m sure it can still be optimized.&lt;/p&gt;
&lt;p&gt;Now it was time to show my awesome tile layer on a Leaflet map. I struggled a bit to get the projection right, but eventually, it worked like a charm (select the tile layer on the leaflet map &lt;a href=&quot;https://peter9192.github.io/webmaps/&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Plotting gridded data on a web map: Python and/or Javascript?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;688&quot; height=&quot;469&quot; src=&quot;https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-a8fb1070.BqhSHahB_gq65k.webp&quot; srcset=&quot;&quot;&gt;
&lt;a href=&quot;https://xkcd.com/2256&quot;&gt;https://xkcd.com/2256&lt;/a&gt;I was happy that my tile layer worked, but it also got me thinking: zoom level 0 seemed quite redundant: why would anyone want to show the whole globe on a tiny thumbnail? The tile layer only starts to be advantageous at the higher zoom levels. But do I really need that? Indeed, with the source data resolution of 0.25 degrees, there might not be much to gain beyond zoom level 3. Consequently, for a global dataset at this resolution, an image overlay might be a better, and easier, solution.&lt;/p&gt;
&lt;p&gt;After tinkering a bit with how to reproject and save the file, I managed to create an image with just as many pixels as I had grid cells, and project it onto my Leaflet map (select the image layer &lt;a href=&quot;https://peter9192.github.io/webmaps/&quot;&gt;here&lt;/a&gt;). The image size was under 400 KB and it rendered nicely onto the map. Maybe even too nicely: at higher zoom levels, Leaflet did a great job at smoothing the edges between the original pixels, and although this provided a nice looking image, I did not like it. For scientific applications, it is more honest to show the coarse pixels of the source data. In that sense, the polygon solution was much better.&lt;/p&gt;
&lt;h2 id=&quot;not-so-bad-after-all&quot;&gt;Not so bad after all?&lt;/h2&gt;
&lt;p&gt;So let’s do a quick resume. To plot data on a web map, we have several options. For relatively coarse datasets, creating an image overlay seems to be a good option, although you might lose the explicit granularity of the source data. Tile layers will be useful mostly when you go to a much higher resolution (whilst keeping a large domain). Both these options require pre-rendering of the images/tiles, which means that the colour bar will be fixed and the connection with the source data is lost.&lt;/p&gt;
&lt;p&gt;Alternatively, rendering the data client-side is also within reach, especially with tools like deck.gl. In my experiments, it required fetching and processing substantial amounts of data, but this can be amended. Similar to the pre-rendered raster tiles I’ve explored, &lt;a href=&quot;https://en.wikipedia.org/wiki/Vector_tiles&quot;&gt;vector tiles&lt;/a&gt; have become increasingly popular. This could be a good solution when you have (much) more pixels than grid cells, whereas raster tiles work well in the opposite situation. The preferred option is thus determined by the source data resolution, and the zoom levels you want to support.&lt;/p&gt;
&lt;p&gt;Finally, let’s look back at the very first figure I showed. It was made with the &lt;a href=&quot;https://hvplot.holoviz.org/&quot;&gt;hvPlot&lt;/a&gt; library, which is built on top of &lt;a href=&quot;https://holoviews.org/&quot;&gt;HoloViews&lt;/a&gt;, which in turn uses &lt;a href=&quot;https://docs.bokeh.org/en/latest/&quot;&gt;Bokeh&lt;/a&gt;. I also used &lt;a href=&quot;https://panel.holoviz.org/index.html&quot;&gt;Panel&lt;/a&gt; for exporting the file. Bokeh consists of two components: BokehJS for creating interactive visualizations with Javascript, and the Python library, which makes it easy to ‘define’ visualizations that are understood by the Javascript counterpart. Simply put, these &lt;em&gt;definitions&lt;/em&gt; are just listings of the different plot elements that constitute the visualization. When you export a visualization as a static file, all possible ‘states’ (in my case the four seasons) are written to the output file(s), alongside the definition. Depending on the plot type, the state may consist of some data, or perhaps an encoded image. At that point, BokehJS can read the definition and state data and reconstruct the visualization.&lt;/p&gt;
&lt;p&gt;It is a great solution if you are happy with the possibilities offered by Bokeh and the libraries that are built on top of it. Personally, I’m not so keen on the “you worry about the science, we worry about the implementation” attitude that some of the high-level visualization packages sometimes tend to preach. I think it’s important to have a basic understanding of what’s going on under the hood. And while the BokehJS library seems to be quite good at what it does, I’d like it even better when the exchange formats between Python and Javascript were more interoperable.&lt;/p&gt;
&lt;p&gt;Anyway, now that I’m starting to grasp the core principles and challenges, I’ve come to appreciate how far they have come, and I look forward to seeing how this exciting visualization landscape will develop in the near future. This exploration has been a valuable learning experience for me, and I hope it may help some of the readers as well.&lt;/p&gt;
&lt;p&gt;Happy mapping!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/plotting-gridded-data-on-a-web-map-pytho-7102366f.CCo91M-J.png" medium="image"/><author>Peter Kalverla</author></item><item><title>Literate Programming in Science</title><link>https://blog.esciencecenter.nl/posts/2021-07-07---literate-programming-in-science</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-07-07---literate-programming-in-science</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;2768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_3ke-o36ZPmah-PK4-a8e3aba4.Csxfd0Dk_1vb839.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Prateek Katyal on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;2-the-how&quot;&gt;2. The How&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is part 2 in a series on Literate Programming in Science. If you haven’t yet,&lt;/em&gt; &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;&lt;em&gt;please read part 1 “The Why”&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Literate programming&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;/ˈlɪtəɹət ˈpɹəʊɡɹæmɪŋ/ (computing) Literate programming is a programming paradigm introduced by Donald Knuth in which a program is given as an explanation of the program logic in a natural language, such as English, interspersed with snippets of macros and traditional source code, from which a compilable source code can be generated.&lt;/em&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Literate_programming&quot;&gt;&lt;em&gt;Wikipedia&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’re reading this, then I hope I’ve convinced you (or maybe you didn’t need convincing) of the necessity of Literate Programming in Science. The next question should be: where do I start? I will discuss three methods of Literate Programming that you can use today, their upsides and downsides, what-have-you-not.&lt;/p&gt;
&lt;p&gt;First, I should explain some nomenclature surrounding the concept of Literate Programming. The idea is that you write documentation first, interspersed with code blocks that actually implement the described ideas. These code blocks can be named and referenced from other code blocks using a system of references called &lt;em&gt;Noweb&lt;/em&gt;. A special program is needed to extract all the code blocks from the markup and put them in the right order so that a well formed program code emerges on the other end: a process known as &lt;em&gt;tangling&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A literate form of “Hello, World” in C++ would look something like this:&lt;/p&gt;
&lt;h2 id=&quot;hello-world&quot;&gt;Hello World&lt;/h2&gt;
&lt;p&gt;This example is written in a style of &lt;em&gt;literate programming&lt;/em&gt; (Knuth 1984). The combined code-blocks in this example compose a compilable source code for “Hello World”. For didactic reasons we don’t always give the listing of an entire source file in one go. In stead, we use a system of references known as &lt;em&gt;noweb&lt;/em&gt; (Ramsey 1994).&lt;/p&gt;
&lt;p&gt;Inside source fragments you may encounter a line with &lt;code&gt;&amp;#x3C;&amp;#x3C;...&gt;&gt;&lt;/code&gt; marks like,&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«hello_world.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#include &amp;#x3C;cstdlib&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#include &amp;#x3C;iostream&gt;&amp;#x3C;&amp;#x3C;example-main-function&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is then elsewhere specified. Order doesn’t matter,&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Hello, World!&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;endl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we can reference the &lt;code&gt;&amp;#x3C;&amp;#x3C;print-message&gt;&gt;&lt;/code&gt; code block later on.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«example&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(int argc, char &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;argv) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &amp;#x3C;&amp;#x3C;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A definition can be appended with more code as follows (in this case, order does matter!):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; EXIT_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These blocks of code can be &lt;em&gt;tangled&lt;/em&gt; into source files, in this case a single &lt;code&gt;hello_world.cc&lt;/code&gt; would emerge.&lt;/p&gt;
&lt;p&gt;This “Hello World” shows just how you can combine the contents of code blocks to create a fully functional “Hello World” in C++. More examples of this type of literate programs can be found on the &lt;a href=&quot;https://entangled.github.io/examples&quot;&gt;Entangled website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Noweb method of literate programming is not the only way to mix documentation with code. Not all methods described here have all the features that you would expect from Knuth’s original invention. In fact the most popular incarnation of Literate Programming arguably is that of notebooks. We may judge each method by their ease of use, and if they fit the bill of generating publishable and reproducible scholarly products.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_E5I_DM8KaxUxkDNf-4dd728e6.D3u-ChMJ_WHtXW.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by NASA on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;notebooks-in-particular-jupyter&quot;&gt;Notebooks (in particular Jupyter)&lt;/h2&gt;
&lt;p&gt;The most common form of Literate Programming found in todays jungle of digitized science is the &lt;em&gt;notebook&lt;/em&gt;. Personally my first encounter with notebooks was with the use of Mathematica, which featured notebooks as early as 1988. Many commercial packages for data analytics and modelling featured notebook interfaces long before the rise of &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebooks&lt;/a&gt; in 2014. What makes Jupyter special is that it is an open source solution for many different languages (as long as someone took the effort of writing a Jupyter kernel for it).&lt;/p&gt;
&lt;h3 id=&quot;pros&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic evaluation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy sharing&lt;/strong&gt; with MyBinder or related tools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language agnostic (in theory)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No support for Noweb references or tangling&lt;/strong&gt;: the code is evaluated in any possible order, depending on user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only really meant for end-of-line products&lt;/strong&gt;: it is not expected that you write a Python library in a Jupyter notebook that someone else can import. It can be done in the case of Python (&lt;a href=&quot;https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Importing%20Notebooks.html&quot;&gt;see Jupyter docs&lt;/a&gt;), but just reading the documentation should instill a deep feeling that you really shouldn’t.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only works for evaluated languages&lt;/strong&gt;: because notebook interfaces are designed to be interactive, they are fundamentally limited to languages that provide a Read-Evaluate-Print loop (or REPL for short). Examples of languages that don’t have this are Java, Rust, Go (I would like to include C++ here, but there is Cling, the complexity of which is an argument against itself). In the case of Haskell we do have a REPL, but it doesn’t expose the full language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crappy text editor&lt;/strong&gt;: With Jupyter you’re stuck with the default inline text editor of Jupyter. If you use VSCode, you can edit notebooks directly from there, but the interface is still quite slow and buggy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to debug&lt;/strong&gt;: The latest version of Jupyter has a debugger for Python, I’m not sure if this debugger translates well to other languages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No stable API&lt;/strong&gt;: This is not a principal argument, but a practical one. The Jupyter API changes often. As a consequence, the only kernel that can be expected to always work is the Python one. I’ve experienced frequent breaks when using Jupyter, even in the relatively common case of GNU R. For most other languages, sadly, chances are that you will have to experiment with downgrading Jupyter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stored in JSON&lt;/strong&gt;: the contents of the notebook are stored in JSON, even opening a notebook changes its contents. This is especially annoying when working with &lt;strong&gt;git&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these downsides may lessen or disappear entirely as Jupyter improves. The first three however are rather fundamental to the method. That is no critique. I love working with Jupyter and use it every day. It just isn’t for everything.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VXW1HQh6uiOo2ftU-cef2e6ae.DJrS2SNb_ZjiOkz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Margarida Afonso on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;rmarkdown-and-knitr-with-rstudio&quot;&gt;RMarkdown and Knitr (with RStudio)&lt;/h2&gt;
&lt;p&gt;RMarkdown was designed as the Literate Programming solution for R, with a focus on reproducibility. As the name suggests, it is a dialect of the markdown language.&lt;/p&gt;
&lt;p&gt;Contrary to Jupyter, RMarkdown is more focused on creating high-quality documents than on interactivity, making it a perfect choice for writing vignettes, reports and even academic papers.&lt;/p&gt;
&lt;p&gt;RMarkdown is particularly easy to learn and to use from RStudio. Nowadays it supports several languages apart from R, such as Python or SQL.&lt;/p&gt;
&lt;h3 id=&quot;pros-1&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easy to install:&lt;/strong&gt; (comes by default with RStudio)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic evaluation:&lt;/strong&gt; only if desired.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy interface&lt;/strong&gt;: RMarkdown is very accessible to new users through the RStudio interface, but it is possible to use it outside RStudio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy sharing:&lt;/strong&gt; with RPubs, MyBinder or related tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plain text:&lt;/strong&gt; Well defined plain-text format, in this case Markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fixed order of evaluation:&lt;/strong&gt; The code is evaluated sequentially by default. Other than with Jupyter, where the order of execution depends on user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language agnostic (in theory):&lt;/strong&gt; many languages are supported through the &lt;em&gt;Knitr engine&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Fancy functionalities are constantly added by the R community, such as caching for long calculations, support for different languages, cross-referencing, templates, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-1&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No support for Noweb references or tangling&lt;/strong&gt;: the code is evaluated in the order that you enter it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-of-line:&lt;/strong&gt; It is not expected that you write an R package in a RMarkdown file that someone else can import. Usually, the RMarkdown files are an addition to a package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to debug&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language centric:&lt;/strong&gt; The integration with languages other than R happens through R packages. Most of these packages are quite well designed and just work out-of-the-box, but for some of them you may need to invest learning how they work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just as Jupyter, RMarkdown is a great tool to get started with Literate Programming. It stops just shy of being able to create fully compilable files from the literate sources.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1333&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_1arvThu4tV8Y4Zuy-effb0a2b.CzqIefJ__1ILJbA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Brigitta Schneiter on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;emacs-org-mode&quot;&gt;Emacs org-mode&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://orgmode.org/&quot;&gt;Org-mode&lt;/a&gt; is not terribly well known, it offers one of the most complete solutions for Literate Programming that you can find. Me myself, I’m a born Vim user. Every now and then I take these editor excursions: VSCode lasted a week before I went back screaming for Vim. For this single feature of Org-mode I nearly switched to Emacs. I tried &lt;a href=&quot;https://spacemacs.org/&quot;&gt;SpaceMacs&lt;/a&gt; for about &lt;em&gt;half a year&lt;/em&gt; until reverting back to Vim. &lt;em&gt;That is how good Org-mode is (26x all of VSCode if you can count).&lt;/em&gt; Many adepts describe it as a life changer.&lt;/p&gt;
&lt;p&gt;In essence Org-mode is an editor mode that helps you edit nestings of unordered lists, it’s main use being for brainstorming and keeping todo lists. From these humble beginings sprouted a markup language that, entirely in the Emacs tradition, includes everything and the kitchen sink (did I mention the spreadsheet?). Today Org-mode could be considered a variant on other markup languages like Markdown and reStructured Text. What makes Org-mode special is the way you can edit and interact with it inside Emacs.&lt;/p&gt;
&lt;p&gt;One of the many features of Org-mode is that it supports code-blocks &lt;em&gt;with noweb references&lt;/em&gt;. These code-blocks can be evaluated inline (using one of many plugins available for Emacs) or tangled to runnable/compilable source files.&lt;/p&gt;
&lt;h3 id=&quot;pros-2&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Supports noweb and tangling.&lt;/li&gt;
&lt;li&gt;Well defined plain-text format.&lt;/li&gt;
&lt;li&gt;Export to nearly anything.&lt;/li&gt;
&lt;li&gt;Dynamic evaluation of code blocks.&lt;/li&gt;
&lt;li&gt;Completely language agnostic.&lt;/li&gt;
&lt;li&gt;Plain text markup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-2&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Only works as intended in &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Collaborators would have to use &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Debugging should be done from &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In its own way Emacs is awesome. If this fits the bill for you, by all means shape your life around it, join the church. I do believe however, that this is not something you can force onto someone else.&lt;/p&gt;
&lt;p&gt;What all the previous methods share is that they drive you into using a chosen set of tools, each with its own particular down sides. What I am aiming for is a method of Literate Programming that is feature complete and &lt;em&gt;minimally intrusive&lt;/em&gt;. Feature completeness is always a matter of personal taste, nevertheless I will give it a shot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deconstruct code using Noweb syntax, or something very close to it.&lt;/li&gt;
&lt;li&gt;Be completely language agnostic.&lt;/li&gt;
&lt;li&gt;Export to nearly everything.&lt;/li&gt;
&lt;li&gt;Use a plain-text markup format.&lt;/li&gt;
&lt;li&gt;Play nicely with existing methods for publishing on the web.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One thing I didn’t include in there is the feature of dynamic evaluation. Such a thing could be achieved in a generic way by implementing editor plug-ins on top of the &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/&quot;&gt;Language Server Protocol&lt;/a&gt; (using a code action of some kind). Implementing an Org-mode kind of interaction in this way would be a very interesting project onto itself, but not today.&lt;/p&gt;
&lt;p&gt;Instead, I introduce a new feature that none of the other methods have: the ability to work on tangled source code while keeping the original markup synchronized. This feature greatly improves the maintainability of the literate program while also opening up all the normal tools you’re used to work with: debuggers, linters, transmogrifiers, you name it. Let’s call this feature: &lt;strong&gt;live untangle mode&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-entangled-project&quot;&gt;The Entangled Project&lt;/h2&gt;
&lt;p&gt;I hope by now I have convinced you that A. Literate Programming is awesome and B. the current set of available tools are not sufficient. This is why I started &lt;a href=&quot;https://entangled.github.io/&quot;&gt;the Entangled project&lt;/a&gt;. The goals of the Entangled Project are three-fold:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Develop tools for Literate Programming&lt;/li&gt;
&lt;li&gt;Arrive at a set of best practices&lt;/li&gt;
&lt;li&gt;Communicate, teach and promote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The push for these methods and best practices focusses on a system using &lt;em&gt;Markdown&lt;/em&gt; as the primary markup language. I believe Markdown offers the ideal combination of readability and flexibility to suit most needs, a stance that I previously defended in a blog post: &lt;a href=&quot;https://blog.esciencecenter.nl/why-all-youll-ever-need-is-markdown-dc604f0ab309&quot;&gt;Why all you’ll ever need is Markdown&lt;/a&gt;. This does not mean that the choice for Markdown is final; all of what we do carries over without problems to other formats.&lt;/p&gt;
&lt;h3 id=&quot;tools&quot;&gt;Tools&lt;/h3&gt;
&lt;p&gt;The primary tool we have developed is Entangled. This is a daemon that runs while you edit the markup files or the tangled sources. Entangled keeps the two in sync so that you only ever have one version of the code.&lt;/p&gt;
&lt;p&gt;Next to this core tool we have several experimental filters for &lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc, the universal document converter.&lt;/a&gt; These filters can do several things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Annotate generated output with headings for the named code fragments.&lt;/li&gt;
&lt;li&gt;Evaluate code fragments by passing them through Jupyter.&lt;/li&gt;
&lt;li&gt;Inject Javascript code fragments into the HTML output for interactive elements (e.g. PlotLy).&lt;/li&gt;
&lt;li&gt;Generate Bootstrap UI elements, for example: foldable code blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The approach we take to Literate Programming has been battle tested using three different document converters: Pandoc, MkDocs and Docsify. Each generator works with a slightly different dialect of Markdown.&lt;/p&gt;
&lt;h3 id=&quot;future-plans&quot;&gt;Future plans&lt;/h3&gt;
&lt;p&gt;Entangled is ready to use, but it is not too user friendly yet. For one, we expect you to setup your own pipeline for building the document for public release. Most often this would be some static HTML generator using Pandoc or MkDocs. Alternatively you can use Docsify to serve a website directly from the Markdown sources.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Getting started:&lt;/strong&gt; The problem for entry level users is that it may not be trivial to set these up. The current template for working with Pandoc requires Pandoc (duh), GNU Make, browser-sync, some form of inotify-wait, and of course, Entangled. We’d like to make it much easier to start working on your own projects, so we’d like to bring this set of requirements back to just Entangled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Templates:&lt;/strong&gt; We should provide easy to use starting templates for a set of popular document generators. The one currently still unmentioned being Sphinx. These templates should be initialized using an &lt;code&gt;entangled init&lt;/code&gt; sub-command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single file mode&lt;/strong&gt;: The default operation of Entangled should be a single file mode (most probably &lt;code&gt;README.md&lt;/code&gt;), and work out of the box with no configuration. Imagine a Github repository with just a &lt;code&gt;README&lt;/code&gt; (and a &lt;code&gt;LICENSE&lt;/code&gt; and a &lt;code&gt;CITATION.cff&lt;/code&gt; and a &lt;code&gt;.editorconfig&lt;/code&gt; and a … oh you get the point!) and a Github Action tacked on to generate the Github.io pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible code presentation:&lt;/strong&gt; in the publicized output code cells are currently static. At the very least Noweb references should be clickable. Other features could include: links to the tangled output, be able to view the code in expanded form.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Help is appreciated! Entangled is primarily developed in Haskell, though no skill in Haskell is required for example to create templates for working with Entangled. Pandoc filters can be developed in Python. In particular the filter for interacting with Jupyter could use some fresh ideas.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;About the author: I’m (among other things) the developer of&lt;/em&gt; &lt;a href=&quot;https://entangled.github.io/&quot;&gt;&lt;em&gt;Entangled, a Literate Programming framework and toolset&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. The main goal of this blog-post is to convince you that existing tools for Literate Programming are not yet ready to serve the needs of the broader scientific community.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Wed, 07 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;2768&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_3ke-o36ZPmah-PK4-a8e3aba4.Csxfd0Dk_1vb839.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Prateek Katyal on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;2-the-how&quot;&gt;2. The How&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is part 2 in a series on Literate Programming in Science. If you haven’t yet,&lt;/em&gt; &lt;a href=&quot;https://blog.esciencecenter.nl/literate-programming-in-science-1669094541a7&quot;&gt;&lt;em&gt;please read part 1 “The Why”&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Literate programming&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;/ˈlɪtəɹət ˈpɹəʊɡɹæmɪŋ/ (computing) Literate programming is a programming paradigm introduced by Donald Knuth in which a program is given as an explanation of the program logic in a natural language, such as English, interspersed with snippets of macros and traditional source code, from which a compilable source code can be generated.&lt;/em&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Literate_programming&quot;&gt;&lt;em&gt;Wikipedia&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’re reading this, then I hope I’ve convinced you (or maybe you didn’t need convincing) of the necessity of Literate Programming in Science. The next question should be: where do I start? I will discuss three methods of Literate Programming that you can use today, their upsides and downsides, what-have-you-not.&lt;/p&gt;
&lt;p&gt;First, I should explain some nomenclature surrounding the concept of Literate Programming. The idea is that you write documentation first, interspersed with code blocks that actually implement the described ideas. These code blocks can be named and referenced from other code blocks using a system of references called &lt;em&gt;Noweb&lt;/em&gt;. A special program is needed to extract all the code blocks from the markup and put them in the right order so that a well formed program code emerges on the other end: a process known as &lt;em&gt;tangling&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A literate form of “Hello, World” in C++ would look something like this:&lt;/p&gt;
&lt;h2 id=&quot;hello-world&quot;&gt;Hello World&lt;/h2&gt;
&lt;p&gt;This example is written in a style of &lt;em&gt;literate programming&lt;/em&gt; (Knuth 1984). The combined code-blocks in this example compose a compilable source code for “Hello World”. For didactic reasons we don’t always give the listing of an entire source file in one go. In stead, we use a system of references known as &lt;em&gt;noweb&lt;/em&gt; (Ramsey 1994).&lt;/p&gt;
&lt;p&gt;Inside source fragments you may encounter a line with &lt;code&gt;&amp;#x3C;&amp;#x3C;...&gt;&gt;&lt;/code&gt; marks like,&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«hello_world.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#include &amp;#x3C;cstdlib&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#include &amp;#x3C;iostream&gt;&amp;#x3C;&amp;#x3C;example-main-function&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is then elsewhere specified. Order doesn’t matter,&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Hello, World!&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;endl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we can reference the &lt;code&gt;&amp;#x3C;&amp;#x3C;print-message&gt;&gt;&lt;/code&gt; code block later on.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«example&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;function»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(int argc, char &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;argv) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &amp;#x3C;&amp;#x3C;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A definition can be appended with more code as follows (in this case, order does matter!):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;«&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;message»&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; EXIT_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These blocks of code can be &lt;em&gt;tangled&lt;/em&gt; into source files, in this case a single &lt;code&gt;hello_world.cc&lt;/code&gt; would emerge.&lt;/p&gt;
&lt;p&gt;This “Hello World” shows just how you can combine the contents of code blocks to create a fully functional “Hello World” in C++. More examples of this type of literate programs can be found on the &lt;a href=&quot;https://entangled.github.io/examples&quot;&gt;Entangled website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Noweb method of literate programming is not the only way to mix documentation with code. Not all methods described here have all the features that you would expect from Knuth’s original invention. In fact the most popular incarnation of Literate Programming arguably is that of notebooks. We may judge each method by their ease of use, and if they fit the bill of generating publishable and reproducible scholarly products.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1499&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_E5I_DM8KaxUxkDNf-4dd728e6.D3u-ChMJ_WHtXW.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by NASA on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;notebooks-in-particular-jupyter&quot;&gt;Notebooks (in particular Jupyter)&lt;/h2&gt;
&lt;p&gt;The most common form of Literate Programming found in todays jungle of digitized science is the &lt;em&gt;notebook&lt;/em&gt;. Personally my first encounter with notebooks was with the use of Mathematica, which featured notebooks as early as 1988. Many commercial packages for data analytics and modelling featured notebook interfaces long before the rise of &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter notebooks&lt;/a&gt; in 2014. What makes Jupyter special is that it is an open source solution for many different languages (as long as someone took the effort of writing a Jupyter kernel for it).&lt;/p&gt;
&lt;h3 id=&quot;pros&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic evaluation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy sharing&lt;/strong&gt; with MyBinder or related tools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language agnostic (in theory)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No support for Noweb references or tangling&lt;/strong&gt;: the code is evaluated in any possible order, depending on user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only really meant for end-of-line products&lt;/strong&gt;: it is not expected that you write a Python library in a Jupyter notebook that someone else can import. It can be done in the case of Python (&lt;a href=&quot;https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Importing%20Notebooks.html&quot;&gt;see Jupyter docs&lt;/a&gt;), but just reading the documentation should instill a deep feeling that you really shouldn’t.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only works for evaluated languages&lt;/strong&gt;: because notebook interfaces are designed to be interactive, they are fundamentally limited to languages that provide a Read-Evaluate-Print loop (or REPL for short). Examples of languages that don’t have this are Java, Rust, Go (I would like to include C++ here, but there is Cling, the complexity of which is an argument against itself). In the case of Haskell we do have a REPL, but it doesn’t expose the full language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crappy text editor&lt;/strong&gt;: With Jupyter you’re stuck with the default inline text editor of Jupyter. If you use VSCode, you can edit notebooks directly from there, but the interface is still quite slow and buggy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to debug&lt;/strong&gt;: The latest version of Jupyter has a debugger for Python, I’m not sure if this debugger translates well to other languages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No stable API&lt;/strong&gt;: This is not a principal argument, but a practical one. The Jupyter API changes often. As a consequence, the only kernel that can be expected to always work is the Python one. I’ve experienced frequent breaks when using Jupyter, even in the relatively common case of GNU R. For most other languages, sadly, chances are that you will have to experiment with downgrading Jupyter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stored in JSON&lt;/strong&gt;: the contents of the notebook are stored in JSON, even opening a notebook changes its contents. This is especially annoying when working with &lt;strong&gt;git&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these downsides may lessen or disappear entirely as Jupyter improves. The first three however are rather fundamental to the method. That is no critique. I love working with Jupyter and use it every day. It just isn’t for everything.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1500&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VXW1HQh6uiOo2ftU-cef2e6ae.DJrS2SNb_ZjiOkz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Margarida Afonso on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;rmarkdown-and-knitr-with-rstudio&quot;&gt;RMarkdown and Knitr (with RStudio)&lt;/h2&gt;
&lt;p&gt;RMarkdown was designed as the Literate Programming solution for R, with a focus on reproducibility. As the name suggests, it is a dialect of the markdown language.&lt;/p&gt;
&lt;p&gt;Contrary to Jupyter, RMarkdown is more focused on creating high-quality documents than on interactivity, making it a perfect choice for writing vignettes, reports and even academic papers.&lt;/p&gt;
&lt;p&gt;RMarkdown is particularly easy to learn and to use from RStudio. Nowadays it supports several languages apart from R, such as Python or SQL.&lt;/p&gt;
&lt;h3 id=&quot;pros-1&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easy to install:&lt;/strong&gt; (comes by default with RStudio)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic evaluation:&lt;/strong&gt; only if desired.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy interface&lt;/strong&gt;: RMarkdown is very accessible to new users through the RStudio interface, but it is possible to use it outside RStudio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy sharing:&lt;/strong&gt; with RPubs, MyBinder or related tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plain text:&lt;/strong&gt; Well defined plain-text format, in this case Markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fixed order of evaluation:&lt;/strong&gt; The code is evaluated sequentially by default. Other than with Jupyter, where the order of execution depends on user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language agnostic (in theory):&lt;/strong&gt; many languages are supported through the &lt;em&gt;Knitr engine&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Fancy functionalities are constantly added by the R community, such as caching for long calculations, support for different languages, cross-referencing, templates, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-1&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No support for Noweb references or tangling&lt;/strong&gt;: the code is evaluated in the order that you enter it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-of-line:&lt;/strong&gt; It is not expected that you write an R package in a RMarkdown file that someone else can import. Usually, the RMarkdown files are an addition to a package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to debug&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language centric:&lt;/strong&gt; The integration with languages other than R happens through R packages. Most of these packages are quite well designed and just work out-of-the-box, but for some of them you may need to invest learning how they work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just as Jupyter, RMarkdown is a great tool to get started with Literate Programming. It stops just shy of being able to create fully compilable files from the literate sources.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1333&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_1arvThu4tV8Y4Zuy-effb0a2b.CzqIefJ__1ILJbA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Brigitta Schneiter on Unsplash&lt;/p&gt;
&lt;h2 id=&quot;emacs-org-mode&quot;&gt;Emacs org-mode&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://orgmode.org/&quot;&gt;Org-mode&lt;/a&gt; is not terribly well known, it offers one of the most complete solutions for Literate Programming that you can find. Me myself, I’m a born Vim user. Every now and then I take these editor excursions: VSCode lasted a week before I went back screaming for Vim. For this single feature of Org-mode I nearly switched to Emacs. I tried &lt;a href=&quot;https://spacemacs.org/&quot;&gt;SpaceMacs&lt;/a&gt; for about &lt;em&gt;half a year&lt;/em&gt; until reverting back to Vim. &lt;em&gt;That is how good Org-mode is (26x all of VSCode if you can count).&lt;/em&gt; Many adepts describe it as a life changer.&lt;/p&gt;
&lt;p&gt;In essence Org-mode is an editor mode that helps you edit nestings of unordered lists, it’s main use being for brainstorming and keeping todo lists. From these humble beginings sprouted a markup language that, entirely in the Emacs tradition, includes everything and the kitchen sink (did I mention the spreadsheet?). Today Org-mode could be considered a variant on other markup languages like Markdown and reStructured Text. What makes Org-mode special is the way you can edit and interact with it inside Emacs.&lt;/p&gt;
&lt;p&gt;One of the many features of Org-mode is that it supports code-blocks &lt;em&gt;with noweb references&lt;/em&gt;. These code-blocks can be evaluated inline (using one of many plugins available for Emacs) or tangled to runnable/compilable source files.&lt;/p&gt;
&lt;h3 id=&quot;pros-2&quot;&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Supports noweb and tangling.&lt;/li&gt;
&lt;li&gt;Well defined plain-text format.&lt;/li&gt;
&lt;li&gt;Export to nearly anything.&lt;/li&gt;
&lt;li&gt;Dynamic evaluation of code blocks.&lt;/li&gt;
&lt;li&gt;Completely language agnostic.&lt;/li&gt;
&lt;li&gt;Plain text markup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-2&quot;&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Only works as intended in &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Collaborators would have to use &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Debugging should be done from &lt;strong&gt;Emacs.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In its own way Emacs is awesome. If this fits the bill for you, by all means shape your life around it, join the church. I do believe however, that this is not something you can force onto someone else.&lt;/p&gt;
&lt;p&gt;What all the previous methods share is that they drive you into using a chosen set of tools, each with its own particular down sides. What I am aiming for is a method of Literate Programming that is feature complete and &lt;em&gt;minimally intrusive&lt;/em&gt;. Feature completeness is always a matter of personal taste, nevertheless I will give it a shot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deconstruct code using Noweb syntax, or something very close to it.&lt;/li&gt;
&lt;li&gt;Be completely language agnostic.&lt;/li&gt;
&lt;li&gt;Export to nearly everything.&lt;/li&gt;
&lt;li&gt;Use a plain-text markup format.&lt;/li&gt;
&lt;li&gt;Play nicely with existing methods for publishing on the web.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One thing I didn’t include in there is the feature of dynamic evaluation. Such a thing could be achieved in a generic way by implementing editor plug-ins on top of the &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/&quot;&gt;Language Server Protocol&lt;/a&gt; (using a code action of some kind). Implementing an Org-mode kind of interaction in this way would be a very interesting project onto itself, but not today.&lt;/p&gt;
&lt;p&gt;Instead, I introduce a new feature that none of the other methods have: the ability to work on tangled source code while keeping the original markup synchronized. This feature greatly improves the maintainability of the literate program while also opening up all the normal tools you’re used to work with: debuggers, linters, transmogrifiers, you name it. Let’s call this feature: &lt;strong&gt;live untangle mode&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-entangled-project&quot;&gt;The Entangled Project&lt;/h2&gt;
&lt;p&gt;I hope by now I have convinced you that A. Literate Programming is awesome and B. the current set of available tools are not sufficient. This is why I started &lt;a href=&quot;https://entangled.github.io/&quot;&gt;the Entangled project&lt;/a&gt;. The goals of the Entangled Project are three-fold:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Develop tools for Literate Programming&lt;/li&gt;
&lt;li&gt;Arrive at a set of best practices&lt;/li&gt;
&lt;li&gt;Communicate, teach and promote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The push for these methods and best practices focusses on a system using &lt;em&gt;Markdown&lt;/em&gt; as the primary markup language. I believe Markdown offers the ideal combination of readability and flexibility to suit most needs, a stance that I previously defended in a blog post: &lt;a href=&quot;https://blog.esciencecenter.nl/why-all-youll-ever-need-is-markdown-dc604f0ab309&quot;&gt;Why all you’ll ever need is Markdown&lt;/a&gt;. This does not mean that the choice for Markdown is final; all of what we do carries over without problems to other formats.&lt;/p&gt;
&lt;h3 id=&quot;tools&quot;&gt;Tools&lt;/h3&gt;
&lt;p&gt;The primary tool we have developed is Entangled. This is a daemon that runs while you edit the markup files or the tangled sources. Entangled keeps the two in sync so that you only ever have one version of the code.&lt;/p&gt;
&lt;p&gt;Next to this core tool we have several experimental filters for &lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc, the universal document converter.&lt;/a&gt; These filters can do several things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Annotate generated output with headings for the named code fragments.&lt;/li&gt;
&lt;li&gt;Evaluate code fragments by passing them through Jupyter.&lt;/li&gt;
&lt;li&gt;Inject Javascript code fragments into the HTML output for interactive elements (e.g. PlotLy).&lt;/li&gt;
&lt;li&gt;Generate Bootstrap UI elements, for example: foldable code blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The approach we take to Literate Programming has been battle tested using three different document converters: Pandoc, MkDocs and Docsify. Each generator works with a slightly different dialect of Markdown.&lt;/p&gt;
&lt;h3 id=&quot;future-plans&quot;&gt;Future plans&lt;/h3&gt;
&lt;p&gt;Entangled is ready to use, but it is not too user friendly yet. For one, we expect you to setup your own pipeline for building the document for public release. Most often this would be some static HTML generator using Pandoc or MkDocs. Alternatively you can use Docsify to serve a website directly from the Markdown sources.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Getting started:&lt;/strong&gt; The problem for entry level users is that it may not be trivial to set these up. The current template for working with Pandoc requires Pandoc (duh), GNU Make, browser-sync, some form of inotify-wait, and of course, Entangled. We’d like to make it much easier to start working on your own projects, so we’d like to bring this set of requirements back to just Entangled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Templates:&lt;/strong&gt; We should provide easy to use starting templates for a set of popular document generators. The one currently still unmentioned being Sphinx. These templates should be initialized using an &lt;code&gt;entangled init&lt;/code&gt; sub-command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single file mode&lt;/strong&gt;: The default operation of Entangled should be a single file mode (most probably &lt;code&gt;README.md&lt;/code&gt;), and work out of the box with no configuration. Imagine a Github repository with just a &lt;code&gt;README&lt;/code&gt; (and a &lt;code&gt;LICENSE&lt;/code&gt; and a &lt;code&gt;CITATION.cff&lt;/code&gt; and a &lt;code&gt;.editorconfig&lt;/code&gt; and a … oh you get the point!) and a Github Action tacked on to generate the Github.io pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible code presentation:&lt;/strong&gt; in the publicized output code cells are currently static. At the very least Noweb references should be clickable. Other features could include: links to the tangled output, be able to view the code in expanded form.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Help is appreciated! Entangled is primarily developed in Haskell, though no skill in Haskell is required for example to create templates for working with Entangled. Pandoc filters can be developed in Python. In particular the filter for interacting with Jupyter could use some fresh ideas.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;About the author: I’m (among other things) the developer of&lt;/em&gt; &lt;a href=&quot;https://entangled.github.io/&quot;&gt;&lt;em&gt;Entangled, a Literate Programming framework and toolset&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. The main goal of this blog-post is to convince you that existing tools for Literate Programming are not yet ready to serve the needs of the broader scientific community.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_E5I_DM8KaxUxkDNf-4dd728e6.D3u-ChMJ.webp" medium="image"/><author>Johan Hidding</author></item><item><title>Visual Storytelling for data science</title><link>https://blog.esciencecenter.nl/posts/2021-06-17---visual-storytelling-for-data-science</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-06-17---visual-storytelling-for-data-science</guid><description>&lt;p&gt;][Maarten van Meersbergen]·Jun 7, 2021&lt;/p&gt;
&lt;p&gt;When conducting research, the data collected can in itself be exciting and meaningful, but when it is presented as spreadsheets or bullet points it can be too boring or difficult to understand for the intended audience. Telling a visual story with data is not trivial however, depending on the level of expertise of your readers, you should choose your storyline structure well.&lt;/p&gt;
&lt;p&gt;The excellent paper &lt;a href=&quot;https://ieeexplore.ieee.org/document/5613452&quot;&gt;Narrative Visualization: Telling Stories with Data&lt;/a&gt; by Edward Segel and Jeffrey Heer provides some good insights on this. The main takeaway from this paper I’d like to share is this:&lt;/p&gt;
&lt;p&gt;Author-driven** VS &lt;strong&gt;reader-driven&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Consider if you want to tell a ‘fixed’ story, or if you want the user to discover new stories based on the data you are providing. If telling a fixed story is what you want, an interactive slideshow would be a good option. Interactively ‘playing’ with the data on a slide-by-slide basis could build the reader’s trust in the author’s analysis, but the author’s conclusions are leading here.&lt;/p&gt;
&lt;p&gt;Interactive slideshow — Martini glass structure — Drill down story, images from &lt;a href=&quot;https://ieeexplore.ieee.org/document/5613452&quot;&gt;Narrative Visualization: Telling Stories with Data&lt;/a&gt; by Edward Segel and Jeffrey HeerIn a more reader-driven discovery scenario, more interaction is definitely needed, and a martini-glass-structure is likely a good option. Provide a ‘narrow’ authored storyline at first to explain a possible interaction with the data for tutorial purposes, and then open up options to let the user discover new stories on their own. This allows the user to learn about the possibilities without getting overwhelmed, but gives them the freedom to discover their own stories.&lt;/p&gt;
&lt;p&gt;Depending on your intended audience, a drill-down story structure could also be an interesting option. You provide a theme for all of the stories you present, but the user can choose which one they are interested in at their leisure. If your intended audience has enough expertise in both the subject matter and the interactive methods to display your data, letting them examine all of the interactive options for themselves from the start can be beneficial. Providing multiple starting points like this can allow for variations in user’s interests, which could then provide an inlet into other stories they would normally be less interested in.&lt;/p&gt;
&lt;h2 id=&quot;escience-application-of-visual-storytelling&quot;&gt;eScience application of Visual Storytelling&lt;/h2&gt;
&lt;p&gt;At the eScience center, we are actively working on visual storytelling applications for scientific purposes. We have three recent examples:&lt;/p&gt;
&lt;h3 id=&quot;climate-science&quot;&gt;Climate Science&lt;/h3&gt;
&lt;p&gt;In the European H2020 funded &lt;a href=&quot;https://climatestorylines.eu/&quot;&gt;RECEIPT&lt;/a&gt; (REmote Climate Effects and their Impact on European sustainability, Policy and Trade) project, we use storytelling as a framework for scientific discovery, modeling and communication. Many complex interactions between climate change in remote (non-EU) areas of the world and their impact on the EU cannot be easily communicated to policy makers and the public. Yet, a drought in South America or a flood in Asia can have major impacts on the European economy, or on the food supply that reaches our tables. The storytelling application we are developing allows the RECEIPT scientists to create storylines that link map locations and map-based data (displayed with &lt;a href=&quot;https://github.com/TerriaJS/terriajs&quot;&gt;TerriaJS&lt;/a&gt;) with text, images and custom graphs (created with &lt;a href=&quot;https://vega.github.io/&quot;&gt;Vega&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In the RECEIPT climate impact story application, we are using the &lt;strong&gt;drill-down-story&lt;/strong&gt; structure. We Provide the common theme of climate changes in remote areas with impact on the EU, but we are letting the user decide what areas of the globe and/or what sectors they are most interested in, be that Agriculture, Finance, International Cooperation, Manufacturing or Coastal Infrastructure. This should provide an in* for many different users, hopefully educating many potential users about the possible impacts of climate change.&lt;/p&gt;
&lt;p&gt;A screenshot from the RECEIPT prototype visual storytelling interface.&lt;/p&gt;
&lt;h3 id=&quot;archeology-and-art-history&quot;&gt;Archeology and Art History&lt;/h3&gt;
&lt;p&gt;In the Via Appia: Revisited project, we are developing a storytelling application for 3d pointclouds (using &lt;a href=&quot;https://github.com/potree/potree&quot;&gt;potree.js)&lt;/a&gt;. The goals of the project are to show the history of art and the (virtual) archeological reconstruction of monuments on the &lt;em&gt;Via Appia Antica&lt;/em&gt;, an ancient Roman highway near Rome itself.&lt;/p&gt;
&lt;p&gt;We will make two versions of this application with different storyline structures. The first instance will be a museum exhibit, where users will interact with physical *forward &lt;em&gt;and&lt;/em&gt; back *buttons to interact with the application. We’ve chosen the &lt;strong&gt;interactive slideshow&lt;/strong&gt; approach for the story structure to simplify the user interface and make sure nothing can go wrong, as well as to allow our authors (the researchers and artists responsible for the exhibit) to carefully craft the narratives.&lt;/p&gt;
&lt;p&gt;The second instance of the application will be a public website, where users from the web can explore the Via Appia on their own. To guide the users towards interesting discoveries, we will adopt the &lt;strong&gt;martini-glass structure&lt;/strong&gt; here. First, we will offer the same storylines as in the museum exhibit, but after these storylines have finished, we open up the interactivity and will let users explore the site on their own.&lt;/p&gt;
&lt;p&gt;An screenshot of the Via Appia: Revisited (early alpha) application&lt;/p&gt;
&lt;h3 id=&quot;medical-imaging&quot;&gt;Medical Imaging&lt;/h3&gt;
&lt;p&gt;Vistories / CLUE — Gapminder visualizationAnother application area for visual storytelling we explored is medical imaging. The goal of this project was to see if we could improve the communication and support the building of trust between medical experts using Visual Storytelling techniques.&lt;/p&gt;
&lt;p&gt;Our starting point was &lt;a href=&quot;https://gapminder.caleydoapp.org/#clue_graph=clue_gapminder0&amp;#x26;clue_state=30&amp;#x26;clue=P&amp;#x26;clue_slide=41&quot;&gt;Vistories / CLUE&lt;/a&gt;, a library that uses interaction provenance as a basis for the authoring of Visual Storylines. The idea was that there could be an opportunity to increase the level of trust between a decision maker (the doctor planning treatment) and an expert doing analysis (a radiologist in the lab) by allowing the analysing expert to author a report directly from the tools used to analyse the images, with preservation of the links back to the data. This could then allow the decision maker to directly access the original analysis, and even directly try out alternate hypotheses or measurements. In this application, the &lt;strong&gt;martini-glass structure&lt;/strong&gt; is also used to guide the users at first, but allow more freedom afterwards.&lt;/p&gt;
&lt;p&gt;In the sister-blog to this one, we’d like to tell you more about the use of *provenance *for these (and other) purposes. Please read on &lt;a href=&quot;https://blog.esciencecenter.nl/konmari-for-science-tidying-up-provenance-aabed5da593&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;Combining data, narratives and visuals can bring powerful messages forward in a way that fact, numbers and data alone can not. Visual stories allow us to be more inclusive, to connect better to our audience, and most importantly, to be more &lt;strong&gt;memorable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At the eScience Center, we do really like to be remembered by both the scientists that we work with, and by their intended audience as well. Visual storytelling is one of the ways in which we try to achieve this.&lt;/p&gt;</description><pubDate>Thu, 17 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;][Maarten van Meersbergen]·Jun 7, 2021&lt;/p&gt;
&lt;p&gt;When conducting research, the data collected can in itself be exciting and meaningful, but when it is presented as spreadsheets or bullet points it can be too boring or difficult to understand for the intended audience. Telling a visual story with data is not trivial however, depending on the level of expertise of your readers, you should choose your storyline structure well.&lt;/p&gt;
&lt;p&gt;The excellent paper &lt;a href=&quot;https://ieeexplore.ieee.org/document/5613452&quot;&gt;Narrative Visualization: Telling Stories with Data&lt;/a&gt; by Edward Segel and Jeffrey Heer provides some good insights on this. The main takeaway from this paper I’d like to share is this:&lt;/p&gt;
&lt;p&gt;Author-driven** VS &lt;strong&gt;reader-driven&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Consider if you want to tell a ‘fixed’ story, or if you want the user to discover new stories based on the data you are providing. If telling a fixed story is what you want, an interactive slideshow would be a good option. Interactively ‘playing’ with the data on a slide-by-slide basis could build the reader’s trust in the author’s analysis, but the author’s conclusions are leading here.&lt;/p&gt;
&lt;p&gt;Interactive slideshow — Martini glass structure — Drill down story, images from &lt;a href=&quot;https://ieeexplore.ieee.org/document/5613452&quot;&gt;Narrative Visualization: Telling Stories with Data&lt;/a&gt; by Edward Segel and Jeffrey HeerIn a more reader-driven discovery scenario, more interaction is definitely needed, and a martini-glass-structure is likely a good option. Provide a ‘narrow’ authored storyline at first to explain a possible interaction with the data for tutorial purposes, and then open up options to let the user discover new stories on their own. This allows the user to learn about the possibilities without getting overwhelmed, but gives them the freedom to discover their own stories.&lt;/p&gt;
&lt;p&gt;Depending on your intended audience, a drill-down story structure could also be an interesting option. You provide a theme for all of the stories you present, but the user can choose which one they are interested in at their leisure. If your intended audience has enough expertise in both the subject matter and the interactive methods to display your data, letting them examine all of the interactive options for themselves from the start can be beneficial. Providing multiple starting points like this can allow for variations in user’s interests, which could then provide an inlet into other stories they would normally be less interested in.&lt;/p&gt;
&lt;h2 id=&quot;escience-application-of-visual-storytelling&quot;&gt;eScience application of Visual Storytelling&lt;/h2&gt;
&lt;p&gt;At the eScience center, we are actively working on visual storytelling applications for scientific purposes. We have three recent examples:&lt;/p&gt;
&lt;h3 id=&quot;climate-science&quot;&gt;Climate Science&lt;/h3&gt;
&lt;p&gt;In the European H2020 funded &lt;a href=&quot;https://climatestorylines.eu/&quot;&gt;RECEIPT&lt;/a&gt; (REmote Climate Effects and their Impact on European sustainability, Policy and Trade) project, we use storytelling as a framework for scientific discovery, modeling and communication. Many complex interactions between climate change in remote (non-EU) areas of the world and their impact on the EU cannot be easily communicated to policy makers and the public. Yet, a drought in South America or a flood in Asia can have major impacts on the European economy, or on the food supply that reaches our tables. The storytelling application we are developing allows the RECEIPT scientists to create storylines that link map locations and map-based data (displayed with &lt;a href=&quot;https://github.com/TerriaJS/terriajs&quot;&gt;TerriaJS&lt;/a&gt;) with text, images and custom graphs (created with &lt;a href=&quot;https://vega.github.io/&quot;&gt;Vega&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In the RECEIPT climate impact story application, we are using the &lt;strong&gt;drill-down-story&lt;/strong&gt; structure. We Provide the common theme of climate changes in remote areas with impact on the EU, but we are letting the user decide what areas of the globe and/or what sectors they are most interested in, be that Agriculture, Finance, International Cooperation, Manufacturing or Coastal Infrastructure. This should provide an in* for many different users, hopefully educating many potential users about the possible impacts of climate change.&lt;/p&gt;
&lt;p&gt;A screenshot from the RECEIPT prototype visual storytelling interface.&lt;/p&gt;
&lt;h3 id=&quot;archeology-and-art-history&quot;&gt;Archeology and Art History&lt;/h3&gt;
&lt;p&gt;In the Via Appia: Revisited project, we are developing a storytelling application for 3d pointclouds (using &lt;a href=&quot;https://github.com/potree/potree&quot;&gt;potree.js)&lt;/a&gt;. The goals of the project are to show the history of art and the (virtual) archeological reconstruction of monuments on the &lt;em&gt;Via Appia Antica&lt;/em&gt;, an ancient Roman highway near Rome itself.&lt;/p&gt;
&lt;p&gt;We will make two versions of this application with different storyline structures. The first instance will be a museum exhibit, where users will interact with physical *forward &lt;em&gt;and&lt;/em&gt; back *buttons to interact with the application. We’ve chosen the &lt;strong&gt;interactive slideshow&lt;/strong&gt; approach for the story structure to simplify the user interface and make sure nothing can go wrong, as well as to allow our authors (the researchers and artists responsible for the exhibit) to carefully craft the narratives.&lt;/p&gt;
&lt;p&gt;The second instance of the application will be a public website, where users from the web can explore the Via Appia on their own. To guide the users towards interesting discoveries, we will adopt the &lt;strong&gt;martini-glass structure&lt;/strong&gt; here. First, we will offer the same storylines as in the museum exhibit, but after these storylines have finished, we open up the interactivity and will let users explore the site on their own.&lt;/p&gt;
&lt;p&gt;An screenshot of the Via Appia: Revisited (early alpha) application&lt;/p&gt;
&lt;h3 id=&quot;medical-imaging&quot;&gt;Medical Imaging&lt;/h3&gt;
&lt;p&gt;Vistories / CLUE — Gapminder visualizationAnother application area for visual storytelling we explored is medical imaging. The goal of this project was to see if we could improve the communication and support the building of trust between medical experts using Visual Storytelling techniques.&lt;/p&gt;
&lt;p&gt;Our starting point was &lt;a href=&quot;https://gapminder.caleydoapp.org/#clue_graph=clue_gapminder0&amp;#x26;clue_state=30&amp;#x26;clue=P&amp;#x26;clue_slide=41&quot;&gt;Vistories / CLUE&lt;/a&gt;, a library that uses interaction provenance as a basis for the authoring of Visual Storylines. The idea was that there could be an opportunity to increase the level of trust between a decision maker (the doctor planning treatment) and an expert doing analysis (a radiologist in the lab) by allowing the analysing expert to author a report directly from the tools used to analyse the images, with preservation of the links back to the data. This could then allow the decision maker to directly access the original analysis, and even directly try out alternate hypotheses or measurements. In this application, the &lt;strong&gt;martini-glass structure&lt;/strong&gt; is also used to guide the users at first, but allow more freedom afterwards.&lt;/p&gt;
&lt;p&gt;In the sister-blog to this one, we’d like to tell you more about the use of *provenance *for these (and other) purposes. Please read on &lt;a href=&quot;https://blog.esciencecenter.nl/konmari-for-science-tidying-up-provenance-aabed5da593&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;Combining data, narratives and visuals can bring powerful messages forward in a way that fact, numbers and data alone can not. Visual stories allow us to be more inclusive, to connect better to our audience, and most importantly, to be more &lt;strong&gt;memorable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At the eScience Center, we do really like to be remembered by both the scientists that we work with, and by their intended audience as well. Visual storytelling is one of the ways in which we try to achieve this.&lt;/p&gt;</content:encoded><author>Maarten van Meersbergen</author></item><item><title>#KonMari for Science? Tidying up Provenance…</title><link>https://blog.esciencecenter.nl/posts/2021-06-14---konmari-for-science-tidying-up-provenance</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-06-14---konmari-for-science-tidying-up-provenance</guid><description>&lt;p&gt;The term provenance mostly originates from the art world, where it aids in authenticating historical objects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The primary purpose of tracing the provenance of an object or entity is normally to provide contextual and circumstantial evidence for its original production or discovery, by establishing, as far as practicable, its later history, especially the sequences of its formal ownership, custody and places of storage. The practice has a particular &lt;strong&gt;value&lt;/strong&gt; in helping authenticate objects.” (&lt;a href=&quot;https://en.wikipedia.org/wiki/Provenance&quot;&gt;Wikipedia&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The potential of provenance tracking as-standard has been identified by people far outside the art world, particularly by scientists. After all, tracing the source and transformations that led to a particular piece of data has clear implications for the reproduction of scientific results that sits at the heart of the scientific method. While the experimentalist’s trusty lab book has been the primary means of recording such information, the increasing use of computers in data generation and analysis has provided a natural drive towards more automated means of keeping track.&lt;/p&gt;
&lt;p&gt;This is great, because if keeping track of the provenance can be automated, we can record everything, right? Well, maybe not everything, but a lot indeed. For example, the provenance in a Jupyter Notebook (&lt;a href=&quot;https://www.db-thueringen.de/receive/dbt_mods_00040396&quot;&gt;ProvBook&lt;/a&gt;), the provenance in visual exploration (&lt;a href=&quot;https://onlinelibrary.wiley.com/doi/pdf/10.1111/cgf.12925?casa_token=Tmhtt4kxbLAAAAAA%3AXp0U4C7KCfCScGrGX_gE_2kuxyOSiHZrKqNrUV2XnjSGzF6uaLnx90zTEO_sznL-28CLNhBa3HB4CoG9jA&quot;&gt;CLUE&lt;/a&gt;), and workflow provenance (&lt;a href=&quot;https://direct.mit.edu/dint/article/2/1-2/108/10003/FAIR-Computational-Workflows&quot;&gt;FAIR Computational Workflows&lt;/a&gt;). However, provenance is always stored for a purpose, even if the purpose is that it might be useful later on. Quite similar actually to collecting things at home.&lt;/p&gt;
&lt;p&gt;Your house might be filled with stuff that you regularly use, sometimes use, think is beautiful, has emotional value, might come in handy someday, or just haven’t had the time to throw out yet. The thing is, if you collect too much stuff at home you run the risk of not knowing what you have in your home anymore or where you stored it. By the time you need the thing that might come in handy someday, you cannot seem to find it or it turns out to be so outdated that you need to buy a new one.&lt;/p&gt;
&lt;p&gt;Something similar might happen with saving data and provenance. Saving data does not necessarily mean that it will be re-used later on. The more we save, the less overview we have of what is really important or valuable. This overview could be provided by using machine learning to dig through the data, but this is not magic either. Exhaust data can feel like a messy attic, there might be something valuable there, but machine learning requires the tedious work of &lt;a href=&quot;https://towardsdatascience.com/how-to-work-with-someone-elses-data-f33485d79ed4&quot;&gt;cleaning and processing the data&lt;/a&gt;, before you might get something out of it.&lt;/p&gt;
&lt;p&gt;In this blog we share some lessons learned about provenance in science and philosophize on how &lt;a href=&quot;https://konmari.com/&quot;&gt;Marie Kondo&lt;/a&gt;, a world-renowned tidying expert, could teach us some lessons that might be valuable for science as well.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;921&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pdCYToZHSFGsbRDku6oONA-366217b0.BoHx5c6u_ppoKs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finding something valuable in here will take some time… (Photo by Cristina Gottardi on Unsplash)&lt;/p&gt;
&lt;p&gt;Some people have the natural tendency to tidy up things, whereas others feel like children whose parents tell them to tidy up their rooms, while they actually want to go play outside.&lt;/p&gt;
&lt;p&gt;A way to tidy up automatically tracked provenance is by providing tools that enable the presentation of provenance for easy human assessment. An example of this is &lt;a href=&quot;https://github.com/Sheeba-Samuel/ProvBook&quot;&gt;ProvBook&lt;/a&gt;, which can automatically track the provenance in a &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter Notebook&lt;/a&gt; and enables sharing and easy viewing of the cell history in a notebook (saved in the &lt;a href=&quot;https://www.db-thueringen.de/receive/dbt_mods_00040396&quot;&gt;REPRODUCE-ME ontology&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;provbook-provenance-of-the-notebook&quot;&gt;&lt;a href=&quot;https://figshare.com/articles/media/ProvBook_Provenance_of_the_Notebook/6401096?source=post_page-----aabed5da593---------------------------------------&quot;&gt;ProvBook: Provenance of the Notebook&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;provbook-provenance-of-the-notebookthis-is-the-demo-video-for-the-introduction-of-provbook-provbook-is-an-extension&quot;&gt;ProvBook: Provenance of the Notebook.This is the demo video for the introduction of ProvBook. ProvBook is an extension…&lt;/h3&gt;
&lt;p&gt;figshare.com&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://onlinelibrary.wiley.com/doi/pdf/10.1111/cgf.12925?casa_token=swxhYSB8GwwAAAAA%3A8uLR0LZORrq2haxpBS3kcMY-JEGNDmGKes4wRaqkoURjD641X9WpVuj-UoMKMLJvbBYiAs0akKr9amnj&quot;&gt;Gratzl et al&lt;/a&gt;. take this idea of presenting provenance tracking one step further for &lt;a href=&quot;https://blog.esciencecenter.nl/visual-storytelling-for-data-science-2f9ef8a27474&quot;&gt;visual story telling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1020&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_lX4tPi4pqtcp1IgRKr-aKw-6003612e.CiwTPtVM_18XAzi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you like, you can try it out here.&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;exploration mode&lt;/strong&gt;, for example while exploring data in a visualization tool, the provenance (user actions) is automatically tracked. Then in the &lt;strong&gt;authoring mode&lt;/strong&gt;, the provenance is presented to the person who performed the exploration, who is given the option to create a visual story from it. This story can then be used to communicate to others how you gained insight while exploring the visualization, by using the &lt;strong&gt;presentation mode&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1276&quot; height=&quot;693&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uMeyOX5M5jKIVLppjpZgAA-d894935d.DcUUqQsn_ZMWCwc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;From Visual Exploration to Storytelling and Back Again (S. Gratzl et al, 2016)&lt;/p&gt;
&lt;p&gt;From the presentation mode you can switch back to the exploration mode and start a new branch of explorations from the last or any of the previous time points in the tracked provenance. Theoretically this sounds great, but in practice it is quite hard to make a tool that presents the automatically tracked provenance in an easy and efficient human readable format. So the question is whether the value outweighs the work that needs to be done either by the person viewing the exploration or by the person creating the visual story.&lt;/p&gt;
&lt;p&gt;In terms of tidying up provenance, the realm of computational workflows deserves a lot of credit as well, where concerted efforts in standardization produced the now ubiquitous &lt;a href=&quot;https://www.w3.org/TR/prov-overview/&quot;&gt;W3C PROV model&lt;/a&gt; and its family of ontologies. A key development in this field is the strict separation of the recorded workflow execution (&lt;em&gt;retrospective provenance&lt;/em&gt;) from the workflow specification (&lt;em&gt;prospective provenance&lt;/em&gt;). The prospective provenance is the high level description of the scientific procedure, whereas the retrospective provenance is the ‘exhaust’ collection of all fine-grained execution details we mentioned earlier. The creation of prospective provenance can be viewed as an attempt to distill the scientifically crucial and useful “story” out, leaving the remaining residue (retrospective provenance) that is more specific and cluttered.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1054&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YvOryy1NoYPq361GOK7aVg-908d75fb.T-e17BEG_ZV4pFz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Prospective versus retrospective provenance? (Photos by Bernard Hermant and Sammy Williams on Unsplash )&lt;/p&gt;
&lt;p&gt;But where do you store all this provenance once you have it? It could of course just lie around on your hard drive or local cluster but if you want to participate in open science then it would be good to publish it. In the semantic web/linked data space there are a number of ways available, such as packaging it up in a &lt;a href=&quot;https://www.researchobject.org/ro-crate/&quot;&gt;Research Object Crate&lt;/a&gt; and publishing it e.g. to the &lt;a href=&quot;https://workflowhub.eu/&quot;&gt;workflowhub registry&lt;/a&gt;, or by publishing the RDF description of your workflow as one or more &lt;a href=&quot;https://blog.esciencecenter.nl/nano-publish-your-research-with-python-b81aa54eb1a2&quot;&gt;nanopublications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are great efforts, but what if you are one of those people that would rather play outside then tidy up your room? Funding agencies can of course play the role of the parent, demanding that research objects and provenance is being saved for possible re-use, adding another checkbox to the long list of boxes that researchers already need to check. The question is, does this really work? Or do we end up with something that seems neat on the outside, but is more like children stuffing their toys anywhere in boxes in their rooms, just to make it look tidy? While underneath the surface, the boxes are a colorful mixture of all sorts of toys in which it is hard to find that specific toy that they must have later on…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-RQR9OMVtltNMGBAQHS0ng-f2dd9525.C2UIrrR5_Z2fxqa2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Nareeta Martin on Unsplash)&lt;/p&gt;
&lt;p&gt;In her book “Spark Joy”, &lt;a href=&quot;https://konmari.com/&quot;&gt;Marie Kondo&lt;/a&gt; mentions that most people tidy up by moving stuff from one room to another, occasionally throwing some things away. This does not seem to lead anywhere, since there is no system behind it. Her method is much more thorough and requires people to make choices. There is no gray area, you either keep something and cherish it or throw it away. The trick is to focus on the things you would like to keep, the rest can go. The way you decide on what to keep is to learn what sparks joy inside you. You go through everything you collected in your house, based on categories, ordered in a way that was designed to slowly teach you what sparks joy inside you.&lt;/p&gt;
&lt;p&gt;What is key here, is that for people following this method, tidying up changes from a painful process of saying goodbye, to an inner journey discovering who they are, what they like and what fits them. This does not only provide an inner drive to tidy up their house, but changes their mindset with respect to &lt;a href=&quot;https://ntnuopen.ntnu.no/ntnu-xmlui/handle/11250/2754612&quot;&gt;future decisions on what to buy&lt;/a&gt;. Knowing who they are and having overview in their home, they think twice before buying something new, because they cherish what they have in their home. In a way, it provides a sense of direction and relieves them from the fear of missing out.&lt;/p&gt;
&lt;p&gt;Is there a lesson to learn here for science? Well, maybe there is.&lt;/p&gt;
&lt;p&gt;First of all, in the past couple of decennia, the focus in science has been more on quantity then on quality, pushed by funding agencies counting the number of publications as a metric for good science. As a result, a lot of publications were written and scientific literature to date is like a home so full of stuff that even scientists themselves have trouble keeping the overview and determining the current state-of-the-art in human knowledge. Is the solution then changing the metrics? Or adding more metrics? Or will this mostly lead to a different form of &lt;a href=&quot;https://www.investopedia.com/terms/c/consumerism.asp&quot;&gt;consumerism&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;868&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_NMKBcvriZFShx8COTneP_A-f118c2a3.DvwD_1WH_2NXB4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Goodhart’s Law Explained ( Source )&lt;/p&gt;
&lt;p&gt;Maybe a more thorough approach is required, making clear choices on what to keep and get rid of the rest. But who needs to make this decision and based on what?&lt;/p&gt;
&lt;p&gt;What the #KonMari method does, is teach people how to make choices that are in line with their “inner joy”, so people themselves are able to make the choices that fit best. In translating the work of Kondo, another phrase was considered as the central question. Instead of “does it spark joy?”, the phrase “does it speak to your heart?” was considered as a translation for &lt;em&gt;tokimeku&lt;/em&gt;, which can be understood as “how does it move the &lt;em&gt;kokoro&lt;/em&gt; (heart / mind)?” (&lt;a href=&quot;https://spectrajournal.org/articles/10.21061/spectra.v7i2.146/&quot;&gt;Tokimeku: The Poetics of Marie Kondo’s KonMari Method&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_TT22KUEpnXuvE_hwJ6g9TQ-7ca18d90.DEhd5cDI_Z1TPTyP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Aziz Acharki on Unsplash)&lt;/p&gt;
&lt;p&gt;Well, this is not something we can use in science, because science is all about reasoning and has nothing to do with the heart or mind… Yes, that is one way to look at it, but if you have read the book “ &lt;a href=&quot;https://www.goodreads.com/book/show/599317.Hare_Brain_Tortoise_Mind&quot;&gt;Hare brain, Tortoise Mind&lt;/a&gt; ”, you might want to reconsider this. The quick thinking hare brain is what we would use for reasoning, whereas the tortoise mind could be described as intuition, the inner drive, sudden inspiration, or a spark of creativity. Both are important, but if you think about it, most of the big leaps in science came from people with an inner drive, following their intuition, not seldom against the main stream in academia.&lt;/p&gt;
&lt;p&gt;So, to recap, what can we learn from all of this with respect to provenance? Maybe, that we should be careful that saving or publishing data and provenance does not become another box to check for already overloaded researchers. Maybe, the less is more approach of Marie Kondo could spark a little joy in the lives of researchers, and free up some time to learn how to use their tortoise mind. Provenance should be saved if there is value in saving it, and if we save it, we should cherish it for human knowledge, communicate it clearly and make sure people can use it. Either for reproducibility purposes or communicating findings or insights, such as in visual story telling. What is required is a mindset change from &lt;a href=&quot;https://www.investopedia.com/terms/c/consumerism.asp&quot;&gt;consumerism&lt;/a&gt; to value (that which moves the &lt;em&gt;kokoro)&lt;/em&gt; for science, and methods and tools that aid this.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1321&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iWIvBdVdJayjhRx4NlXEUw-d2394d7f.SzZBKfMd_17zwWx.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Fahrul Azmi on Unsplash)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Jiri Kosinka, Carlos Martinez-Ortiz, and Lourens Veen.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 14 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The term provenance mostly originates from the art world, where it aids in authenticating historical objects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The primary purpose of tracing the provenance of an object or entity is normally to provide contextual and circumstantial evidence for its original production or discovery, by establishing, as far as practicable, its later history, especially the sequences of its formal ownership, custody and places of storage. The practice has a particular &lt;strong&gt;value&lt;/strong&gt; in helping authenticate objects.” (&lt;a href=&quot;https://en.wikipedia.org/wiki/Provenance&quot;&gt;Wikipedia&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The potential of provenance tracking as-standard has been identified by people far outside the art world, particularly by scientists. After all, tracing the source and transformations that led to a particular piece of data has clear implications for the reproduction of scientific results that sits at the heart of the scientific method. While the experimentalist’s trusty lab book has been the primary means of recording such information, the increasing use of computers in data generation and analysis has provided a natural drive towards more automated means of keeping track.&lt;/p&gt;
&lt;p&gt;This is great, because if keeping track of the provenance can be automated, we can record everything, right? Well, maybe not everything, but a lot indeed. For example, the provenance in a Jupyter Notebook (&lt;a href=&quot;https://www.db-thueringen.de/receive/dbt_mods_00040396&quot;&gt;ProvBook&lt;/a&gt;), the provenance in visual exploration (&lt;a href=&quot;https://onlinelibrary.wiley.com/doi/pdf/10.1111/cgf.12925?casa_token=Tmhtt4kxbLAAAAAA%3AXp0U4C7KCfCScGrGX_gE_2kuxyOSiHZrKqNrUV2XnjSGzF6uaLnx90zTEO_sznL-28CLNhBa3HB4CoG9jA&quot;&gt;CLUE&lt;/a&gt;), and workflow provenance (&lt;a href=&quot;https://direct.mit.edu/dint/article/2/1-2/108/10003/FAIR-Computational-Workflows&quot;&gt;FAIR Computational Workflows&lt;/a&gt;). However, provenance is always stored for a purpose, even if the purpose is that it might be useful later on. Quite similar actually to collecting things at home.&lt;/p&gt;
&lt;p&gt;Your house might be filled with stuff that you regularly use, sometimes use, think is beautiful, has emotional value, might come in handy someday, or just haven’t had the time to throw out yet. The thing is, if you collect too much stuff at home you run the risk of not knowing what you have in your home anymore or where you stored it. By the time you need the thing that might come in handy someday, you cannot seem to find it or it turns out to be so outdated that you need to buy a new one.&lt;/p&gt;
&lt;p&gt;Something similar might happen with saving data and provenance. Saving data does not necessarily mean that it will be re-used later on. The more we save, the less overview we have of what is really important or valuable. This overview could be provided by using machine learning to dig through the data, but this is not magic either. Exhaust data can feel like a messy attic, there might be something valuable there, but machine learning requires the tedious work of &lt;a href=&quot;https://towardsdatascience.com/how-to-work-with-someone-elses-data-f33485d79ed4&quot;&gt;cleaning and processing the data&lt;/a&gt;, before you might get something out of it.&lt;/p&gt;
&lt;p&gt;In this blog we share some lessons learned about provenance in science and philosophize on how &lt;a href=&quot;https://konmari.com/&quot;&gt;Marie Kondo&lt;/a&gt;, a world-renowned tidying expert, could teach us some lessons that might be valuable for science as well.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;921&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pdCYToZHSFGsbRDku6oONA-366217b0.BoHx5c6u_ppoKs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finding something valuable in here will take some time… (Photo by Cristina Gottardi on Unsplash)&lt;/p&gt;
&lt;p&gt;Some people have the natural tendency to tidy up things, whereas others feel like children whose parents tell them to tidy up their rooms, while they actually want to go play outside.&lt;/p&gt;
&lt;p&gt;A way to tidy up automatically tracked provenance is by providing tools that enable the presentation of provenance for easy human assessment. An example of this is &lt;a href=&quot;https://github.com/Sheeba-Samuel/ProvBook&quot;&gt;ProvBook&lt;/a&gt;, which can automatically track the provenance in a &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter Notebook&lt;/a&gt; and enables sharing and easy viewing of the cell history in a notebook (saved in the &lt;a href=&quot;https://www.db-thueringen.de/receive/dbt_mods_00040396&quot;&gt;REPRODUCE-ME ontology&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;provbook-provenance-of-the-notebook&quot;&gt;&lt;a href=&quot;https://figshare.com/articles/media/ProvBook_Provenance_of_the_Notebook/6401096?source=post_page-----aabed5da593---------------------------------------&quot;&gt;ProvBook: Provenance of the Notebook&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;provbook-provenance-of-the-notebookthis-is-the-demo-video-for-the-introduction-of-provbook-provbook-is-an-extension&quot;&gt;ProvBook: Provenance of the Notebook.This is the demo video for the introduction of ProvBook. ProvBook is an extension…&lt;/h3&gt;
&lt;p&gt;figshare.com&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://onlinelibrary.wiley.com/doi/pdf/10.1111/cgf.12925?casa_token=swxhYSB8GwwAAAAA%3A8uLR0LZORrq2haxpBS3kcMY-JEGNDmGKes4wRaqkoURjD641X9WpVuj-UoMKMLJvbBYiAs0akKr9amnj&quot;&gt;Gratzl et al&lt;/a&gt;. take this idea of presenting provenance tracking one step further for &lt;a href=&quot;https://blog.esciencecenter.nl/visual-storytelling-for-data-science-2f9ef8a27474&quot;&gt;visual story telling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1020&quot; height=&quot;563&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_lX4tPi4pqtcp1IgRKr-aKw-6003612e.CiwTPtVM_18XAzi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you like, you can try it out here.&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;exploration mode&lt;/strong&gt;, for example while exploring data in a visualization tool, the provenance (user actions) is automatically tracked. Then in the &lt;strong&gt;authoring mode&lt;/strong&gt;, the provenance is presented to the person who performed the exploration, who is given the option to create a visual story from it. This story can then be used to communicate to others how you gained insight while exploring the visualization, by using the &lt;strong&gt;presentation mode&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1276&quot; height=&quot;693&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_uMeyOX5M5jKIVLppjpZgAA-d894935d.DcUUqQsn_ZMWCwc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;From Visual Exploration to Storytelling and Back Again (S. Gratzl et al, 2016)&lt;/p&gt;
&lt;p&gt;From the presentation mode you can switch back to the exploration mode and start a new branch of explorations from the last or any of the previous time points in the tracked provenance. Theoretically this sounds great, but in practice it is quite hard to make a tool that presents the automatically tracked provenance in an easy and efficient human readable format. So the question is whether the value outweighs the work that needs to be done either by the person viewing the exploration or by the person creating the visual story.&lt;/p&gt;
&lt;p&gt;In terms of tidying up provenance, the realm of computational workflows deserves a lot of credit as well, where concerted efforts in standardization produced the now ubiquitous &lt;a href=&quot;https://www.w3.org/TR/prov-overview/&quot;&gt;W3C PROV model&lt;/a&gt; and its family of ontologies. A key development in this field is the strict separation of the recorded workflow execution (&lt;em&gt;retrospective provenance&lt;/em&gt;) from the workflow specification (&lt;em&gt;prospective provenance&lt;/em&gt;). The prospective provenance is the high level description of the scientific procedure, whereas the retrospective provenance is the ‘exhaust’ collection of all fine-grained execution details we mentioned earlier. The creation of prospective provenance can be viewed as an attempt to distill the scientifically crucial and useful “story” out, leaving the remaining residue (retrospective provenance) that is more specific and cluttered.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1054&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YvOryy1NoYPq361GOK7aVg-908d75fb.T-e17BEG_ZV4pFz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Prospective versus retrospective provenance? (Photos by Bernard Hermant and Sammy Williams on Unsplash )&lt;/p&gt;
&lt;p&gt;But where do you store all this provenance once you have it? It could of course just lie around on your hard drive or local cluster but if you want to participate in open science then it would be good to publish it. In the semantic web/linked data space there are a number of ways available, such as packaging it up in a &lt;a href=&quot;https://www.researchobject.org/ro-crate/&quot;&gt;Research Object Crate&lt;/a&gt; and publishing it e.g. to the &lt;a href=&quot;https://workflowhub.eu/&quot;&gt;workflowhub registry&lt;/a&gt;, or by publishing the RDF description of your workflow as one or more &lt;a href=&quot;https://blog.esciencecenter.nl/nano-publish-your-research-with-python-b81aa54eb1a2&quot;&gt;nanopublications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are great efforts, but what if you are one of those people that would rather play outside then tidy up your room? Funding agencies can of course play the role of the parent, demanding that research objects and provenance is being saved for possible re-use, adding another checkbox to the long list of boxes that researchers already need to check. The question is, does this really work? Or do we end up with something that seems neat on the outside, but is more like children stuffing their toys anywhere in boxes in their rooms, just to make it look tidy? While underneath the surface, the boxes are a colorful mixture of all sorts of toys in which it is hard to find that specific toy that they must have later on…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_-RQR9OMVtltNMGBAQHS0ng-f2dd9525.C2UIrrR5_Z2fxqa2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Nareeta Martin on Unsplash)&lt;/p&gt;
&lt;p&gt;In her book “Spark Joy”, &lt;a href=&quot;https://konmari.com/&quot;&gt;Marie Kondo&lt;/a&gt; mentions that most people tidy up by moving stuff from one room to another, occasionally throwing some things away. This does not seem to lead anywhere, since there is no system behind it. Her method is much more thorough and requires people to make choices. There is no gray area, you either keep something and cherish it or throw it away. The trick is to focus on the things you would like to keep, the rest can go. The way you decide on what to keep is to learn what sparks joy inside you. You go through everything you collected in your house, based on categories, ordered in a way that was designed to slowly teach you what sparks joy inside you.&lt;/p&gt;
&lt;p&gt;What is key here, is that for people following this method, tidying up changes from a painful process of saying goodbye, to an inner journey discovering who they are, what they like and what fits them. This does not only provide an inner drive to tidy up their house, but changes their mindset with respect to &lt;a href=&quot;https://ntnuopen.ntnu.no/ntnu-xmlui/handle/11250/2754612&quot;&gt;future decisions on what to buy&lt;/a&gt;. Knowing who they are and having overview in their home, they think twice before buying something new, because they cherish what they have in their home. In a way, it provides a sense of direction and relieves them from the fear of missing out.&lt;/p&gt;
&lt;p&gt;Is there a lesson to learn here for science? Well, maybe there is.&lt;/p&gt;
&lt;p&gt;First of all, in the past couple of decennia, the focus in science has been more on quantity then on quality, pushed by funding agencies counting the number of publications as a metric for good science. As a result, a lot of publications were written and scientific literature to date is like a home so full of stuff that even scientists themselves have trouble keeping the overview and determining the current state-of-the-art in human knowledge. Is the solution then changing the metrics? Or adding more metrics? Or will this mostly lead to a different form of &lt;a href=&quot;https://www.investopedia.com/terms/c/consumerism.asp&quot;&gt;consumerism&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;868&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_NMKBcvriZFShx8COTneP_A-f118c2a3.DvwD_1WH_2NXB4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Goodhart’s Law Explained ( Source )&lt;/p&gt;
&lt;p&gt;Maybe a more thorough approach is required, making clear choices on what to keep and get rid of the rest. But who needs to make this decision and based on what?&lt;/p&gt;
&lt;p&gt;What the #KonMari method does, is teach people how to make choices that are in line with their “inner joy”, so people themselves are able to make the choices that fit best. In translating the work of Kondo, another phrase was considered as the central question. Instead of “does it spark joy?”, the phrase “does it speak to your heart?” was considered as a translation for &lt;em&gt;tokimeku&lt;/em&gt;, which can be understood as “how does it move the &lt;em&gt;kokoro&lt;/em&gt; (heart / mind)?” (&lt;a href=&quot;https://spectrajournal.org/articles/10.21061/spectra.v7i2.146/&quot;&gt;Tokimeku: The Poetics of Marie Kondo’s KonMari Method&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_TT22KUEpnXuvE_hwJ6g9TQ-7ca18d90.DEhd5cDI_Z1TPTyP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Aziz Acharki on Unsplash)&lt;/p&gt;
&lt;p&gt;Well, this is not something we can use in science, because science is all about reasoning and has nothing to do with the heart or mind… Yes, that is one way to look at it, but if you have read the book “ &lt;a href=&quot;https://www.goodreads.com/book/show/599317.Hare_Brain_Tortoise_Mind&quot;&gt;Hare brain, Tortoise Mind&lt;/a&gt; ”, you might want to reconsider this. The quick thinking hare brain is what we would use for reasoning, whereas the tortoise mind could be described as intuition, the inner drive, sudden inspiration, or a spark of creativity. Both are important, but if you think about it, most of the big leaps in science came from people with an inner drive, following their intuition, not seldom against the main stream in academia.&lt;/p&gt;
&lt;p&gt;So, to recap, what can we learn from all of this with respect to provenance? Maybe, that we should be careful that saving or publishing data and provenance does not become another box to check for already overloaded researchers. Maybe, the less is more approach of Marie Kondo could spark a little joy in the lives of researchers, and free up some time to learn how to use their tortoise mind. Provenance should be saved if there is value in saving it, and if we save it, we should cherish it for human knowledge, communicate it clearly and make sure people can use it. Either for reproducibility purposes or communicating findings or insights, such as in visual story telling. What is required is a mindset change from &lt;a href=&quot;https://www.investopedia.com/terms/c/consumerism.asp&quot;&gt;consumerism&lt;/a&gt; to value (that which moves the &lt;em&gt;kokoro)&lt;/em&gt; for science, and methods and tools that aid this.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1321&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_iWIvBdVdJayjhRx4NlXEUw-d2394d7f.SzZBKfMd_17zwWx.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Photo by Fahrul Azmi on Unsplash)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Jiri Kosinka, Carlos Martinez-Ortiz, and Lourens Veen.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_pdCYToZHSFGsbRDku6oONA-366217b0.BoHx5c6u.jpeg" medium="image"/><author>Adriënne Mendrik</author></item><item><title>(Nano)Publish your research with Python</title><link>https://blog.esciencecenter.nl/posts/2021-05-31---nanopublish-your-research-with-python</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-05-31---nanopublish-your-research-with-python</guid><description>&lt;h2 id=&quot;using-nanopub-a-high-level-user-friendly-python-interface-to-the-nanopublication-network&quot;&gt;Using nanopub, a high-level, user-friendly python interface to the nanopublication network&lt;/h2&gt;
&lt;p&gt;For example, if you want to e.g. search for all nanopublications containing the text Picoides*:&lt;/p&gt;
&lt;p&gt;which returns two results both pointing to the example nanopublication we just discussed:&lt;/p&gt;
&lt;p&gt;{‘np’: ‘&lt;a href=&quot;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA&amp;#x27;&quot;&gt;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA’&lt;/a&gt;, ‘description’: ‘Inter-species interaction of Picoides villosus with Ips’, ‘date’: ‘2020-12-24T10:51:43.931Z’}
{‘np’: ‘&lt;a href=&quot;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA&amp;#x27;&quot;&gt;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA’&lt;/a&gt;, ‘description’: ‘Picoides villosus’, ‘date’: ‘2020-12-24T10:51:43.931Z’}You can then fetch a specific nanopublication directly using its URI:&lt;/p&gt;
&lt;p&gt;This snippet will fetch the nanopublication we discussed earlier, about the interaction of the bird and the beetle, and print the contents of its assertion. Of course, you are not limited to simple text searches. The library has several search methods, including finding nanopubs with a given triple pattern — you can find detailed documentation &lt;a href=&quot;https://nanopub.readthedocs.io/en/latest/searching.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hold-on-i-want-to-publish-nanopublications-of-my-own&quot;&gt;Hold on, I want to publish Nanopublications of my own!&lt;/h2&gt;
&lt;p&gt;To publish to the nanopub server you need to set up your profile. This allows the nanopub server to identify you. Run the following interactive command (on the command line):&lt;/p&gt;
&lt;p&gt;setup_nanopub_profileIt will add and store RSA keys to sign your nanopublications, publish a nanopublication with your name and ORCID iD to declare that you are using using these RSA keys, and store your ORCID iD to automatically add as author to the provenance of any nanopublication you will publish using this library.&lt;/p&gt;
&lt;p&gt;You can then publish a quick claim:&lt;/p&gt;
&lt;p&gt;Published to &lt;a href=&quot;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&quot;&gt;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&lt;/a&gt;View the resulting nanopublication &lt;a href=&quot;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&quot;&gt;here&lt;/a&gt;. Note that the URI of your nanopublication is a signed hash of its contents, making its authorship verifiable and enforcing its immutability — known as a &lt;a href=&quot;https://doi.org/10.1007/978-3-319-07443-6_27&quot;&gt;trusty URI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or, to leverage the true power of semantic technologies, you can build your own RDF graph of triples and publish that:&lt;/p&gt;
&lt;p&gt;The above builds a graph containing a single triple that states (essentially) the concept pointed to by &lt;code&gt;www.example.org/timbernerslee&lt;/code&gt;is of type Person. We use the &lt;a href=&quot;https://github.com/RDFLib/rdflib&quot;&gt;rdflib&lt;/a&gt; library to build the graph, but this is already a dependency of nanopub. A Publication object is then created, using that graph as its assertion, and finally published using the NanopubClient as before. The code produces the following output:&lt;/p&gt;
&lt;p&gt;Published to &lt;a href=&quot;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&quot;&gt;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&lt;/a&gt;You can view the resulting nanopublication &lt;a href=&quot;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot;&gt;Outlook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nanopub&lt;/code&gt; makes interacting with nanopublications quite intuitive for those with sufficient RDF and python skills. For all others we foresee tools built around &lt;code&gt;nanopub&lt;/code&gt; that make it intuitive for domain-experts (but not RDF-experts) to make use of the nanopublication network.&lt;/p&gt;
&lt;p&gt;There are a couple of those already in the making:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nanotate-tool/nanotate&quot;&gt;nanotate&lt;/a&gt;: Create nanopublications from annotations in PDF-files made with &lt;a href=&quot;https://web.hypothes.is/&quot;&gt;hypothes.is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fair-workflows/fairworkflows&quot;&gt;fairworkflows&lt;/a&gt;: Support the construction, manipulation and publishing of FAIR scientific workflows using semantic technologies. This is developed as part of the wider &lt;a href=&quot;https://www.esciencecenter.nl/projects/fair-is-as-fair-does/&quot;&gt;FAIR is as FAIR does&lt;/a&gt; project at the eScience Center.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The python &lt;code&gt;nanopub&lt;/code&gt; library provides a high-level, user-friendly python interface for the nanopub server, making it easy to publish and search small scientific publications. We created this library to bring nanopublishing to python users and we’re keen to help people make use of it.&lt;/p&gt;
&lt;p&gt;Consider how &lt;a href=&quot;http://nanopub.org/wordpress/&quot;&gt;nanopublications&lt;/a&gt; might fit in with your field, and feel free to &lt;a href=&quot;https://github.com/fair-workflows/nanopub&quot;&gt;try the library out&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The quality of this text was greatly improved by the suggestions of &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, Tobias Kuhn, &lt;a href=&quot;https://orcid.org/0000-0003-1711-7961&quot;&gt;Arnold Kuzniar&lt;/a&gt;, Lars Ridder, &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;, and &lt;a href=&quot;https://medium.com/@s.verhoeven&quot;&gt;Stefan Verhoeven&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 31 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;using-nanopub-a-high-level-user-friendly-python-interface-to-the-nanopublication-network&quot;&gt;Using nanopub, a high-level, user-friendly python interface to the nanopublication network&lt;/h2&gt;
&lt;p&gt;For example, if you want to e.g. search for all nanopublications containing the text Picoides*:&lt;/p&gt;
&lt;p&gt;which returns two results both pointing to the example nanopublication we just discussed:&lt;/p&gt;
&lt;p&gt;{‘np’: ‘&lt;a href=&quot;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA&amp;#x27;&quot;&gt;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA’&lt;/a&gt;, ‘description’: ‘Inter-species interaction of Picoides villosus with Ips’, ‘date’: ‘2020-12-24T10:51:43.931Z’}
{‘np’: ‘&lt;a href=&quot;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA&amp;#x27;&quot;&gt;http://purl.org/np/RAMzGwLotMRSQTHRCS15B6hvuYSyEupGnxZaFU3EmcItA’&lt;/a&gt;, ‘description’: ‘Picoides villosus’, ‘date’: ‘2020-12-24T10:51:43.931Z’}You can then fetch a specific nanopublication directly using its URI:&lt;/p&gt;
&lt;p&gt;This snippet will fetch the nanopublication we discussed earlier, about the interaction of the bird and the beetle, and print the contents of its assertion. Of course, you are not limited to simple text searches. The library has several search methods, including finding nanopubs with a given triple pattern — you can find detailed documentation &lt;a href=&quot;https://nanopub.readthedocs.io/en/latest/searching.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hold-on-i-want-to-publish-nanopublications-of-my-own&quot;&gt;Hold on, I want to publish Nanopublications of my own!&lt;/h2&gt;
&lt;p&gt;To publish to the nanopub server you need to set up your profile. This allows the nanopub server to identify you. Run the following interactive command (on the command line):&lt;/p&gt;
&lt;p&gt;setup_nanopub_profileIt will add and store RSA keys to sign your nanopublications, publish a nanopublication with your name and ORCID iD to declare that you are using using these RSA keys, and store your ORCID iD to automatically add as author to the provenance of any nanopublication you will publish using this library.&lt;/p&gt;
&lt;p&gt;You can then publish a quick claim:&lt;/p&gt;
&lt;p&gt;Published to &lt;a href=&quot;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&quot;&gt;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&lt;/a&gt;View the resulting nanopublication &lt;a href=&quot;http://purl.org/np/RA47eJP2UBJCWuJ324c6Qw0OwtCb8wCrprwSk39am7xck&quot;&gt;here&lt;/a&gt;. Note that the URI of your nanopublication is a signed hash of its contents, making its authorship verifiable and enforcing its immutability — known as a &lt;a href=&quot;https://doi.org/10.1007/978-3-319-07443-6_27&quot;&gt;trusty URI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or, to leverage the true power of semantic technologies, you can build your own RDF graph of triples and publish that:&lt;/p&gt;
&lt;p&gt;The above builds a graph containing a single triple that states (essentially) the concept pointed to by &lt;code&gt;www.example.org/timbernerslee&lt;/code&gt;is of type Person. We use the &lt;a href=&quot;https://github.com/RDFLib/rdflib&quot;&gt;rdflib&lt;/a&gt; library to build the graph, but this is already a dependency of nanopub. A Publication object is then created, using that graph as its assertion, and finally published using the NanopubClient as before. The code produces the following output:&lt;/p&gt;
&lt;p&gt;Published to &lt;a href=&quot;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&quot;&gt;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&lt;/a&gt;You can view the resulting nanopublication &lt;a href=&quot;http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot;&gt;Outlook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nanopub&lt;/code&gt; makes interacting with nanopublications quite intuitive for those with sufficient RDF and python skills. For all others we foresee tools built around &lt;code&gt;nanopub&lt;/code&gt; that make it intuitive for domain-experts (but not RDF-experts) to make use of the nanopublication network.&lt;/p&gt;
&lt;p&gt;There are a couple of those already in the making:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nanotate-tool/nanotate&quot;&gt;nanotate&lt;/a&gt;: Create nanopublications from annotations in PDF-files made with &lt;a href=&quot;https://web.hypothes.is/&quot;&gt;hypothes.is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fair-workflows/fairworkflows&quot;&gt;fairworkflows&lt;/a&gt;: Support the construction, manipulation and publishing of FAIR scientific workflows using semantic technologies. This is developed as part of the wider &lt;a href=&quot;https://www.esciencecenter.nl/projects/fair-is-as-fair-does/&quot;&gt;FAIR is as FAIR does&lt;/a&gt; project at the eScience Center.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The python &lt;code&gt;nanopub&lt;/code&gt; library provides a high-level, user-friendly python interface for the nanopub server, making it easy to publish and search small scientific publications. We created this library to bring nanopublishing to python users and we’re keen to help people make use of it.&lt;/p&gt;
&lt;p&gt;Consider how &lt;a href=&quot;http://nanopub.org/wordpress/&quot;&gt;nanopublications&lt;/a&gt; might fit in with your field, and feel free to &lt;a href=&quot;https://github.com/fair-workflows/nanopub&quot;&gt;try the library out&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The quality of this text was greatly improved by the suggestions of &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, Tobias Kuhn, &lt;a href=&quot;https://orcid.org/0000-0003-1711-7961&quot;&gt;Arnold Kuzniar&lt;/a&gt;, Lars Ridder, &lt;a href=&quot;https://medium.com/@pab.rod&quot;&gt;Pablo Rodríguez-Sánchez&lt;/a&gt;, and &lt;a href=&quot;https://medium.com/@s.verhoeven&quot;&gt;Stefan Verhoeven&lt;/a&gt;.&lt;/p&gt;</content:encoded><author>Robin Richardson</author></item><item><title>Lesson development blitz</title><link>https://blog.esciencecenter.nl/posts/2021-05-11---lesson-development-blitz</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-05-11---lesson-development-blitz</guid><description>&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Testing lessons**&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt=&quot;Lesson development blitz&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;220&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lesson-development-blitz-8f0c1255.47MG0Sfm_ZbfnD9.webp&quot; srcset=&quot;&quot;&gt;
designed by freepik &lt;a href=&quot;https://stories.freepik.com/&quot;&gt;https://stories.freepik.com/&lt;/a&gt;The coordinator asks some of the researchers in the community to use the tutorial and to report any issues or bugs. It is also recommended to organize training activities using the tutorial and gather feedback from participants. The outputs of the evaluation are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a list of issues and bugs.&lt;/li&gt;
&lt;li&gt;whether the tutorial needs polishing (go to step 4) or is ready for a release (go to step 6).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Release​&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lesson development blitz&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;236&quot; height=&quot;227&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lesson-development-blitz-99c8f53f.Daq9_2xG_2qddg.webp&quot; srcset=&quot;&quot;&gt;
designed by freepik &lt;a href=&quot;https://stories.freepik.com/&quot;&gt;https://stories.freepik.com/&lt;/a&gt;The tutorial is released on GitHub in a beta version and published on Zenodo. With this version, the lessons can be used for broader teaching and contributions.&lt;/p&gt;
&lt;h2 id=&quot;at-the-end-of-the-blitz-&quot;&gt;At the end of the blitz …&lt;/h2&gt;
&lt;p&gt;Our development blitz took about one week and the ESMValTool tutorial was released in Beta-version.&lt;/p&gt;
&lt;p&gt;Like every procedure, a development blitz has some pros and cons. A development blitz increases focus​, creates satisfaction and good feeling​, helps communication​, and spreads best practices in the community. However, it may lead to disappointment​, needs lots of commitment​ and slows down decision making​.&lt;/p&gt;
&lt;h2 id=&quot;interesting-readings&quot;&gt;Interesting readings:&lt;/h2&gt;
&lt;p&gt;The Carpentries Curriculum Development Handbook provides guides on designing and developing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;different parts of a tutorial, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/our-curriculum-structure.html#episodes&quot;&gt;episodes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;objectives and scope, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/developing-content.html&quot;&gt;developing content&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;development and release stages, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/the-lesson-life-cycle.html&quot;&gt;lesson life-cycle&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, some blog posts about blitz planning that might be of interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@Future__Friendly/conducting-a-blitz-sprint-19f563bfc9ba&quot;&gt;Conducting a blitz sprint​&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.luxoft.com/blog/sprokhorenko/blitz-planning/&quot;&gt;Blitz planning​&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;acknowledgment&quot;&gt;Acknowledgment&lt;/h2&gt;
&lt;p&gt;Thanks to [Carlos Martinez-Ortiz], [Felipe], [Pablo Rodríguez-Sánchez] and [Tom Bakker] for their feedback.&lt;/p&gt;</description><pubDate>Tue, 11 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Testing lessons**&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt=&quot;Lesson development blitz&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;220&quot; height=&quot;195&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lesson-development-blitz-8f0c1255.47MG0Sfm_ZbfnD9.webp&quot; srcset=&quot;&quot;&gt;
designed by freepik &lt;a href=&quot;https://stories.freepik.com/&quot;&gt;https://stories.freepik.com/&lt;/a&gt;The coordinator asks some of the researchers in the community to use the tutorial and to report any issues or bugs. It is also recommended to organize training activities using the tutorial and gather feedback from participants. The outputs of the evaluation are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a list of issues and bugs.&lt;/li&gt;
&lt;li&gt;whether the tutorial needs polishing (go to step 4) or is ready for a release (go to step 6).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Release​&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Lesson development blitz&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;236&quot; height=&quot;227&quot; src=&quot;https://blog.esciencecenter.nl/_astro/lesson-development-blitz-99c8f53f.Daq9_2xG_2qddg.webp&quot; srcset=&quot;&quot;&gt;
designed by freepik &lt;a href=&quot;https://stories.freepik.com/&quot;&gt;https://stories.freepik.com/&lt;/a&gt;The tutorial is released on GitHub in a beta version and published on Zenodo. With this version, the lessons can be used for broader teaching and contributions.&lt;/p&gt;
&lt;h2 id=&quot;at-the-end-of-the-blitz-&quot;&gt;At the end of the blitz …&lt;/h2&gt;
&lt;p&gt;Our development blitz took about one week and the ESMValTool tutorial was released in Beta-version.&lt;/p&gt;
&lt;p&gt;Like every procedure, a development blitz has some pros and cons. A development blitz increases focus​, creates satisfaction and good feeling​, helps communication​, and spreads best practices in the community. However, it may lead to disappointment​, needs lots of commitment​ and slows down decision making​.&lt;/p&gt;
&lt;h2 id=&quot;interesting-readings&quot;&gt;Interesting readings:&lt;/h2&gt;
&lt;p&gt;The Carpentries Curriculum Development Handbook provides guides on designing and developing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;different parts of a tutorial, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/our-curriculum-structure.html#episodes&quot;&gt;episodes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;objectives and scope, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/developing-content.html&quot;&gt;developing content&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;development and release stages, see &lt;a href=&quot;https://carpentries.github.io/curriculum-development/the-lesson-life-cycle.html&quot;&gt;lesson life-cycle&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, some blog posts about blitz planning that might be of interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@Future__Friendly/conducting-a-blitz-sprint-19f563bfc9ba&quot;&gt;Conducting a blitz sprint​&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.luxoft.com/blog/sprokhorenko/blitz-planning/&quot;&gt;Blitz planning​&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;acknowledgment&quot;&gt;Acknowledgment&lt;/h2&gt;
&lt;p&gt;Thanks to [Carlos Martinez-Ortiz], [Felipe], [Pablo Rodríguez-Sánchez] and [Tom Bakker] for their feedback.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/lesson-development-blitz-99c8f53f.Daq9_2xG.png" medium="image"/><author>Fakhereh (Sarah) Alidoost</author></item><item><title>Using Rust for Scientific Numerical applications: Learning from Past Experiences</title><link>https://blog.esciencecenter.nl/posts/2021-04-14---using-rust-for-scientific-numerical-applications-learning-fr</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-04-14---using-rust-for-scientific-numerical-applications-learning-fr</guid><description>&lt;p&gt;Every experienced programmer knows that both their productivity depends on the abstraction level of the language. The fewer lines of code you write, the fewer bugs you introduce.* However, an increase in abstraction often results in a higher runtime cost (code that needs to run extremely fast is often &lt;em&gt;very&lt;/em&gt; ugly). Rust &lt;a href=&quot;https://carette.xyz/posts/zero_cost_abstraction/&quot;&gt;zero-cost abstraction&lt;/a&gt; allows you to write more concise code by using a higher level abstraction without additional computing cost at runtime. *Rust *&lt;a href=&quot;https://doc.rust-lang.org/book/ch13-02-iterators.html&quot;&gt;&lt;em&gt;iterators&lt;/em&gt;&lt;/a&gt; are a great example of the power of Rust zero cost abstraction. &lt;em&gt;It is fair to mention that zero-cost abstraction is also central in C++.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How much effort is required to maintain the code?**&lt;/p&gt;
&lt;p&gt;If you have ever worked in a medium to large size C/Fortran code base, you certainly know how incredibly difficult and frustrating it can be to maintain it. A recurrent complaint among the programmers in these languages is the dreadful bugs related to unsafe memory management that can take days to trace and reproduce. Fortran programmers are famously known for having &lt;a href=&quot;https://nalgebra.org/&quot;&gt;segmentation faults&lt;/a&gt; for breakfast.&lt;/p&gt;
&lt;p&gt;The Rust type system stands out for its capabilities to rule out memory errors at runtime. The Rust &lt;a href=&quot;https://blog.logrocket.com/introducing-the-rust-borrow-checker/&quot;&gt;borrow checker&lt;/a&gt; is the killer feature that helps to eliminate all those memory bugs while still offering lightning-fast speed.&lt;/p&gt;
&lt;p&gt;Also, as mentioned previously, Rust’s zero cost abstraction allows you to keep a lean code base that is easier to maintain.&lt;/p&gt;
&lt;p&gt;***Note for C++ developer: ***&lt;em&gt;smart pointers partly alleviate the memory management issues, but the borrow checker can help you to extend the safety guarantees to multithreading code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How much effort is required to test the code and write documentation?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Writing documentation in C/C++/Fortran involved bringing a third-party tool like &lt;a href=&quot;https://www.doxygen.nl/index.html&quot;&gt;Doxygen&lt;/a&gt; that we need to install and add to our CMake zoo. Also, we need to learn this tool’s special syntax to write documentation and then pray that the documentation builds.&lt;/p&gt;
&lt;p&gt;Software documentation is essential for scientific code due to the volatile nature of scientific research. *Scientific software without documentation is not legacy code but dead code. *Given the high barrier imposed by traditional languages to write documentation, it is expected that most scientific software is stillborn due to the impossibility to understand what has been done, even by experts in the same field (or sometimes even by the person who wrote it).&lt;/p&gt;
&lt;p&gt;Documenting a Rust project only requires that you write the documentation in markdown inside the source code as shown in &lt;a href=&quot;https://github.com/felipeZ/eigenvalues/blob/master/src/lib.rs&quot;&gt;this example&lt;/a&gt;. Then you just need to run the &lt;code&gt;cargo doc&lt;/code&gt; command and that is it!&lt;/p&gt;
&lt;p&gt;Testing in C/C++/Fortran has a similar fate, they required third-party frameworks that need to be installed and added to CMake. Fortran is particularly painful for testing due to the lack of a standard testing framework, forcing programmers to maintain a bunch of scripts to call the binaries, parse the output, and check the results.&lt;/p&gt;
&lt;p&gt;Rust has a built-in system to test your code, with no third-party libraries. You can have &lt;a href=&quot;https://doc.rust-lang.org/nightly/rust-by-example/testing/unit_testing.html&quot;&gt;unit tests&lt;/a&gt; to check the functionality of a given module at a time, but also &lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html&quot;&gt;integration tests&lt;/a&gt; to check the public interface of your code. You can even run and test the &lt;a href=&quot;https://doc.rust-lang.org/rustdoc/documentation-tests.html&quot;&gt;examples in the documentation&lt;/a&gt;! In summary, writing and running tests is as effortless as you can get it.&lt;/p&gt;
&lt;p&gt;Lowering the barrier to write tests and documentation is an undervalued feature of Rust. I bet that we all agree that code without tests and documentation is short of useless.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I parallelize the application?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Using Rust for Scientific Numerical applications: Learning from Past Experiences&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;349&quot; src=&quot;https://blog.esciencecenter.nl/_astro/using-rust-for-scientific-numerical-appl-ab3f6590.Dl0JlQpe_2uet5c.webp&quot; srcset=&quot;&quot;&gt;
Image: courtesy of &lt;a href=&quot;https://www.instagram.com/qiadraws/&quot;&gt;Chiara Caratelli&lt;/a&gt;&lt;em&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/em&gt;*:* &lt;em&gt;due to my ignorance of the latest Rust developments on multi-node computing (&lt;/em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Message_Passing_Interface&quot;&gt;&lt;em&gt;MPI&lt;/em&gt;&lt;/a&gt;&lt;em&gt;) and GPU integration, I am going to blatantly ignore those two subjects.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scientific simulations like weather prediction, protein binding, fluid dynamics, etc*.* are computationally intensive but often parallelizable (at least on paper!). It goes without saying that we want to make use of all cores available in a given machine. The standard approach is to use something like &lt;a href=&quot;https://www.openmp.org/&quot;&gt;OpenMP&lt;/a&gt; that consists of runtime libraries, compiler directives, &lt;em&gt;etc&lt;/em&gt;. to support shared-memory multithreading programming.&lt;/p&gt;
&lt;p&gt;A quite dreaded moment for scientific software developers is when the serial implementation is working and a new parallel version must be implemented. Seriously, parallel implementation in C/C+/Fortran means that all your &lt;a href=&quot;https://en.wikipedia.org/wiki/There_are_known_knowns&quot;&gt;unknown unknowns&lt;/a&gt; about unsafe memory management suddenly uncover all the obnoxious bugs that you didn’t know about until now, and that you need to track for endless hours.&lt;/p&gt;
&lt;p&gt;As a remedy for all that frustration and wasted time, Rust offers a novel approach coined as &lt;a href=&quot;https://doc.rust-lang.org/book/ch16-00-concurrency.html&quot;&gt;fearless concurrency&lt;/a&gt;. This concept refers to the possibility of writing parallel applications that are free of subtle bugs and can be refactored without introducing new bugs.&lt;/p&gt;
&lt;p&gt;But how does Rust achieve this marvelous formula? It turns out that the Rust type system and &lt;a href=&quot;https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html&quot;&gt;ownership system&lt;/a&gt; keep track of what is safe to share across threads, refusing to compile illegal concurrent memory transactions that would have resulted in runtime issues. So, the Rust compiler happily raises compilation errors whenever you are trying to use memory in an unsafe way instead of unleashing Godzilla in the middle of your simulation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Using Rust for Scientific Numerical applications: Learning from Past Experiences&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/using-rust-for-scientific-numerical-appl-622b6b49.DO8qr1Y8_Z1Mo3P.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markuswinkler?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Markus Winkler&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since Rust is a system programming language, rather than choosing a single parallelism model, it allows multiple low level models like message-passing, share-state, &lt;em&gt;etc&lt;/em&gt;. The good news is that we don’t need to use the primitives ourselves, instead, we can use the community-provided libraries like &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; that build on top of those primitives. &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; offers powerful functionality like &lt;a href=&quot;https://docs.rs/rayon/1.5.0/rayon/iter/index.html&quot;&gt;parallel iterators&lt;/a&gt; that allow us to execute operations on the elements of an &lt;a href=&quot;https://doc.rust-lang.org/book/ch13-02-iterators.html&quot;&gt;iterator&lt;/a&gt; in parallel, with minimal changes in the source code.&lt;/p&gt;
&lt;p&gt;What is even better, you can use libraries like &lt;a href=&quot;https://github.com/rust-ndarray/ndarray&quot;&gt;ndarray&lt;/a&gt; that has a Numpy-style API to manipulate arrays, while simultaneously offering features like an interface to &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; to run your array operations in parallel.&lt;/p&gt;
&lt;h2 id=&quot;the-challenges-of-using-rust-for-scientific-applications&quot;&gt;The Challenges of using Rust for scientific applications&lt;/h2&gt;
&lt;p&gt;Rust is a promising language for scientific applications but there are several challenges that need to be overcome before the language can gain significant traction by the scientific community.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust is a low-level language with many powerful features&lt;/strong&gt;. In other words, actually you do not learn Rust during a Saturday afternoon while drinking mojitos. It takes significant effort and time before you can start writing with confidence. Fortunately the Rust community is very open and welcoming and there are always people willing to help. Besides, the compiler has the most informative error messages that I have seen in any programming language. In short, the learning curve is steeper than Python, but you will have a single memory-safe language to rule them all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There may be some functionality that is still missing or unstable&lt;/strong&gt;. The Rust ecosystem is growing rapidly and more people are coming out with great libraries. The community is always happy to help you to come up with a solution for your missing functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interoperability with C/C++&lt;/strong&gt;. We certainly do not want to rewrite everything from scratch, therefore we would like to reuse as much code as we can from C/C++. For the Rust community, smooth interoperability with C/C++ is a top priority.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;any-further-thoughts&quot;&gt;Any further thoughts?&lt;/h2&gt;
&lt;p&gt;I hope that I could give you an idea about using Rust for scientific software applications. Comments and thoughts are appreciated.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;Thanks to Chiara Caratelli from providing the great drawings. Also my special thanks to [Florian Huber], [Carlos Martinez-Ortiz,] [Patrick Bos] and Tom Bakker for their help editing the text.&lt;/p&gt;</description><pubDate>Wed, 14 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every experienced programmer knows that both their productivity depends on the abstraction level of the language. The fewer lines of code you write, the fewer bugs you introduce.* However, an increase in abstraction often results in a higher runtime cost (code that needs to run extremely fast is often &lt;em&gt;very&lt;/em&gt; ugly). Rust &lt;a href=&quot;https://carette.xyz/posts/zero_cost_abstraction/&quot;&gt;zero-cost abstraction&lt;/a&gt; allows you to write more concise code by using a higher level abstraction without additional computing cost at runtime. *Rust *&lt;a href=&quot;https://doc.rust-lang.org/book/ch13-02-iterators.html&quot;&gt;&lt;em&gt;iterators&lt;/em&gt;&lt;/a&gt; are a great example of the power of Rust zero cost abstraction. &lt;em&gt;It is fair to mention that zero-cost abstraction is also central in C++.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How much effort is required to maintain the code?**&lt;/p&gt;
&lt;p&gt;If you have ever worked in a medium to large size C/Fortran code base, you certainly know how incredibly difficult and frustrating it can be to maintain it. A recurrent complaint among the programmers in these languages is the dreadful bugs related to unsafe memory management that can take days to trace and reproduce. Fortran programmers are famously known for having &lt;a href=&quot;https://nalgebra.org/&quot;&gt;segmentation faults&lt;/a&gt; for breakfast.&lt;/p&gt;
&lt;p&gt;The Rust type system stands out for its capabilities to rule out memory errors at runtime. The Rust &lt;a href=&quot;https://blog.logrocket.com/introducing-the-rust-borrow-checker/&quot;&gt;borrow checker&lt;/a&gt; is the killer feature that helps to eliminate all those memory bugs while still offering lightning-fast speed.&lt;/p&gt;
&lt;p&gt;Also, as mentioned previously, Rust’s zero cost abstraction allows you to keep a lean code base that is easier to maintain.&lt;/p&gt;
&lt;p&gt;***Note for C++ developer: ***&lt;em&gt;smart pointers partly alleviate the memory management issues, but the borrow checker can help you to extend the safety guarantees to multithreading code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How much effort is required to test the code and write documentation?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Writing documentation in C/C++/Fortran involved bringing a third-party tool like &lt;a href=&quot;https://www.doxygen.nl/index.html&quot;&gt;Doxygen&lt;/a&gt; that we need to install and add to our CMake zoo. Also, we need to learn this tool’s special syntax to write documentation and then pray that the documentation builds.&lt;/p&gt;
&lt;p&gt;Software documentation is essential for scientific code due to the volatile nature of scientific research. *Scientific software without documentation is not legacy code but dead code. *Given the high barrier imposed by traditional languages to write documentation, it is expected that most scientific software is stillborn due to the impossibility to understand what has been done, even by experts in the same field (or sometimes even by the person who wrote it).&lt;/p&gt;
&lt;p&gt;Documenting a Rust project only requires that you write the documentation in markdown inside the source code as shown in &lt;a href=&quot;https://github.com/felipeZ/eigenvalues/blob/master/src/lib.rs&quot;&gt;this example&lt;/a&gt;. Then you just need to run the &lt;code&gt;cargo doc&lt;/code&gt; command and that is it!&lt;/p&gt;
&lt;p&gt;Testing in C/C++/Fortran has a similar fate, they required third-party frameworks that need to be installed and added to CMake. Fortran is particularly painful for testing due to the lack of a standard testing framework, forcing programmers to maintain a bunch of scripts to call the binaries, parse the output, and check the results.&lt;/p&gt;
&lt;p&gt;Rust has a built-in system to test your code, with no third-party libraries. You can have &lt;a href=&quot;https://doc.rust-lang.org/nightly/rust-by-example/testing/unit_testing.html&quot;&gt;unit tests&lt;/a&gt; to check the functionality of a given module at a time, but also &lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html&quot;&gt;integration tests&lt;/a&gt; to check the public interface of your code. You can even run and test the &lt;a href=&quot;https://doc.rust-lang.org/rustdoc/documentation-tests.html&quot;&gt;examples in the documentation&lt;/a&gt;! In summary, writing and running tests is as effortless as you can get it.&lt;/p&gt;
&lt;p&gt;Lowering the barrier to write tests and documentation is an undervalued feature of Rust. I bet that we all agree that code without tests and documentation is short of useless.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I parallelize the application?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Using Rust for Scientific Numerical applications: Learning from Past Experiences&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;349&quot; src=&quot;https://blog.esciencecenter.nl/_astro/using-rust-for-scientific-numerical-appl-ab3f6590.Dl0JlQpe_2uet5c.webp&quot; srcset=&quot;&quot;&gt;
Image: courtesy of &lt;a href=&quot;https://www.instagram.com/qiadraws/&quot;&gt;Chiara Caratelli&lt;/a&gt;&lt;em&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/em&gt;*:* &lt;em&gt;due to my ignorance of the latest Rust developments on multi-node computing (&lt;/em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Message_Passing_Interface&quot;&gt;&lt;em&gt;MPI&lt;/em&gt;&lt;/a&gt;&lt;em&gt;) and GPU integration, I am going to blatantly ignore those two subjects.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scientific simulations like weather prediction, protein binding, fluid dynamics, etc*.* are computationally intensive but often parallelizable (at least on paper!). It goes without saying that we want to make use of all cores available in a given machine. The standard approach is to use something like &lt;a href=&quot;https://www.openmp.org/&quot;&gt;OpenMP&lt;/a&gt; that consists of runtime libraries, compiler directives, &lt;em&gt;etc&lt;/em&gt;. to support shared-memory multithreading programming.&lt;/p&gt;
&lt;p&gt;A quite dreaded moment for scientific software developers is when the serial implementation is working and a new parallel version must be implemented. Seriously, parallel implementation in C/C+/Fortran means that all your &lt;a href=&quot;https://en.wikipedia.org/wiki/There_are_known_knowns&quot;&gt;unknown unknowns&lt;/a&gt; about unsafe memory management suddenly uncover all the obnoxious bugs that you didn’t know about until now, and that you need to track for endless hours.&lt;/p&gt;
&lt;p&gt;As a remedy for all that frustration and wasted time, Rust offers a novel approach coined as &lt;a href=&quot;https://doc.rust-lang.org/book/ch16-00-concurrency.html&quot;&gt;fearless concurrency&lt;/a&gt;. This concept refers to the possibility of writing parallel applications that are free of subtle bugs and can be refactored without introducing new bugs.&lt;/p&gt;
&lt;p&gt;But how does Rust achieve this marvelous formula? It turns out that the Rust type system and &lt;a href=&quot;https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html&quot;&gt;ownership system&lt;/a&gt; keep track of what is safe to share across threads, refusing to compile illegal concurrent memory transactions that would have resulted in runtime issues. So, the Rust compiler happily raises compilation errors whenever you are trying to use memory in an unsafe way instead of unleashing Godzilla in the middle of your simulation.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Using Rust for Scientific Numerical applications: Learning from Past Experiences&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/using-rust-for-scientific-numerical-appl-622b6b49.DO8qr1Y8_Z1Mo3P.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@markuswinkler?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Markus Winkler&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since Rust is a system programming language, rather than choosing a single parallelism model, it allows multiple low level models like message-passing, share-state, &lt;em&gt;etc&lt;/em&gt;. The good news is that we don’t need to use the primitives ourselves, instead, we can use the community-provided libraries like &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; that build on top of those primitives. &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; offers powerful functionality like &lt;a href=&quot;https://docs.rs/rayon/1.5.0/rayon/iter/index.html&quot;&gt;parallel iterators&lt;/a&gt; that allow us to execute operations on the elements of an &lt;a href=&quot;https://doc.rust-lang.org/book/ch13-02-iterators.html&quot;&gt;iterator&lt;/a&gt; in parallel, with minimal changes in the source code.&lt;/p&gt;
&lt;p&gt;What is even better, you can use libraries like &lt;a href=&quot;https://github.com/rust-ndarray/ndarray&quot;&gt;ndarray&lt;/a&gt; that has a Numpy-style API to manipulate arrays, while simultaneously offering features like an interface to &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot;&gt;Rayon&lt;/a&gt; to run your array operations in parallel.&lt;/p&gt;
&lt;h2 id=&quot;the-challenges-of-using-rust-for-scientific-applications&quot;&gt;The Challenges of using Rust for scientific applications&lt;/h2&gt;
&lt;p&gt;Rust is a promising language for scientific applications but there are several challenges that need to be overcome before the language can gain significant traction by the scientific community.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust is a low-level language with many powerful features&lt;/strong&gt;. In other words, actually you do not learn Rust during a Saturday afternoon while drinking mojitos. It takes significant effort and time before you can start writing with confidence. Fortunately the Rust community is very open and welcoming and there are always people willing to help. Besides, the compiler has the most informative error messages that I have seen in any programming language. In short, the learning curve is steeper than Python, but you will have a single memory-safe language to rule them all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There may be some functionality that is still missing or unstable&lt;/strong&gt;. The Rust ecosystem is growing rapidly and more people are coming out with great libraries. The community is always happy to help you to come up with a solution for your missing functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interoperability with C/C++&lt;/strong&gt;. We certainly do not want to rewrite everything from scratch, therefore we would like to reuse as much code as we can from C/C++. For the Rust community, smooth interoperability with C/C++ is a top priority.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;any-further-thoughts&quot;&gt;Any further thoughts?&lt;/h2&gt;
&lt;p&gt;I hope that I could give you an idea about using Rust for scientific software applications. Comments and thoughts are appreciated.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;Thanks to Chiara Caratelli from providing the great drawings. Also my special thanks to [Florian Huber], [Carlos Martinez-Ortiz,] [Patrick Bos] and Tom Bakker for their help editing the text.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/using-rust-for-scientific-numerical-appl-ab3f6590.Dl0JlQpe.png" medium="image"/><author>Felipe</author></item><item><title>Can mathematical models predict the future?</title><link>https://blog.esciencecenter.nl/posts/2021-03-18---can-mathematical-models-predict-the-future</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-03-18---can-mathematical-models-predict-the-future</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4000&quot; height=&quot;6000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_nCQRZRSdypw2jmuH-8bc780bd.7sAvCYMP_xxG8i.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by John Moeses Bauan on Unsplash&lt;/p&gt;
&lt;p&gt;Let me start right away with a question: do you think that the future can be predicted? When formulated like this, this question makes us think of crystal balls, palm reading, fortune tellers, … and ultimately invites us to answer with a loud and clear: &lt;em&gt;“no”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Nevertheless, every day we read things like &lt;em&gt;“the average mean temperature will rise 0.5 ⁰C worldwide in the next ten years”&lt;/em&gt;, or &lt;em&gt;“the contagion curve of COVID-19 will start to flatten in the next 3 days”.&lt;/em&gt; And we read themwithout raising a single eyebrow. Indeed, these sentences evoke in us feelings of rigor and expert knowledge. But, are they not predictions about the future?&lt;/p&gt;
&lt;p&gt;If we dive into the foundations of this kind of forecasts, chances are that they had been obtained using mathematical models. Most likely, they will have error bars attached to them, and provide numerous caveats that, somehow, subtract some strength from the conclusions.&lt;/p&gt;
&lt;p&gt;Mathematical models are getting more attention than ever. The COVID-19 pandemic made them jump from the inner pages of specialized journals to the front pages of press and TV news. For audience and format reasons, the necessary details to understand the reach and limitations of these models are rarely mentioned. This may lead to a wrong impression about their power.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-mathematical-model&quot;&gt;What is a mathematical model?&lt;/h2&gt;
&lt;p&gt;==A model is a description of a phenomenon under study. A mathematical model just uses mathematical language in this description.==&lt;/p&gt;
&lt;p&gt;It sounds almost like a tongue-twister, but is actually anything but exotic. Even more, it is very likely you have worked with mathematical models before. Particularly in school. Do you remember those problems about compound interest? Or those about the movement of a projectile in physics class? Did your teachers not ask you to calculate the future evolution of a bank account or the time and place of the projectile’s impact?&lt;/p&gt;
&lt;p&gt;Contrary to what is often thought, mathematical models do not answer the question &lt;em&gt;“What will happen?”&lt;/em&gt;, but to a subtly different one: &lt;em&gt;“What would happen if…?”&lt;/em&gt;. This constitutes, simultaneously, the strength and the weakness of mathematical modeling.&lt;/p&gt;
&lt;p&gt;Let me illustrate my point with the example of a body in free fall. Perhaps you remember your own skepticism when, in school, your physics teacher told you that a feather and a cannonball free-falling from the same height touch the ground at the very same moment.&lt;/p&gt;
&lt;p&gt;Sounds strange, but it is rigorously true. In fact, it is so rigorously true, that if we just drop the word &lt;em&gt;“free”&lt;/em&gt; from &lt;em&gt;“free-falling”&lt;/em&gt;, the statement is not true anymore. Free falls require the absence of an atmosphere, and thus do not happen often in our daily life. Still skeptical? Check the video below:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KDp1tiUsZw8&quot;&gt;https://www.youtube.com/watch?v=KDp1tiUsZw8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we try to apply the model of free-fall to the fall of an everyday object, we’ll soon see that its prediction fails miserably. We just used an inadequate model, because the free-fall model answers a question we don’t need to answer: &lt;em&gt;“what would happen if I let this object fall in the absence of an atmosphere?”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When we mathematicians build our models, we often start with a very simple one, and we keep adding features to it while we need them. When do we stop, then? When the model is sufficiently good. That is, when we are happy about the light it sheds onto the phenomenon under study.&lt;/p&gt;
&lt;p&gt;If we are interested in understanding the fall of a feather, the above-mentioned free-fall model will certainly not make us happy. If we add some drag terms to the model, accounting for the presence of an atmosphere, the results will be much better (although still not perfect, because there will always be small discrepancies between the predictions and the experiment).&lt;/p&gt;
&lt;p&gt;All models, no exception, are more or less sophisticated approximations of reality. But they are never perfect. Unfortunately, it is not always easy to quantify the precision of a mathematical model. As a consequence, it is also hard to communicate its limitations to a general audience.&lt;/p&gt;
&lt;h2 id=&quot;why-do-we-use-them&quot;&gt;Why do we use them?&lt;/h2&gt;
&lt;p&gt;If all mathematical models are approximations, why do we use them? There is a simple answer to this: we use them because they are useful. Models’ capacity of answering the question: &lt;em&gt;“What would happen if…”&lt;/em&gt;, makes them an excellent substitute for scientific experiments.&lt;/p&gt;
&lt;p&gt;In science, the experiment is the highest authority, but sometimes we have no choice but to not perform them. We either use a computational/mathematical model, or we are stuck. Some examples of this situation are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unfeasible experiments: such as studying a black hole on site.&lt;/li&gt;
&lt;li&gt;Costly or very hard experiments: such as studying plankton populations, a problem whose scale in space and time is, literally, oceanic and of the order of decades.&lt;/li&gt;
&lt;li&gt;Destructive or dangerous experiments: such as studying the effects of a earthquake on a city.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Models are also very useful to obtain visualizations that, otherwise, will be difficult or impossible to obtain experimentally. Think for instance of the movement of the wind around a turbine, with the pressure painted as color.&lt;/p&gt;
&lt;p&gt;Models also help us understanding. Even models with a very humble predictive power can be very useful to understand complex problems. For instance, thanks to a &lt;a href=&quot;https://blog.esciencecenter.nl/a-mathematician-in-quarantine-4555cfbf9f60&quot;&gt;very simple model of epidemic propagation&lt;/a&gt; from the 1920s we know that there are thresholds where the contagion becomes explosive. The model is useless if we want to know where exactly that threshold is, but it provides the very idea that such a threshold exists.&lt;/p&gt;
&lt;h2 id=&quot;mathematicians-cannot-predict-the-future&quot;&gt;Mathematicians cannot predict the future&lt;/h2&gt;
&lt;p&gt;Our initial question was: can the future be forecasted? No sensible person will ever answer &lt;em&gt;“yes, of course, always”&lt;/em&gt;. I hope to have convinced you that mathematicians, who most of the time are also sensible persons, neither will answer so.&lt;/p&gt;
&lt;p&gt;Science is, by its own nature, a fundamentally incomplete enterprise. This is true whether we use letters or formulas to write it. Mathematical models have to be consumed with no less than the same healthy skepticism we use with the weather forecast.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The quality of this text was greatly improved by the suggestions of &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@lourensveen&quot;&gt;Lourens Veen&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@f.huber&quot;&gt;Florian Huber&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This article is an adapted translation from an article the same author published in&lt;/em&gt; &lt;a href=&quot;https://theconversation.com/&quot;&gt;&lt;em&gt;The Conversation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under a Creative Commons license. If you can (and want to) read Spanish, visit the&lt;/em&gt; &lt;a href=&quot;https://theconversation.com/los-modelos-matematicos-no-predicen-el-futuro-pero-ayudan-a-entenderlo-147299&quot;&gt;&lt;em&gt;original article&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Thu, 18 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4000&quot; height=&quot;6000&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_nCQRZRSdypw2jmuH-8bc780bd.7sAvCYMP_xxG8i.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by John Moeses Bauan on Unsplash&lt;/p&gt;
&lt;p&gt;Let me start right away with a question: do you think that the future can be predicted? When formulated like this, this question makes us think of crystal balls, palm reading, fortune tellers, … and ultimately invites us to answer with a loud and clear: &lt;em&gt;“no”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Nevertheless, every day we read things like &lt;em&gt;“the average mean temperature will rise 0.5 ⁰C worldwide in the next ten years”&lt;/em&gt;, or &lt;em&gt;“the contagion curve of COVID-19 will start to flatten in the next 3 days”.&lt;/em&gt; And we read themwithout raising a single eyebrow. Indeed, these sentences evoke in us feelings of rigor and expert knowledge. But, are they not predictions about the future?&lt;/p&gt;
&lt;p&gt;If we dive into the foundations of this kind of forecasts, chances are that they had been obtained using mathematical models. Most likely, they will have error bars attached to them, and provide numerous caveats that, somehow, subtract some strength from the conclusions.&lt;/p&gt;
&lt;p&gt;Mathematical models are getting more attention than ever. The COVID-19 pandemic made them jump from the inner pages of specialized journals to the front pages of press and TV news. For audience and format reasons, the necessary details to understand the reach and limitations of these models are rarely mentioned. This may lead to a wrong impression about their power.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-mathematical-model&quot;&gt;What is a mathematical model?&lt;/h2&gt;
&lt;p&gt;==A model is a description of a phenomenon under study. A mathematical model just uses mathematical language in this description.==&lt;/p&gt;
&lt;p&gt;It sounds almost like a tongue-twister, but is actually anything but exotic. Even more, it is very likely you have worked with mathematical models before. Particularly in school. Do you remember those problems about compound interest? Or those about the movement of a projectile in physics class? Did your teachers not ask you to calculate the future evolution of a bank account or the time and place of the projectile’s impact?&lt;/p&gt;
&lt;p&gt;Contrary to what is often thought, mathematical models do not answer the question &lt;em&gt;“What will happen?”&lt;/em&gt;, but to a subtly different one: &lt;em&gt;“What would happen if…?”&lt;/em&gt;. This constitutes, simultaneously, the strength and the weakness of mathematical modeling.&lt;/p&gt;
&lt;p&gt;Let me illustrate my point with the example of a body in free fall. Perhaps you remember your own skepticism when, in school, your physics teacher told you that a feather and a cannonball free-falling from the same height touch the ground at the very same moment.&lt;/p&gt;
&lt;p&gt;Sounds strange, but it is rigorously true. In fact, it is so rigorously true, that if we just drop the word &lt;em&gt;“free”&lt;/em&gt; from &lt;em&gt;“free-falling”&lt;/em&gt;, the statement is not true anymore. Free falls require the absence of an atmosphere, and thus do not happen often in our daily life. Still skeptical? Check the video below:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KDp1tiUsZw8&quot;&gt;https://www.youtube.com/watch?v=KDp1tiUsZw8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we try to apply the model of free-fall to the fall of an everyday object, we’ll soon see that its prediction fails miserably. We just used an inadequate model, because the free-fall model answers a question we don’t need to answer: &lt;em&gt;“what would happen if I let this object fall in the absence of an atmosphere?”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When we mathematicians build our models, we often start with a very simple one, and we keep adding features to it while we need them. When do we stop, then? When the model is sufficiently good. That is, when we are happy about the light it sheds onto the phenomenon under study.&lt;/p&gt;
&lt;p&gt;If we are interested in understanding the fall of a feather, the above-mentioned free-fall model will certainly not make us happy. If we add some drag terms to the model, accounting for the presence of an atmosphere, the results will be much better (although still not perfect, because there will always be small discrepancies between the predictions and the experiment).&lt;/p&gt;
&lt;p&gt;All models, no exception, are more or less sophisticated approximations of reality. But they are never perfect. Unfortunately, it is not always easy to quantify the precision of a mathematical model. As a consequence, it is also hard to communicate its limitations to a general audience.&lt;/p&gt;
&lt;h2 id=&quot;why-do-we-use-them&quot;&gt;Why do we use them?&lt;/h2&gt;
&lt;p&gt;If all mathematical models are approximations, why do we use them? There is a simple answer to this: we use them because they are useful. Models’ capacity of answering the question: &lt;em&gt;“What would happen if…”&lt;/em&gt;, makes them an excellent substitute for scientific experiments.&lt;/p&gt;
&lt;p&gt;In science, the experiment is the highest authority, but sometimes we have no choice but to not perform them. We either use a computational/mathematical model, or we are stuck. Some examples of this situation are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unfeasible experiments: such as studying a black hole on site.&lt;/li&gt;
&lt;li&gt;Costly or very hard experiments: such as studying plankton populations, a problem whose scale in space and time is, literally, oceanic and of the order of decades.&lt;/li&gt;
&lt;li&gt;Destructive or dangerous experiments: such as studying the effects of a earthquake on a city.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Models are also very useful to obtain visualizations that, otherwise, will be difficult or impossible to obtain experimentally. Think for instance of the movement of the wind around a turbine, with the pressure painted as color.&lt;/p&gt;
&lt;p&gt;Models also help us understanding. Even models with a very humble predictive power can be very useful to understand complex problems. For instance, thanks to a &lt;a href=&quot;https://blog.esciencecenter.nl/a-mathematician-in-quarantine-4555cfbf9f60&quot;&gt;very simple model of epidemic propagation&lt;/a&gt; from the 1920s we know that there are thresholds where the contagion becomes explosive. The model is useless if we want to know where exactly that threshold is, but it provides the very idea that such a threshold exists.&lt;/p&gt;
&lt;h2 id=&quot;mathematicians-cannot-predict-the-future&quot;&gt;Mathematicians cannot predict the future&lt;/h2&gt;
&lt;p&gt;Our initial question was: can the future be forecasted? No sensible person will ever answer &lt;em&gt;“yes, of course, always”&lt;/em&gt;. I hope to have convinced you that mathematicians, who most of the time are also sensible persons, neither will answer so.&lt;/p&gt;
&lt;p&gt;Science is, by its own nature, a fundamentally incomplete enterprise. This is true whether we use letters or formulas to write it. Mathematical models have to be consumed with no less than the same healthy skepticism we use with the weather forecast.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The quality of this text was greatly improved by the suggestions of &lt;a href=&quot;https://egpbos.medium.com/&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@lourensveen&quot;&gt;Lourens Veen&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@f.huber&quot;&gt;Florian Huber&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This article is an adapted translation from an article the same author published in&lt;/em&gt; &lt;a href=&quot;https://theconversation.com/&quot;&gt;&lt;em&gt;The Conversation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under a Creative Commons license. If you can (and want to) read Spanish, visit the&lt;/em&gt; &lt;a href=&quot;https://theconversation.com/los-modelos-matematicos-no-predicen-el-futuro-pero-ayudan-a-entenderlo-147299&quot;&gt;&lt;em&gt;original article&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_nCQRZRSdypw2jmuH-8bc780bd.7sAvCYMP.webp" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Automate chores with GitHub Actions</title><link>https://blog.esciencecenter.nl/posts/2021-03-05---automate-chores-with-github-actions</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-03-05---automate-chores-with-github-actions</guid><description>&lt;h2 id=&quot;how-i-keep-my-heroku-web-apps-data-up-to-date-automatically&quot;&gt;How I keep my Heroku web-app’s data up-to-date automatically&lt;/h2&gt;
&lt;p&gt;Scientists, open source developers, and basically probably most people, have to deal with one common obstacle in life: lack of funds to do all the stuff.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;593&quot; height=&quot;421&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JECSe723rgCyyHyK-48ff0ae8.CC1T0dJb_1nkBT7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In particular in science and open source software, we cannot be bothered to maintain the stuff we left behind (at least, not on the boss’s time). It’s a never-ending quest towards novelty. People just tend to be more forthcoming in the wallet area when fancy new features or knowledge are promised.&lt;/p&gt;
&lt;p&gt;This is why it is vital that we automate the crap out of everything we humanly can, especially if what we built is some kind of service.&lt;/p&gt;
&lt;p&gt;A few months ago, I launched a small web-app called &lt;a href=&quot;http://coalitiewijzer.herokuapp.com/&quot;&gt;Coalitiewijzer&lt;/a&gt;. It uses data from &lt;a href=&quot;https://peilingwijzer.tomlouwerse.nl/&quot;&gt;Peilingwijzer&lt;/a&gt; (which combines major political polls into one) that is updated in irregular intervals. So you guessed it: we’re going to automate the ingestion of that data into the Coalitiewijzer.&lt;/p&gt;
&lt;p&gt;In this short post, I’ll show you how I did this using GitHub Actions. GitHub Actions is a Continuous Integration (CI) provider that (obviously) integrates well with GitHub. If you want to know more about CI in general, I recommend checking out our &lt;a href=&quot;https://guide.esciencecenter.nl/#/best_practices/testing&quot;&gt;Guide&lt;/a&gt;. I’ll assume some working knowledge on this and also on Git, GitHub and GitHub Actions themselves. &lt;a href=&quot;https://blog.esciencecenter.nl/coalition-polls-for-the-people-with-coalitiewijzer-68bca83b95e7&quot;&gt;For more background info about the app itself, check out my other blog post&lt;/a&gt;. This article is basically an add-on to that one. To sum up this article, we’ll look at four steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up a basic GitHub Actions &lt;strong&gt;workflow that runs daily&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Update the data and commit to your Git repo&lt;/li&gt;
&lt;li&gt;Push this from a GitHub Actions runner back to the GitHub repo&lt;/li&gt;
&lt;li&gt;Deploy your app from GitHub Actions to Heroku&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you just want to take a shortcut straight to the code: &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/f9c2712/.github/workflows/update.yml&quot;&gt;here is the current GitHub Actions workflow file I wrote&lt;/a&gt;. For those who like to read poor prose instead: read on!&lt;/p&gt;
&lt;h2 id=&quot;daily-running-workflow&quot;&gt;Daily running workflow&lt;/h2&gt;
&lt;p&gt;To start a new GitHub Actions workflow file, GitHub offers a convenient “New workflow” button under the Actions tab in your repo. You can also copy-paste the basic example in the &lt;a href=&quot;https://docs.github.com/en/actions/quickstart&quot;&gt;Actions Quickstart guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These basic workflows typically only trigger on a push to your GitHub repo, as specified by the &lt;code&gt;on: push&lt;/code&gt; line. We’ll want to change that into something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  schedule:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; cron:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &apos;0 17 * * *&apos;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # 17:00 UTC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  workflow_dispatch:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The weird string between single quotes is &lt;a href=&quot;https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events&quot;&gt;cron syntax, which is explained in the docs&lt;/a&gt;. It allows you to specify at which times you want the workflow to run, in this case at 17:00. The timezone is UTC, keep that in mind.&lt;/p&gt;
&lt;p&gt;The last line is actually unrelated, but quite useful nonetheless. It allows you to manually start the workflow from the Actions page, which I found to be essential wihle testing my workflow.&lt;/p&gt;
&lt;h2 id=&quot;updating-the-data&quot;&gt;Updating the data&lt;/h2&gt;
&lt;p&gt;My app uses data from &lt;a href=&quot;https://peilingwijzer.tomlouwerse.nl/&quot;&gt;Peilingwijzer,&lt;/a&gt; which I preprocess for use in my app and then store in a pickle file. For details on this, see the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;update script on GitHub,&lt;/a&gt; or check out the &lt;a href=&quot;https://blog.esciencecenter.nl/coalition-polls-for-the-people-with-coalitiewijzer-68bca83b95e7&quot;&gt;blog post about the app&lt;/a&gt;. The pickle file has to be committed to the repo and then I can deploy to Heroku with the new data.&lt;/p&gt;
&lt;p&gt;This can all be done with a shell script that looks roughly like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;set &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;e                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# make the script end on errors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python update_numbers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;py&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # download new data and dump to files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git add [the updated files]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;updated data&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Python script does the actual data downloading and mangling and dumps the results into files that the web-app uses. These are then committed to the repo.&lt;/p&gt;
&lt;p&gt;To run this script (in particular the &lt;code&gt;git commit&lt;/code&gt;), you do need to configure the git client on the GitHub Actions runner. You can do this with a workflow step at any time before running the commit command. Add this to your workflow job in the yml file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; configure git user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  run:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local user.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${{ github.actor }}@users.noreply.github.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local user.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${{ github.actor }}&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This commits under your own GitHub user name (or, in general, the username of the one that triggers the workflow to run), so it’ll identify the commits to be yours. It won’t do certification unless you also somehow configure that (perhaps using GitHub secrets, see the Heroku section below). You can fill in any name you want, though, so you could also put something like “Actions bot”.&lt;/p&gt;
&lt;h2 id=&quot;push-back-to-your-github-repo&quot;&gt;Push back to your GitHub repo&lt;/h2&gt;
&lt;p&gt;One of the beauties of GitHub Actions is the great availability of … well, Actions. These are pre-baked recipes for steps that you can very conveniently plug and play. To be precise, you can add such a step to your job, which is part of your Actions pipeline.&lt;/p&gt;
&lt;p&gt;For the next step, I needed to push the commit made above into the GitHub repo from within the GitHub (Actions) infrastructure itself. I was a bit anxious about whether I would find an Action which allowed me to do this. It feels like a potential security leak. Luckily, it turns out &lt;a href=&quot;https://github.com/marketplace/actions/github-push#example-workflow-file&quot;&gt;there is already an Action for this very task&lt;/a&gt;. Hurray! The &lt;a href=&quot;https://github.com/ad-m/github-push-action&quot;&gt;Action’s source&lt;/a&gt; can easily be checked if you’re worried about security.&lt;/p&gt;
&lt;p&gt;Just add the following step to your job after running the update script:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; name:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ad&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;github&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;action@v0.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    github_token:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{ secrets.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    branch:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{ github.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this to work, one more step is necessary. You also need to add two options to your checkout step (at least, this is what I figure from the &lt;a href=&quot;https://github.com/marketplace/actions/github-push#usage&quot;&gt;Action docs&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;checkout@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    persist&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;credentials:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    fetch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;depth:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
&lt;h2 id=&quot;deploying-to-heroku&quot;&gt;Deploying to Heroku&lt;/h2&gt;
&lt;p&gt;Finally, after the data has been updated in the Git repo, the Coalitiewijzer app can be deployed back onto Heroku (which runs &lt;a href=&quot;http://coalitiewijzer.herokuapp.com/&quot;&gt;the app, live here&lt;/a&gt;). Heroku deployment can be done by just pushing your repo directly to the Heroku servers. Really convenient!&lt;/p&gt;
&lt;p&gt;So, since this is again just a git push, albeit to a different repo, this should not be a problem. And, indeed, a &lt;a href=&quot;https://github.com/marketplace/actions/deploy-to-heroku&quot;&gt;Deploy to Heroku Action already exists&lt;/a&gt; for this very purpose!&lt;/p&gt;
&lt;p&gt;To make this work, you need to add your Heroku API key &lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository&quot;&gt;to your GitHub repo’s secrets (instructions here)&lt;/a&gt;. You can find the Heroku API key in your &lt;a href=&quot;https://dashboard.heroku.com/account&quot;&gt;Heroku account&lt;/a&gt;. Call it &lt;code&gt;HEROKU_API_KEY&lt;/code&gt; if you want the snippet below to work.&lt;/p&gt;
&lt;p&gt;After that, you just add the action to your workflow job, like described in the action’s documentation (replace the boldfaced parts):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; akhileshns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;heroku&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deploy@v3.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10.9&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; # This is the action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_api_key:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{secrets.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HEROKU_API_KEY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_app_name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; your_app_name_on_heroku&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_email:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; your@email.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be careful with this key, because it gives access to your full Heroku account.&lt;/p&gt;
&lt;p&gt;And that’s it! From now on, your updates will be pushed back to the GitHub repo and deployed on Heroku.&lt;/p&gt;
&lt;p&gt;Of course, this is just one of many things you could automate using GitHub Actions. The combination with running actual servers on Heroku for free is icing on the cake. Of course, if you want more performance, more MBs, more connections, etcetera, you can pay them for that. But for low profile web-apps, the free package is really a great deal.&lt;/p&gt;
&lt;p&gt;Let me know if you have any comments or questions. I’m happy to help!&lt;/p&gt;</description><pubDate>Fri, 05 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-i-keep-my-heroku-web-apps-data-up-to-date-automatically&quot;&gt;How I keep my Heroku web-app’s data up-to-date automatically&lt;/h2&gt;
&lt;p&gt;Scientists, open source developers, and basically probably most people, have to deal with one common obstacle in life: lack of funds to do all the stuff.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;593&quot; height=&quot;421&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_JECSe723rgCyyHyK-48ff0ae8.CC1T0dJb_1nkBT7.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In particular in science and open source software, we cannot be bothered to maintain the stuff we left behind (at least, not on the boss’s time). It’s a never-ending quest towards novelty. People just tend to be more forthcoming in the wallet area when fancy new features or knowledge are promised.&lt;/p&gt;
&lt;p&gt;This is why it is vital that we automate the crap out of everything we humanly can, especially if what we built is some kind of service.&lt;/p&gt;
&lt;p&gt;A few months ago, I launched a small web-app called &lt;a href=&quot;http://coalitiewijzer.herokuapp.com/&quot;&gt;Coalitiewijzer&lt;/a&gt;. It uses data from &lt;a href=&quot;https://peilingwijzer.tomlouwerse.nl/&quot;&gt;Peilingwijzer&lt;/a&gt; (which combines major political polls into one) that is updated in irregular intervals. So you guessed it: we’re going to automate the ingestion of that data into the Coalitiewijzer.&lt;/p&gt;
&lt;p&gt;In this short post, I’ll show you how I did this using GitHub Actions. GitHub Actions is a Continuous Integration (CI) provider that (obviously) integrates well with GitHub. If you want to know more about CI in general, I recommend checking out our &lt;a href=&quot;https://guide.esciencecenter.nl/#/best_practices/testing&quot;&gt;Guide&lt;/a&gt;. I’ll assume some working knowledge on this and also on Git, GitHub and GitHub Actions themselves. &lt;a href=&quot;https://blog.esciencecenter.nl/coalition-polls-for-the-people-with-coalitiewijzer-68bca83b95e7&quot;&gt;For more background info about the app itself, check out my other blog post&lt;/a&gt;. This article is basically an add-on to that one. To sum up this article, we’ll look at four steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up a basic GitHub Actions &lt;strong&gt;workflow that runs daily&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Update the data and commit to your Git repo&lt;/li&gt;
&lt;li&gt;Push this from a GitHub Actions runner back to the GitHub repo&lt;/li&gt;
&lt;li&gt;Deploy your app from GitHub Actions to Heroku&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you just want to take a shortcut straight to the code: &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/f9c2712/.github/workflows/update.yml&quot;&gt;here is the current GitHub Actions workflow file I wrote&lt;/a&gt;. For those who like to read poor prose instead: read on!&lt;/p&gt;
&lt;h2 id=&quot;daily-running-workflow&quot;&gt;Daily running workflow&lt;/h2&gt;
&lt;p&gt;To start a new GitHub Actions workflow file, GitHub offers a convenient “New workflow” button under the Actions tab in your repo. You can also copy-paste the basic example in the &lt;a href=&quot;https://docs.github.com/en/actions/quickstart&quot;&gt;Actions Quickstart guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These basic workflows typically only trigger on a push to your GitHub repo, as specified by the &lt;code&gt;on: push&lt;/code&gt; line. We’ll want to change that into something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  schedule:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; cron:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &apos;0 17 * * *&apos;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # 17:00 UTC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  workflow_dispatch:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The weird string between single quotes is &lt;a href=&quot;https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events&quot;&gt;cron syntax, which is explained in the docs&lt;/a&gt;. It allows you to specify at which times you want the workflow to run, in this case at 17:00. The timezone is UTC, keep that in mind.&lt;/p&gt;
&lt;p&gt;The last line is actually unrelated, but quite useful nonetheless. It allows you to manually start the workflow from the Actions page, which I found to be essential wihle testing my workflow.&lt;/p&gt;
&lt;h2 id=&quot;updating-the-data&quot;&gt;Updating the data&lt;/h2&gt;
&lt;p&gt;My app uses data from &lt;a href=&quot;https://peilingwijzer.tomlouwerse.nl/&quot;&gt;Peilingwijzer,&lt;/a&gt; which I preprocess for use in my app and then store in a pickle file. For details on this, see the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;update script on GitHub,&lt;/a&gt; or check out the &lt;a href=&quot;https://blog.esciencecenter.nl/coalition-polls-for-the-people-with-coalitiewijzer-68bca83b95e7&quot;&gt;blog post about the app&lt;/a&gt;. The pickle file has to be committed to the repo and then I can deploy to Heroku with the new data.&lt;/p&gt;
&lt;p&gt;This can all be done with a shell script that looks roughly like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;set &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;e                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# make the script end on errors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python update_numbers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;py&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # download new data and dump to files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git add [the updated files]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git commit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;updated data&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Python script does the actual data downloading and mangling and dumps the results into files that the web-app uses. These are then committed to the repo.&lt;/p&gt;
&lt;p&gt;To run this script (in particular the &lt;code&gt;git commit&lt;/code&gt;), you do need to configure the git client on the GitHub Actions runner. You can do this with a workflow step at any time before running the commit command. Add this to your workflow job in the yml file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; configure git user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  run:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local user.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${{ github.actor }}@users.noreply.github.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    git config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;local user.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${{ github.actor }}&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This commits under your own GitHub user name (or, in general, the username of the one that triggers the workflow to run), so it’ll identify the commits to be yours. It won’t do certification unless you also somehow configure that (perhaps using GitHub secrets, see the Heroku section below). You can fill in any name you want, though, so you could also put something like “Actions bot”.&lt;/p&gt;
&lt;h2 id=&quot;push-back-to-your-github-repo&quot;&gt;Push back to your GitHub repo&lt;/h2&gt;
&lt;p&gt;One of the beauties of GitHub Actions is the great availability of … well, Actions. These are pre-baked recipes for steps that you can very conveniently plug and play. To be precise, you can add such a step to your job, which is part of your Actions pipeline.&lt;/p&gt;
&lt;p&gt;For the next step, I needed to push the commit made above into the GitHub repo from within the GitHub (Actions) infrastructure itself. I was a bit anxious about whether I would find an Action which allowed me to do this. It feels like a potential security leak. Luckily, it turns out &lt;a href=&quot;https://github.com/marketplace/actions/github-push#example-workflow-file&quot;&gt;there is already an Action for this very task&lt;/a&gt;. Hurray! The &lt;a href=&quot;https://github.com/ad-m/github-push-action&quot;&gt;Action’s source&lt;/a&gt; can easily be checked if you’re worried about security.&lt;/p&gt;
&lt;p&gt;Just add the following step to your job after running the update script:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; name:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ad&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;github&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;action@v0.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    github_token:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{ secrets.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    branch:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{ github.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this to work, one more step is necessary. You also need to add two options to your checkout step (at least, this is what I figure from the &lt;a href=&quot;https://github.com/marketplace/actions/github-push#usage&quot;&gt;Action docs&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;checkout@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    persist&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;credentials:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    fetch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;depth:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
&lt;h2 id=&quot;deploying-to-heroku&quot;&gt;Deploying to Heroku&lt;/h2&gt;
&lt;p&gt;Finally, after the data has been updated in the Git repo, the Coalitiewijzer app can be deployed back onto Heroku (which runs &lt;a href=&quot;http://coalitiewijzer.herokuapp.com/&quot;&gt;the app, live here&lt;/a&gt;). Heroku deployment can be done by just pushing your repo directly to the Heroku servers. Really convenient!&lt;/p&gt;
&lt;p&gt;So, since this is again just a git push, albeit to a different repo, this should not be a problem. And, indeed, a &lt;a href=&quot;https://github.com/marketplace/actions/deploy-to-heroku&quot;&gt;Deploy to Heroku Action already exists&lt;/a&gt; for this very purpose!&lt;/p&gt;
&lt;p&gt;To make this work, you need to add your Heroku API key &lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository&quot;&gt;to your GitHub repo’s secrets (instructions here)&lt;/a&gt;. You can find the Heroku API key in your &lt;a href=&quot;https://dashboard.heroku.com/account&quot;&gt;Heroku account&lt;/a&gt;. Call it &lt;code&gt;HEROKU_API_KEY&lt;/code&gt; if you want the snippet below to work.&lt;/p&gt;
&lt;p&gt;After that, you just add the action to your workflow job, like described in the action’s documentation (replace the boldfaced parts):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rb&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; uses:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; akhileshns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;heroku&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deploy@v3.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10.9&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; # This is the action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  with:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_api_key:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ${{secrets.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;HEROKU_API_KEY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_app_name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; your_app_name_on_heroku&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      heroku_email:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; your@email.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be careful with this key, because it gives access to your full Heroku account.&lt;/p&gt;
&lt;p&gt;And that’s it! From now on, your updates will be pushed back to the GitHub repo and deployed on Heroku.&lt;/p&gt;
&lt;p&gt;Of course, this is just one of many things you could automate using GitHub Actions. The combination with running actual servers on Heroku for free is icing on the cake. Of course, if you want more performance, more MBs, more connections, etcetera, you can pay them for that. But for low profile web-apps, the free package is really a great deal.&lt;/p&gt;
&lt;p&gt;Let me know if you have any comments or questions. I’m happy to help!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_JECSe723rgCyyHyK-48ff0ae8.CC1T0dJb.jpg" medium="image"/><author>Patrick Bos</author></item><item><title>A Quick and Dirty Pytest Cookbook</title><link>https://blog.esciencecenter.nl/posts/2021-02-22---a-quick-and-dirty-pytest-cookbook</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-02-22---a-quick-and-dirty-pytest-cookbook</guid><description>&lt;p&gt;As an alternative to the above snippet, you can install and run the &lt;a href=&quot;https://pypi.org/project/pytest-mypy-plugins/&quot;&gt;pytest-mypy-plugins&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;testing-the-documentation&quot;&gt;Testing the documentation&lt;/h2&gt;
&lt;p&gt;Testing the documentation is a must have. The following snippet shows how you can do so:&lt;/p&gt;
&lt;h2 id=&quot;testing-async-code&quot;&gt;Testing async code&lt;/h2&gt;
&lt;p&gt;If you do web applications or something similar you probably have run into Python &lt;a href=&quot;https://docs.python.org/3/library/asyncio.html&quot;&gt;asyncio&lt;/a&gt;. If you try to run async code using normal pytest code, chances are that you wouldn’t notice that there are no tests running at all. Async code is lazy and requires that you run it inside an async block*, otherwise nothing interesting happens. The following snippet shows how to invoke async code in Pytest:&lt;/p&gt;
&lt;p&gt;For more details about testing asynchronous code in python check &lt;a href=&quot;https://github.com/pytest-dev/pytest-asyncio&quot;&gt;pytest-asyncio&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;running-tests-in-parallel&quot;&gt;Running tests in parallel&lt;/h2&gt;
&lt;p&gt;If you, like me, have the tendency to procrastinate while waiting for the test suite to finish executing, then a good way to reduce the procrastination time is to run the tests in parallel.&lt;/p&gt;
&lt;p&gt;For running your tests in parallel, you just need to install the &lt;a href=&quot;https://github.com/browsertron/pytest-parallel&quot;&gt;pytest-parallel&lt;/a&gt; library that not only allows you to run your tests in parallel but also in a thread-safe manner, using commands as simple as:&lt;/p&gt;
&lt;p&gt;pytest —workers 2&lt;/p&gt;
&lt;h2 id=&quot;running-a-test-with-multiple-parameters&quot;&gt;Running a test with multiple parameters&lt;/h2&gt;
&lt;p&gt;Imaging that you have a simulation that receives some parameters as input and gives you back some numerical output. You can use &lt;a href=&quot;https://docs.pytest.org/en/stable/parametrize.html&quot;&gt;pytest’s parametrize extension&lt;/a&gt; to feed one parameter at a time to the simulation and check that each one of them returns the expected output. The following snippet shows how to accomplish that:&lt;/p&gt;
&lt;p&gt;If you run the previous snippet, you should see something like:&lt;/p&gt;
&lt;p&gt;pytest -v test_parameters.py
test_parameters.py::test_simulation[pi-3.141592653589793] PASSED&lt;br&gt;
test_parameters.py::test_simulation[exp-2.718281828459045] FAILEDparameter = ‘exp’, expected = 2.718281828459045&lt;a href=&quot;http://twitter.com/pytest&quot;&gt;@pytest&lt;/a&gt;.mark.parametrize(“parameter, expected”,
[(“pi”, np.pi), (“exp”, np.exp(1))])
def test_simulation(parameter: str, expected: float) -&gt; None:
&quot;&quot;&quot;Check the simulation.&quot;&quot;&quot;
result = run_simulation(parameter)
&gt;       assert abs(result - expected) &amp;#x3C; 1e-8
E       assert 39.28171817154095 &amp;#x3C; 1e-08
E        +  where 39.28171817154095 = abs((42 - 2.718281828459045))test_parameter.py:16: AssertionError&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Pytest is a flexible tool with a great number of useful extensions. With Pytest, there is always a way to check your code functionality, even those annoying corner cases.&lt;/p&gt;
&lt;p&gt;Please comment if you find these tricks useful or if you find another nice trick that you want to share.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;My special gratitude to Bas van Beek to share with me some of his useful recipes. I would like also to thank [Florian Huber] and Stefan Verhoeven for their feedback.&lt;/p&gt;
&lt;p&gt;Thanks to [Pablo Rodríguez-Sánchez] and Steven Roldan for their help editing the text.&lt;/p&gt;</description><pubDate>Mon, 22 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As an alternative to the above snippet, you can install and run the &lt;a href=&quot;https://pypi.org/project/pytest-mypy-plugins/&quot;&gt;pytest-mypy-plugins&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;testing-the-documentation&quot;&gt;Testing the documentation&lt;/h2&gt;
&lt;p&gt;Testing the documentation is a must have. The following snippet shows how you can do so:&lt;/p&gt;
&lt;h2 id=&quot;testing-async-code&quot;&gt;Testing async code&lt;/h2&gt;
&lt;p&gt;If you do web applications or something similar you probably have run into Python &lt;a href=&quot;https://docs.python.org/3/library/asyncio.html&quot;&gt;asyncio&lt;/a&gt;. If you try to run async code using normal pytest code, chances are that you wouldn’t notice that there are no tests running at all. Async code is lazy and requires that you run it inside an async block*, otherwise nothing interesting happens. The following snippet shows how to invoke async code in Pytest:&lt;/p&gt;
&lt;p&gt;For more details about testing asynchronous code in python check &lt;a href=&quot;https://github.com/pytest-dev/pytest-asyncio&quot;&gt;pytest-asyncio&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;running-tests-in-parallel&quot;&gt;Running tests in parallel&lt;/h2&gt;
&lt;p&gt;If you, like me, have the tendency to procrastinate while waiting for the test suite to finish executing, then a good way to reduce the procrastination time is to run the tests in parallel.&lt;/p&gt;
&lt;p&gt;For running your tests in parallel, you just need to install the &lt;a href=&quot;https://github.com/browsertron/pytest-parallel&quot;&gt;pytest-parallel&lt;/a&gt; library that not only allows you to run your tests in parallel but also in a thread-safe manner, using commands as simple as:&lt;/p&gt;
&lt;p&gt;pytest —workers 2&lt;/p&gt;
&lt;h2 id=&quot;running-a-test-with-multiple-parameters&quot;&gt;Running a test with multiple parameters&lt;/h2&gt;
&lt;p&gt;Imaging that you have a simulation that receives some parameters as input and gives you back some numerical output. You can use &lt;a href=&quot;https://docs.pytest.org/en/stable/parametrize.html&quot;&gt;pytest’s parametrize extension&lt;/a&gt; to feed one parameter at a time to the simulation and check that each one of them returns the expected output. The following snippet shows how to accomplish that:&lt;/p&gt;
&lt;p&gt;If you run the previous snippet, you should see something like:&lt;/p&gt;
&lt;p&gt;pytest -v test_parameters.py
test_parameters.py::test_simulation[pi-3.141592653589793] PASSED&lt;br&gt;
test_parameters.py::test_simulation[exp-2.718281828459045] FAILEDparameter = ‘exp’, expected = 2.718281828459045&lt;a href=&quot;http://twitter.com/pytest&quot;&gt;@pytest&lt;/a&gt;.mark.parametrize(“parameter, expected”,
[(“pi”, np.pi), (“exp”, np.exp(1))])
def test_simulation(parameter: str, expected: float) -&gt; None:
&quot;&quot;&quot;Check the simulation.&quot;&quot;&quot;
result = run_simulation(parameter)
&gt;       assert abs(result - expected) &amp;#x3C; 1e-8
E       assert 39.28171817154095 &amp;#x3C; 1e-08
E        +  where 39.28171817154095 = abs((42 - 2.718281828459045))test_parameter.py:16: AssertionError&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Pytest is a flexible tool with a great number of useful extensions. With Pytest, there is always a way to check your code functionality, even those annoying corner cases.&lt;/p&gt;
&lt;p&gt;Please comment if you find these tricks useful or if you find another nice trick that you want to share.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;My special gratitude to Bas van Beek to share with me some of his useful recipes. I would like also to thank [Florian Huber] and Stefan Verhoeven for their feedback.&lt;/p&gt;
&lt;p&gt;Thanks to [Pablo Rodríguez-Sánchez] and Steven Roldan for their help editing the text.&lt;/p&gt;</content:encoded><author>Felipe</author></item><item><title>Twitter Bots, for Science!</title><link>https://blog.esciencecenter.nl/posts/2021-02-19---twitter-bots-for-science</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-02-19---twitter-bots-for-science</guid><description>&lt;h2 id=&quot;how-to-build-a-bot-to-show-covid-19-vaccination-progress&quot;&gt;How to build a bot to show Covid-19 vaccination progress&lt;/h2&gt;
&lt;p&gt;Twitter bots have a really bad rep. Troll armies, spam, fake news… You name it, a bot’s done it.&lt;/p&gt;
&lt;p&gt;But what if we could harness their powers for good? Use bots to inform people in a fun way? That would be &lt;strong&gt;science outreach&lt;/strong&gt;! It’s all in a name.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2053&quot; height=&quot;1095&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YL2rNx2g8oxkMG149unWgQ-2fde1464.1WN8Ucbt_17M1Gc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The knights who say “SCI!” ( Python et al., 1975 ). Photo: CC BY 2.0, Brickset&lt;/p&gt;
&lt;p&gt;Of course, Covid-19 is on everybody’s mind, but the tide of horribility (it’s a word) is slowly turning into one of hope and recovery. We’re not out of the woods yet, but we are jabbing our way out, one vaccine at a time.&lt;/p&gt;
&lt;p&gt;To spread a bit of this hope (and have some fun), I created a &lt;a href=&quot;https://twitter.com/CoVacProgress&quot;&gt;&lt;strong&gt;progress bar&lt;/strong&gt; (who doesn’t love progress bars?!) on Twitter&lt;/a&gt; that shows &lt;strong&gt;how many people have been vaccinated&lt;/strong&gt; worldwide and per continent. The bars are updated daily.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;304&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zMpiXECwyVswfe-fU4EWcg-78e58517.DcKfMD6c_Z2efLgs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot&quot;&gt;code is open source&lt;/a&gt; and the open data comes from &lt;a href=&quot;https://ourworldindata.org/covid-vaccinations&quot;&gt;Our World in Data&lt;/a&gt;. If you feel inspired by this little project to share some of &lt;strong&gt;your&lt;/strong&gt; scientific data, feel free to build on it! I had my first version up in about an hour: it’s really surprisingly easy, so &lt;em&gt;&lt;strong&gt;don’t let technical barriers hold you back from communicating cool science results automatically&lt;/strong&gt;&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;The requirements for reading this howto are a working knowledge of Python, Pandas, Git, GitHub and Twitter and a high tolerance for painfully horrible jokes. For the working knowledge part: check out our &lt;a href=&quot;https://guide.esciencecenter.nl/#/&quot;&gt;Guide&lt;/a&gt;. For the jokes, well… maybe reading this article will actually build up your tolerance.&lt;/p&gt;
&lt;p&gt;I’ll cover the five steps I took to build this bot:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a “bot account” on Twitter&lt;/li&gt;
&lt;li&gt;Get and mangle the data from Our World in Data with the Python Pandas package&lt;/li&gt;
&lt;li&gt;Use tqdm to make progress bars suitable for Twitter&lt;/li&gt;
&lt;li&gt;Send tweets using the Python Tweepy package&lt;/li&gt;
&lt;li&gt;Automate this using GitHub Actions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;create-a-bot-account&quot;&gt;Create a “bot” account&lt;/h2&gt;
&lt;p&gt;The first thing you need is a developer account on Twitter. This allows you to get key strings which you can use later on to log in and do stuff on Twitter from a Python script.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://realpython.com/twitter-bot-python-tweepy/#creating-twitter-api-authentication-credentials&quot;&gt;This post&lt;/a&gt; (among many others) clearly explains the steps you need to take for this.&lt;/p&gt;
&lt;p&gt;It is possible to use your personal account for your bot (and for activating the developer account on), but for this project I decided to create a separate account. You’ll need a unique email address to do so, but you can use the same telephone number as your existing account for confirmation. A separate account allows for easy &lt;strong&gt;testing&lt;/strong&gt; of your bot before you start promoting it widely. Just delete the test tweets when everything is done.&lt;/p&gt;
&lt;p&gt;So, with your bot account ready, jot down the keys somewhere — but &lt;strong&gt;don’t put them in your git repo&lt;/strong&gt; (&lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/dfbd3101aa192be8fd6448aa051b0ae14cc1520a/test_tweepy.py#L10&quot;&gt;like I obviously did 😁&lt;/a&gt;) — so we can use them in Tweepy later on.&lt;/p&gt;
&lt;h2 id=&quot;get-the-data-with-pandas&quot;&gt;Get the data with Pandas&lt;/h2&gt;
&lt;p&gt;One of &lt;strong&gt;the&lt;/strong&gt; authoritative sources on Covid-19 data is &lt;a href=&quot;https://ourworldindata.org/&quot;&gt;Our World in Data&lt;/a&gt;. You can find their graphs all over the place. The data they gather is conveniently open (under a Creative Commons license) and &lt;a href=&quot;https://github.com/owid/covid-19-data/tree/master/public/data/vaccinations&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;652&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_dThJeI5ENXybCcen6GsAow-34e7bbdf.CK0okt-i_Z1dnOht.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Grizzlies would be a better name… Image: CC BY-NC-ND 2.0 iregretjumping.&lt;/p&gt;
&lt;p&gt;Pandas, the &lt;em&gt;ironically named omnivore of data science&lt;/em&gt;, can chew this right up, straight from the raw URL. This saves you the step of manually downloading. Convenient! Look for the little “raw” button when viewing a file on GitHub and give that URL to your favorite ursid:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pand&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;df &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pd&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;read_csv(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, parse_dates&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives us a nice dataframe containing which countries had what number of people vaccinated at which dates. They even keep track of whether people had only one or two (where applicable) shots. Not every country has good data, so Our World in Data only includes those numbers which pass their quality checks.&lt;/p&gt;
&lt;p&gt;For the time being, I’m using the column &lt;code&gt;people_vaccinated_per_hundred&lt;/code&gt; for the bot, because those numbers are a bit less depressing at the moment, but may switch to &lt;code&gt;people_fully_vaccinated_per_hundred&lt;/code&gt; later on. Since not all countries have data in these columns, this leaves us with a little over 50 countries &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/e9d4eced48f315567c224f19068ab6bd8206020c/run.py#L55&quot;&gt;after filtering&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;calculate-continent-totals-with-pycountry_convert&quot;&gt;Calculate continent totals with pycountry_convert&lt;/h3&gt;
&lt;p&gt;Now, the table has numbers for the whole world pre-calculated, so I grabbed those for my first tests. But I thought it would be fun to also add some more detailed data.&lt;/p&gt;
&lt;p&gt;Twitter’s character limit prevents me from posting bars for all 56 countries, but we can certainly do continents. I think that’s still interesting, as well as poignant given the inequality in the world it so very clearly highlights. If the stark contrast makes policy makers think about fairer distribution for a second, that would be a huge win.&lt;/p&gt;
&lt;p&gt;Of course, finding the continents for 56 countries &lt;strong&gt;by hand&lt;/strong&gt; goes against everything I stand for as a lazy programmer. Obviously, I went about spending way more time on finding and figuring out a nice library that can do this work for me automatically. And, lo and behold, it exists, is called &lt;a href=&quot;https://pypi.org/project/pycountry-convert/&quot;&gt;pycountry_convert&lt;/a&gt; and &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/e9d4eced48f315567c224f19068ab6bd8206020c/run.py#L49&quot;&gt;works like a charm&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Combine it with the &lt;a href=&quot;https://raw.githubusercontent.com/owid/covid-19-data/master/scripts/input/un/population_2020.csv&quot;&gt;total population table that Our World in Data also maintains&lt;/a&gt; and you’ve got all the ingredients you need to compute percentages per continent.&lt;/p&gt;
&lt;p&gt;Note that the continent numbers are not completely correct like this. Some countries span multiple continents (notably Russia). I treat such countries to just be part of one continent (so Russia is part of Europe, because pycountry_convert tells me it is).&lt;/p&gt;
&lt;h2 id=&quot;make-tweetable-progress-bars-with-tqdm&quot;&gt;Make Tweetable progress bars with tqdm&lt;/h2&gt;
&lt;p&gt;Now that we have percentages, we can convert them to progress bars.&lt;/p&gt;
&lt;p&gt;My go-to package for progress bars is &lt;code&gt;tqdm&lt;/code&gt;. It is especially good in interactive environments. There’s nothing like a progress bar to spice up a slow &lt;code&gt;for&lt;/code&gt; -loop. What’s more, &lt;code&gt;tqdm&lt;/code&gt; ’s bars look really good both in Jupyter notebooks and on the command line due to &lt;em&gt;using fancy unicode characters&lt;/em&gt;. The latter is exactly what I want to use here as well: Twitter is primarily a textual medium, and although I could just post images of progress bars (wait… why didn’t I? d’oh!), posting text-based bars should be an easy first option.&lt;/p&gt;
&lt;p&gt;Also, &lt;a href=&quot;https://twitter.com/year_progress&quot;&gt;year_progress&lt;/a&gt; does text-bars as well and that bot inspired this one, so there you go.&lt;/p&gt;
&lt;p&gt;Given some &lt;code&gt;percentage&lt;/code&gt; from the dataset, we can make a bar-string for posting to Twitter with something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bar &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tqdm(initial&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;percentage, total&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bar_format&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{bar&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {percentage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;1f}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;, ascii&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bar_string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; str(bar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tweet_string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bar_string[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;replace(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u3000&apos;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bar_string[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few tricks beyond the &lt;code&gt;tqdm&lt;/code&gt; basics to highlight are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I used a custom format string to remove some superfluous stuff. We need to use as little characters as possible, but, also, it is important to not make the string too wide, otherwise it doesn’t display nicely on all devices (read: phones).&lt;/li&gt;
&lt;li&gt;Usually, &lt;code&gt;tqdm&lt;/code&gt; is used to display an “animated” progress bar. To emulate animation on the command line, it does all sorts of magic with carriage return (&lt;code&gt;\r&lt;/code&gt;) and new line (&lt;code&gt;\n&lt;/code&gt;) characters. I first tried using the &lt;code&gt;tqdm&lt;/code&gt; option of specifying an output stream using an &lt;code&gt;io.StringIO&lt;/code&gt; stream object, to act as a virtual terminal so to speak. I then tried to extract the bar string from that. This turned out to be quite a nightmarish experience (may have had to do with it getting quite late). Probably, &lt;code&gt;tqdm&lt;/code&gt; tries to do very smart things when outputting to this stream, and clearly I wasn’t smart enough to undo those smart things. Luckily, after a good night’s rest, I found that directly extracting the bar string from &lt;code&gt;bar.__str__()&lt;/code&gt; does not do weird animation stuff and just gives a neat, clean progress bar. Phew.&lt;/li&gt;
&lt;li&gt;Twitter is not a terminal. The relevance of this obvious statement is that Twitter does not use a fixed width font. Madness, I know. But luckily, the unicode committee (I’m sure there is one, perhaps several, in fact) blessed us with more kinds of space characters than we could ever have hoped for. &lt;code&gt;\u3000&lt;/code&gt;, the “ideographic space”, is the one that turns out to have the same width on Twitter as (most) unicode characters used for the bar itself. So I replace spaces in the bar (barring (heehee) those around the bar) with this ideographic one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tweet-with-tweepy&quot;&gt;Tweet with Tweepy&lt;/h2&gt;
&lt;p&gt;The actual tweeting is the easiest part in all this. The &lt;a href=&quot;https://realpython.com/twitter-bot-python-tweepy/#creating-twitter-api-authentication-credentials&quot;&gt;above mentioned article&lt;/a&gt; explains most of it using the &lt;a href=&quot;https://www.tweepy.org/&quot;&gt;Tweepy&lt;/a&gt; package. You need the keys you obtained earlier to authenticate and create an &lt;code&gt;api&lt;/code&gt; object (see the snippet in the article).&lt;/p&gt;
&lt;p&gt;Then, tweeting is as simple as:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;update_status(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ceci n&apos;est pas une tweet&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;810&quot; height=&quot;475&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_ZdxO48qSyJmHrXsL-1f57d952.Gm0PiurH_Z1X5XYc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simple. J’approuve.&lt;/p&gt;
&lt;p&gt;If all goes well, this command will return a giant blob of JSON, wrapped in some Tweepy class. Not to worry, do not disturb it, it means you no harm. If for some reason the Tweepy call failed, you’ll get an error message, so you’ll know when you actually have to start paying attention.&lt;/p&gt;
&lt;h2 id=&quot;automate-on-github-actions&quot;&gt;Automate on GitHub Actions&lt;/h2&gt;
&lt;p&gt;Obviously, the last part of the show is about getting rid of any future manual action and getting back to watching YouTube. We are programmers, after all. Moreover, we are scientists and we don’t have time for manual labor. That is what PhD stu…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[anxious whispering]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[angry, impatient whispering]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not supposed to…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[university PR department whispers]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, but…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[whispered definitive executive order]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Automation, then!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[financial whispers]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For free! Yes, we can, with GitHub Actions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[mumbled approval]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After putting all my code in a git repository (on GitHub), I created a workflow file &lt;code&gt;.github/workflows/tweet_progress.yml&lt;/code&gt;. The file looks something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Tweet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; latest progresson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  schedule&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cron&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &apos;0 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;  &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;00&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; UTC&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, see https&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;://&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;crontab&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;guru&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  #&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; allows you to run this workflow manually from the &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Actions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tab&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  tweet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    runs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ubuntu&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;setup&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pip install &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;r requirements&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; run script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_API&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_API }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_API_SECRET&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_API_SECRET }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_ACCESS&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_ACCESS }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_ACCESS_SECRET&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_ACCESS_SECRET }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the &lt;code&gt;on&lt;/code&gt; section, we make our Tweepy script run on a regular &lt;code&gt;schedule&lt;/code&gt;: every day at 10 a.m., UTC (check out &lt;a href=&quot;https://crontab.guru/&quot;&gt;https://crontab.guru/&lt;/a&gt; if you don’t want to bother remembering the arcane cron syntax, thanks to&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/fca35bfb3190?source=post_page---user_mention--1cf3f19dcda8---------------------------------------&quot;&gt;Stefan Verhoeven&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;for the tip). The data is updated daily in the morning, so this should use the freshest data most days. We can also trigger the job manually by adding &lt;code&gt;workflow_dispatch&lt;/code&gt;. The part below &lt;code&gt;jobs&lt;/code&gt; is what will actually run on a GitHub machine and should be mostly self-explanatory. This will also be different for your specific application (unless you copy mine). The important thing to notice, though, is the bold part where I pass in all the keys.&lt;/p&gt;
&lt;p&gt;Two things to make this possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The awesome &lt;a href=&quot;https://pypi.org/project/ConfigArgParse/&quot;&gt;ConfigArgParse&lt;/a&gt; module allows for specifying program parameters in three ways: via command line arguments (like the Python standard library &lt;code&gt;argparse&lt;/code&gt;), via a config file or via environment variables, all through one convenient, almost-drop-in-replacement-of- &lt;code&gt;argparse&lt;/code&gt; call. On my laptop (for testing and such) I added a config file with the keys in it (and put the name of that file in &lt;code&gt;.gitignore&lt;/code&gt;, after my earlier key committing booboo), but on GitHub Actions I can now pass them in through environment variables via the &lt;code&gt;env&lt;/code&gt; section.&lt;/li&gt;
&lt;li&gt;The second part is those &lt;code&gt;${{ secrets.THING }}&lt;/code&gt; things. You have to &lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository&quot;&gt;store the Twitter keys in GitHub secrets (instructions here)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commit the yml file, push it to GitHub, and just like that you’ve got yourself an automatically updating Twitter bot!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;605&quot; height=&quot;568&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_l1__Q8DxN_LnAe_VU4L3CQ-2dc29b71.Dgpci5tY_2rTIFX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The top two tweets were automatically produced. It’s alive! ALIVE!!!&lt;/p&gt;
&lt;p&gt;I hope I convinced you that if you have a cool idea for a bot and know of a data source, you should immediately go for it! Just &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/&quot;&gt;fork my repo&lt;/a&gt; if you want to get a quick start, modify it to your liking and put it out there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations&lt;/strong&gt;, you just made the world a better, more well-informed place!&lt;/p&gt;
&lt;p&gt;I’d love to hear what you think, let me know in the comments. Also, if you want some help setting up your bot, don’t hesitate to ask.&lt;/p&gt;</description><pubDate>Fri, 19 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-to-build-a-bot-to-show-covid-19-vaccination-progress&quot;&gt;How to build a bot to show Covid-19 vaccination progress&lt;/h2&gt;
&lt;p&gt;Twitter bots have a really bad rep. Troll armies, spam, fake news… You name it, a bot’s done it.&lt;/p&gt;
&lt;p&gt;But what if we could harness their powers for good? Use bots to inform people in a fun way? That would be &lt;strong&gt;science outreach&lt;/strong&gt;! It’s all in a name.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2053&quot; height=&quot;1095&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_YL2rNx2g8oxkMG149unWgQ-2fde1464.1WN8Ucbt_17M1Gc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The knights who say “SCI!” ( Python et al., 1975 ). Photo: CC BY 2.0, Brickset&lt;/p&gt;
&lt;p&gt;Of course, Covid-19 is on everybody’s mind, but the tide of horribility (it’s a word) is slowly turning into one of hope and recovery. We’re not out of the woods yet, but we are jabbing our way out, one vaccine at a time.&lt;/p&gt;
&lt;p&gt;To spread a bit of this hope (and have some fun), I created a &lt;a href=&quot;https://twitter.com/CoVacProgress&quot;&gt;&lt;strong&gt;progress bar&lt;/strong&gt; (who doesn’t love progress bars?!) on Twitter&lt;/a&gt; that shows &lt;strong&gt;how many people have been vaccinated&lt;/strong&gt; worldwide and per continent. The bars are updated daily.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;600&quot; height=&quot;304&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_zMpiXECwyVswfe-fU4EWcg-78e58517.DcKfMD6c_Z2efLgs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot&quot;&gt;code is open source&lt;/a&gt; and the open data comes from &lt;a href=&quot;https://ourworldindata.org/covid-vaccinations&quot;&gt;Our World in Data&lt;/a&gt;. If you feel inspired by this little project to share some of &lt;strong&gt;your&lt;/strong&gt; scientific data, feel free to build on it! I had my first version up in about an hour: it’s really surprisingly easy, so &lt;em&gt;&lt;strong&gt;don’t let technical barriers hold you back from communicating cool science results automatically&lt;/strong&gt;&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;The requirements for reading this howto are a working knowledge of Python, Pandas, Git, GitHub and Twitter and a high tolerance for painfully horrible jokes. For the working knowledge part: check out our &lt;a href=&quot;https://guide.esciencecenter.nl/#/&quot;&gt;Guide&lt;/a&gt;. For the jokes, well… maybe reading this article will actually build up your tolerance.&lt;/p&gt;
&lt;p&gt;I’ll cover the five steps I took to build this bot:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a “bot account” on Twitter&lt;/li&gt;
&lt;li&gt;Get and mangle the data from Our World in Data with the Python Pandas package&lt;/li&gt;
&lt;li&gt;Use tqdm to make progress bars suitable for Twitter&lt;/li&gt;
&lt;li&gt;Send tweets using the Python Tweepy package&lt;/li&gt;
&lt;li&gt;Automate this using GitHub Actions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;create-a-bot-account&quot;&gt;Create a “bot” account&lt;/h2&gt;
&lt;p&gt;The first thing you need is a developer account on Twitter. This allows you to get key strings which you can use later on to log in and do stuff on Twitter from a Python script.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://realpython.com/twitter-bot-python-tweepy/#creating-twitter-api-authentication-credentials&quot;&gt;This post&lt;/a&gt; (among many others) clearly explains the steps you need to take for this.&lt;/p&gt;
&lt;p&gt;It is possible to use your personal account for your bot (and for activating the developer account on), but for this project I decided to create a separate account. You’ll need a unique email address to do so, but you can use the same telephone number as your existing account for confirmation. A separate account allows for easy &lt;strong&gt;testing&lt;/strong&gt; of your bot before you start promoting it widely. Just delete the test tweets when everything is done.&lt;/p&gt;
&lt;p&gt;So, with your bot account ready, jot down the keys somewhere — but &lt;strong&gt;don’t put them in your git repo&lt;/strong&gt; (&lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/dfbd3101aa192be8fd6448aa051b0ae14cc1520a/test_tweepy.py#L10&quot;&gt;like I obviously did 😁&lt;/a&gt;) — so we can use them in Tweepy later on.&lt;/p&gt;
&lt;h2 id=&quot;get-the-data-with-pandas&quot;&gt;Get the data with Pandas&lt;/h2&gt;
&lt;p&gt;One of &lt;strong&gt;the&lt;/strong&gt; authoritative sources on Covid-19 data is &lt;a href=&quot;https://ourworldindata.org/&quot;&gt;Our World in Data&lt;/a&gt;. You can find their graphs all over the place. The data they gather is conveniently open (under a Creative Commons license) and &lt;a href=&quot;https://github.com/owid/covid-19-data/tree/master/public/data/vaccinations&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;652&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_dThJeI5ENXybCcen6GsAow-34e7bbdf.CK0okt-i_Z1dnOht.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Grizzlies would be a better name… Image: CC BY-NC-ND 2.0 iregretjumping.&lt;/p&gt;
&lt;p&gt;Pandas, the &lt;em&gt;ironically named omnivore of data science&lt;/em&gt;, can chew this right up, straight from the raw URL. This saves you the step of manually downloading. Convenient! Look for the little “raw” button when viewing a file on GitHub and give that URL to your favorite ursid:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pand&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;df &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pd&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;read_csv(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, parse_dates&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives us a nice dataframe containing which countries had what number of people vaccinated at which dates. They even keep track of whether people had only one or two (where applicable) shots. Not every country has good data, so Our World in Data only includes those numbers which pass their quality checks.&lt;/p&gt;
&lt;p&gt;For the time being, I’m using the column &lt;code&gt;people_vaccinated_per_hundred&lt;/code&gt; for the bot, because those numbers are a bit less depressing at the moment, but may switch to &lt;code&gt;people_fully_vaccinated_per_hundred&lt;/code&gt; later on. Since not all countries have data in these columns, this leaves us with a little over 50 countries &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/e9d4eced48f315567c224f19068ab6bd8206020c/run.py#L55&quot;&gt;after filtering&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;calculate-continent-totals-with-pycountry_convert&quot;&gt;Calculate continent totals with pycountry_convert&lt;/h3&gt;
&lt;p&gt;Now, the table has numbers for the whole world pre-calculated, so I grabbed those for my first tests. But I thought it would be fun to also add some more detailed data.&lt;/p&gt;
&lt;p&gt;Twitter’s character limit prevents me from posting bars for all 56 countries, but we can certainly do continents. I think that’s still interesting, as well as poignant given the inequality in the world it so very clearly highlights. If the stark contrast makes policy makers think about fairer distribution for a second, that would be a huge win.&lt;/p&gt;
&lt;p&gt;Of course, finding the continents for 56 countries &lt;strong&gt;by hand&lt;/strong&gt; goes against everything I stand for as a lazy programmer. Obviously, I went about spending way more time on finding and figuring out a nice library that can do this work for me automatically. And, lo and behold, it exists, is called &lt;a href=&quot;https://pypi.org/project/pycountry-convert/&quot;&gt;pycountry_convert&lt;/a&gt; and &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/blob/e9d4eced48f315567c224f19068ab6bd8206020c/run.py#L49&quot;&gt;works like a charm&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Combine it with the &lt;a href=&quot;https://raw.githubusercontent.com/owid/covid-19-data/master/scripts/input/un/population_2020.csv&quot;&gt;total population table that Our World in Data also maintains&lt;/a&gt; and you’ve got all the ingredients you need to compute percentages per continent.&lt;/p&gt;
&lt;p&gt;Note that the continent numbers are not completely correct like this. Some countries span multiple continents (notably Russia). I treat such countries to just be part of one continent (so Russia is part of Europe, because pycountry_convert tells me it is).&lt;/p&gt;
&lt;h2 id=&quot;make-tweetable-progress-bars-with-tqdm&quot;&gt;Make Tweetable progress bars with tqdm&lt;/h2&gt;
&lt;p&gt;Now that we have percentages, we can convert them to progress bars.&lt;/p&gt;
&lt;p&gt;My go-to package for progress bars is &lt;code&gt;tqdm&lt;/code&gt;. It is especially good in interactive environments. There’s nothing like a progress bar to spice up a slow &lt;code&gt;for&lt;/code&gt; -loop. What’s more, &lt;code&gt;tqdm&lt;/code&gt; ’s bars look really good both in Jupyter notebooks and on the command line due to &lt;em&gt;using fancy unicode characters&lt;/em&gt;. The latter is exactly what I want to use here as well: Twitter is primarily a textual medium, and although I could just post images of progress bars (wait… why didn’t I? d’oh!), posting text-based bars should be an easy first option.&lt;/p&gt;
&lt;p&gt;Also, &lt;a href=&quot;https://twitter.com/year_progress&quot;&gt;year_progress&lt;/a&gt; does text-bars as well and that bot inspired this one, so there you go.&lt;/p&gt;
&lt;p&gt;Given some &lt;code&gt;percentage&lt;/code&gt; from the dataset, we can make a bar-string for posting to Twitter with something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bar &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tqdm(initial&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;percentage, total&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bar_format&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{bar&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {percentage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;1f}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;, ascii&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bar_string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; str(bar)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tweet_string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bar_string[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;replace(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;u3000&apos;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bar_string[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few tricks beyond the &lt;code&gt;tqdm&lt;/code&gt; basics to highlight are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I used a custom format string to remove some superfluous stuff. We need to use as little characters as possible, but, also, it is important to not make the string too wide, otherwise it doesn’t display nicely on all devices (read: phones).&lt;/li&gt;
&lt;li&gt;Usually, &lt;code&gt;tqdm&lt;/code&gt; is used to display an “animated” progress bar. To emulate animation on the command line, it does all sorts of magic with carriage return (&lt;code&gt;\r&lt;/code&gt;) and new line (&lt;code&gt;\n&lt;/code&gt;) characters. I first tried using the &lt;code&gt;tqdm&lt;/code&gt; option of specifying an output stream using an &lt;code&gt;io.StringIO&lt;/code&gt; stream object, to act as a virtual terminal so to speak. I then tried to extract the bar string from that. This turned out to be quite a nightmarish experience (may have had to do with it getting quite late). Probably, &lt;code&gt;tqdm&lt;/code&gt; tries to do very smart things when outputting to this stream, and clearly I wasn’t smart enough to undo those smart things. Luckily, after a good night’s rest, I found that directly extracting the bar string from &lt;code&gt;bar.__str__()&lt;/code&gt; does not do weird animation stuff and just gives a neat, clean progress bar. Phew.&lt;/li&gt;
&lt;li&gt;Twitter is not a terminal. The relevance of this obvious statement is that Twitter does not use a fixed width font. Madness, I know. But luckily, the unicode committee (I’m sure there is one, perhaps several, in fact) blessed us with more kinds of space characters than we could ever have hoped for. &lt;code&gt;\u3000&lt;/code&gt;, the “ideographic space”, is the one that turns out to have the same width on Twitter as (most) unicode characters used for the bar itself. So I replace spaces in the bar (barring (heehee) those around the bar) with this ideographic one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tweet-with-tweepy&quot;&gt;Tweet with Tweepy&lt;/h2&gt;
&lt;p&gt;The actual tweeting is the easiest part in all this. The &lt;a href=&quot;https://realpython.com/twitter-bot-python-tweepy/#creating-twitter-api-authentication-credentials&quot;&gt;above mentioned article&lt;/a&gt; explains most of it using the &lt;a href=&quot;https://www.tweepy.org/&quot;&gt;Tweepy&lt;/a&gt; package. You need the keys you obtained earlier to authenticate and create an &lt;code&gt;api&lt;/code&gt; object (see the snippet in the article).&lt;/p&gt;
&lt;p&gt;Then, tweeting is as simple as:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;update_status(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Ceci n&apos;est pas une tweet&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;810&quot; height=&quot;475&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_ZdxO48qSyJmHrXsL-1f57d952.Gm0PiurH_Z1X5XYc.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simple. J’approuve.&lt;/p&gt;
&lt;p&gt;If all goes well, this command will return a giant blob of JSON, wrapped in some Tweepy class. Not to worry, do not disturb it, it means you no harm. If for some reason the Tweepy call failed, you’ll get an error message, so you’ll know when you actually have to start paying attention.&lt;/p&gt;
&lt;h2 id=&quot;automate-on-github-actions&quot;&gt;Automate on GitHub Actions&lt;/h2&gt;
&lt;p&gt;Obviously, the last part of the show is about getting rid of any future manual action and getting back to watching YouTube. We are programmers, after all. Moreover, we are scientists and we don’t have time for manual labor. That is what PhD stu…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[anxious whispering]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[angry, impatient whispering]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not supposed to…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[university PR department whispers]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, but…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[whispered definitive executive order]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Automation, then!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[financial whispers]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For free! Yes, we can, with GitHub Actions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[mumbled approval]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After putting all my code in a git repository (on GitHub), I created a workflow file &lt;code&gt;.github/workflows/tweet_progress.yml&lt;/code&gt;. The file looks something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Tweet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; latest progresson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  schedule&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cron&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &apos;0 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&apos;  &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;00&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; UTC&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, see https&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;://&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;crontab&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;guru&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  #&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; allows you to run this workflow manually from the &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Actions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tab&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  tweet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    runs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ubuntu&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; uses&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;setup&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pip install &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;r requirements&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; run script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_API&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_API }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_API_SECRET&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_API_SECRET }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_ACCESS&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_ACCESS }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          BOT_ACCESS_SECRET&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ secrets.BOT_ACCESS_SECRET }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; python run&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the &lt;code&gt;on&lt;/code&gt; section, we make our Tweepy script run on a regular &lt;code&gt;schedule&lt;/code&gt;: every day at 10 a.m., UTC (check out &lt;a href=&quot;https://crontab.guru/&quot;&gt;https://crontab.guru/&lt;/a&gt; if you don’t want to bother remembering the arcane cron syntax, thanks to&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/u/fca35bfb3190?source=post_page---user_mention--1cf3f19dcda8---------------------------------------&quot;&gt;Stefan Verhoeven&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;for the tip). The data is updated daily in the morning, so this should use the freshest data most days. We can also trigger the job manually by adding &lt;code&gt;workflow_dispatch&lt;/code&gt;. The part below &lt;code&gt;jobs&lt;/code&gt; is what will actually run on a GitHub machine and should be mostly self-explanatory. This will also be different for your specific application (unless you copy mine). The important thing to notice, though, is the bold part where I pass in all the keys.&lt;/p&gt;
&lt;p&gt;Two things to make this possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The awesome &lt;a href=&quot;https://pypi.org/project/ConfigArgParse/&quot;&gt;ConfigArgParse&lt;/a&gt; module allows for specifying program parameters in three ways: via command line arguments (like the Python standard library &lt;code&gt;argparse&lt;/code&gt;), via a config file or via environment variables, all through one convenient, almost-drop-in-replacement-of- &lt;code&gt;argparse&lt;/code&gt; call. On my laptop (for testing and such) I added a config file with the keys in it (and put the name of that file in &lt;code&gt;.gitignore&lt;/code&gt;, after my earlier key committing booboo), but on GitHub Actions I can now pass them in through environment variables via the &lt;code&gt;env&lt;/code&gt; section.&lt;/li&gt;
&lt;li&gt;The second part is those &lt;code&gt;${{ secrets.THING }}&lt;/code&gt; things. You have to &lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository&quot;&gt;store the Twitter keys in GitHub secrets (instructions here)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commit the yml file, push it to GitHub, and just like that you’ve got yourself an automatically updating Twitter bot!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;605&quot; height=&quot;568&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_l1__Q8DxN_LnAe_VU4L3CQ-2dc29b71.Dgpci5tY_2rTIFX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The top two tweets were automatically produced. It’s alive! ALIVE!!!&lt;/p&gt;
&lt;p&gt;I hope I convinced you that if you have a cool idea for a bot and know of a data source, you should immediately go for it! Just &lt;a href=&quot;https://github.com/egpbos/covid_vaccine_progress_bot/&quot;&gt;fork my repo&lt;/a&gt; if you want to get a quick start, modify it to your liking and put it out there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations&lt;/strong&gt;, you just made the world a better, more well-informed place!&lt;/p&gt;
&lt;p&gt;I’d love to hear what you think, let me know in the comments. Also, if you want some help setting up your bot, don’t hesitate to ask.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_YL2rNx2g8oxkMG149unWgQ-2fde1464.1WN8Ucbt.png" medium="image"/><author>Patrick Bos</author></item><item><title>Building a Web Service to Manage Scientific Simulation Data Using GraphQL</title><link>https://blog.esciencecenter.nl/posts/2021-01-15---building-a-web-service-to-manage-scientific-simulation-data-</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2021-01-15---building-a-web-service-to-manage-scientific-simulation-data-</guid><description>&lt;p&gt;Therefore, the &lt;a href=&quot;https://github.com/nlesc-nano/ceiba&quot;&gt;Ceiba&lt;/a&gt; web service needs to handle two kinds of requests by the client: read-only queries and mutations on the datasets. These “queries” and “mutations” can be easily describe with &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In a nutshell, &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; defines a contract (known as a schema) between the actions that a client can perform with the web service and the possible outcomes of those actions. More formally, &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; is a query language that allows you to specify an application Programming interface (API) using different programming languages. If you have previous experience with &lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;RESTful API&lt;/a&gt; have a look at a comparison between &lt;a href=&quot;https://www.howtographql.com/basics/1-graphql-is-the-better-rest/&quot;&gt;GraphQL and REST&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But how does GraphQL work? First, you need to define a schema using the &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; schema language. The following code snippet defines a schema to query a job using its status,&lt;/p&gt;
&lt;p&gt;Schema definition for job query&lt;/p&gt;
&lt;p&gt;The Query** schema specifies that in order to request some &lt;strong&gt;jobs&lt;/strong&gt;* you need to provide a &lt;em&gt;Status&lt;/em&gt; argument, where &lt;em&gt;Status&lt;/em&gt; can be one of four possibilities: &lt;em&gt;AVAILABLE, DONE, FAILED&lt;/em&gt; and *RUNNING. *The exclamation mark (!) indicates that the argument cannot be &lt;em&gt;Null&lt;/em&gt; (a.k.a &lt;em&gt;None&lt;/em&gt; in Python).&lt;/p&gt;
&lt;p&gt;The following &lt;strong&gt;Mutation&lt;/strong&gt; schema defines the required arguments to update a given job status.&lt;/p&gt;
&lt;p&gt;Schema definitation for Job status mutation&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;&lt;strong&gt;updateJob&lt;/strong&gt;&lt;/em&gt; action specifies that you must provide an &lt;em&gt;id&lt;/em&gt; and a &lt;em&gt;new_status&lt;/em&gt; in order to be able to update a job. You will receive a &lt;em&gt;Reply&lt;/em&gt; specifying whether the update action has succeeded.&lt;/p&gt;
&lt;p&gt;Have a look at the Ceiba &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/sdl/Query.graphql&quot;&gt;queries&lt;/a&gt; and &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/sdl/Mutation.graphql&quot;&gt;mutations&lt;/a&gt; schemas. They are slightly more complex than the aforementioned schemas but follow the same rationale as the previous examples. You can also have a look at the official &lt;a href=&quot;https://graphql.org/learn/&quot;&gt;introduction to GraphQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We have just defined the schemas that specify the actions that we want to perform. We still need to implement the actions and for doing so, we need a GraphQL engine: a library that takes the schemas together with the code that implements the actions and generates an API.&lt;/p&gt;
&lt;p&gt;We have chosen the &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette GraphQL engine&lt;/a&gt; to implement our web service mostly because it is easy to use and open source. The following snippet shows a possible implementation for querying jobs based on their status using &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;the &lt;em&gt;&lt;strong&gt;Resolver&lt;/strong&gt;&lt;/em&gt; decorator indicates that the &lt;em&gt;&lt;strong&gt;resolver_query_jobs&lt;/strong&gt;&lt;/em&gt; function corresponds to the implementation of the &lt;em&gt;&lt;strong&gt;query jobs&lt;/strong&gt;&lt;/em&gt; schema. The function takes 4 arguments of which I only use &lt;em&gt;&lt;strong&gt;args&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;ctx&lt;/strong&gt;&lt;/em&gt;(You can refer to &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette&lt;/a&gt; for further details). ***args ***contains the arguments given by the client code, while ***ctx ***contains the context for running the current function, for example the handler to access the database that is called &lt;em&gt;&lt;strong&gt;mongodb&lt;/strong&gt;&lt;/em&gt; in this code snippet.&lt;/p&gt;
&lt;p&gt;Notice that the definition of the aforementioned function starts with the &lt;em&gt;async&lt;/em&gt; keyword. &lt;a href=&quot;https://docs.python.org/3/library/asyncio.html&quot;&gt;Asyncio&lt;/a&gt; is a popular built-in Python library to write concurrent code. It is extensively used to write high performance web services.&lt;/p&gt;
&lt;p&gt;In the Ceiba web service implementation of the &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;&lt;strong&gt;queries&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/mutation_resolvers.py&quot;&gt;&lt;strong&gt;mutations&lt;/strong&gt;&lt;/a&gt;, there are definitions for all the Python functions that perform the actions specified in the GraphQL schemas. For each query and mutation, there is a corresponding function.&lt;/p&gt;
&lt;h2 id=&quot;the-database&quot;&gt;The database&lt;/h2&gt;
&lt;p&gt;We need a database not only for storing the interesting data but also to store the jobs metadata, like what jobs are available. For the Ceiba web service we use &lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My personal opinion is that a &lt;a href=&quot;https://en.wikipedia.org/wiki/NoSQL&quot;&gt;NoSQL database&lt;/a&gt; like &lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB&lt;/a&gt; gives a significant advantage over traditional SQL databases on research projects where up-front design of the schemas to store data is unfeasible. The research priorities can change as the project evolves and having dynamic schemas to store the data makes the researchers’ lives easier.&lt;/p&gt;
&lt;h2 id=&quot;putting-all-together&quot;&gt;Putting all together&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Building a Web Service to Manage Scientific Simulation Data Using GraphQL&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;456&quot; src=&quot;https://blog.esciencecenter.nl/_astro/building-a-web-service-to-manage-scienti-33d7f19d.DZVFi1SS_Z1O8kwP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@frankiefoto?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;frank mckenna&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker containers&lt;/a&gt; are the perfect way to ship our web service. We just need to write a [Dockerfile](&lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/&quot;&gt;https://github.com/nlesc-nano/insilico-server/blob/master/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dockerfile) with the recipe to install and start the service together with the &lt;a href=&quot;https://hub.docker.com/_/mongo&quot;&gt;mongo container&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to deploy the Ceiba web service to a remote server you need to follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href=&quot;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html&quot;&gt;Ansible&lt;/a&gt; in your computer.&lt;/li&gt;
&lt;li&gt;Clone the &lt;a href=&quot;https://github.com/nlesc-nano/ceiba&quot;&gt;Ceiba&lt;/a&gt; repo and go to the &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;provisioning&lt;/a&gt; folder.&lt;/li&gt;
&lt;li&gt;Edit the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html&quot;&gt;inventory&lt;/a&gt; file with the address of the server(s) where you want to install the runner.&lt;/li&gt;
&lt;li&gt;Edit the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks.html&quot;&gt;playbook&lt;/a&gt; file with the &lt;code&gt;remote_user&lt;/code&gt; name for the remote servers.&lt;/li&gt;
&lt;li&gt;Make sure that you can ssh to your server(s).&lt;/li&gt;
&lt;li&gt;Install the runner with the following command:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ansible-playbook -i inventory playbook.ymlThe Ceiba server should be up and running!&lt;/p&gt;
&lt;h2 id=&quot;the-pesky-details&quot;&gt;The pesky details&lt;/h2&gt;
&lt;p&gt;You certainly do not want to keep your web service open, so people can remove your data. You want that users are authenticated before using your service, but you also do not want to manage all the security on your own. Getting authentication right using something like &lt;a href=&quot;https://en.wikipedia.org/wiki/OAuth&quot;&gt;OAuth2&lt;/a&gt; is tricky and it needs at least an entire post on its own.&lt;/p&gt;
&lt;p&gt;Also, you need to host your web service somewhere and &lt;strong&gt;hosting costs money&lt;/strong&gt;. It is simply not viable that you host your service in your computer, it is not safe and it takes too much time to maintain. Fortunately for researchers, there are institutions like &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt; that can help you to host a web service for research purposes.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;Creating the Ceiba web service would not be possible without &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt; advice and the computational resources provided by &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will also to thank &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jens-wehner/&quot;&gt;Jens Wehner&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-nicolas-renaud-2/&quot;&gt;Nicolas Renaud,&lt;/a&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/johan-hidding-msc/&quot;&gt;Johan Hidding&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-lopez-tarifa/&quot;&gt;Pablo Lopez-Tarifa&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/victor-azizi-msc/&quot;&gt;Victor Azizi&lt;/a&gt; for their feedback and support.&lt;/p&gt;
&lt;p&gt;Specially thanks to [Patrick Bos,] &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;Tom Bakker&lt;/a&gt; for their feedback.&lt;/p&gt;</description><pubDate>Fri, 15 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Therefore, the &lt;a href=&quot;https://github.com/nlesc-nano/ceiba&quot;&gt;Ceiba&lt;/a&gt; web service needs to handle two kinds of requests by the client: read-only queries and mutations on the datasets. These “queries” and “mutations” can be easily describe with &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In a nutshell, &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; defines a contract (known as a schema) between the actions that a client can perform with the web service and the possible outcomes of those actions. More formally, &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; is a query language that allows you to specify an application Programming interface (API) using different programming languages. If you have previous experience with &lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;RESTful API&lt;/a&gt; have a look at a comparison between &lt;a href=&quot;https://www.howtographql.com/basics/1-graphql-is-the-better-rest/&quot;&gt;GraphQL and REST&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But how does GraphQL work? First, you need to define a schema using the &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; schema language. The following code snippet defines a schema to query a job using its status,&lt;/p&gt;
&lt;p&gt;Schema definition for job query&lt;/p&gt;
&lt;p&gt;The Query** schema specifies that in order to request some &lt;strong&gt;jobs&lt;/strong&gt;* you need to provide a &lt;em&gt;Status&lt;/em&gt; argument, where &lt;em&gt;Status&lt;/em&gt; can be one of four possibilities: &lt;em&gt;AVAILABLE, DONE, FAILED&lt;/em&gt; and *RUNNING. *The exclamation mark (!) indicates that the argument cannot be &lt;em&gt;Null&lt;/em&gt; (a.k.a &lt;em&gt;None&lt;/em&gt; in Python).&lt;/p&gt;
&lt;p&gt;The following &lt;strong&gt;Mutation&lt;/strong&gt; schema defines the required arguments to update a given job status.&lt;/p&gt;
&lt;p&gt;Schema definitation for Job status mutation&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;&lt;strong&gt;updateJob&lt;/strong&gt;&lt;/em&gt; action specifies that you must provide an &lt;em&gt;id&lt;/em&gt; and a &lt;em&gt;new_status&lt;/em&gt; in order to be able to update a job. You will receive a &lt;em&gt;Reply&lt;/em&gt; specifying whether the update action has succeeded.&lt;/p&gt;
&lt;p&gt;Have a look at the Ceiba &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/sdl/Query.graphql&quot;&gt;queries&lt;/a&gt; and &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/sdl/Mutation.graphql&quot;&gt;mutations&lt;/a&gt; schemas. They are slightly more complex than the aforementioned schemas but follow the same rationale as the previous examples. You can also have a look at the official &lt;a href=&quot;https://graphql.org/learn/&quot;&gt;introduction to GraphQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We have just defined the schemas that specify the actions that we want to perform. We still need to implement the actions and for doing so, we need a GraphQL engine: a library that takes the schemas together with the code that implements the actions and generates an API.&lt;/p&gt;
&lt;p&gt;We have chosen the &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette GraphQL engine&lt;/a&gt; to implement our web service mostly because it is easy to use and open source. The following snippet shows a possible implementation for querying jobs based on their status using &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;the &lt;em&gt;&lt;strong&gt;Resolver&lt;/strong&gt;&lt;/em&gt; decorator indicates that the &lt;em&gt;&lt;strong&gt;resolver_query_jobs&lt;/strong&gt;&lt;/em&gt; function corresponds to the implementation of the &lt;em&gt;&lt;strong&gt;query jobs&lt;/strong&gt;&lt;/em&gt; schema. The function takes 4 arguments of which I only use &lt;em&gt;&lt;strong&gt;args&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;ctx&lt;/strong&gt;&lt;/em&gt;(You can refer to &lt;a href=&quot;https://tartiflette.io/&quot;&gt;Tartiflette&lt;/a&gt; for further details). ***args ***contains the arguments given by the client code, while ***ctx ***contains the context for running the current function, for example the handler to access the database that is called &lt;em&gt;&lt;strong&gt;mongodb&lt;/strong&gt;&lt;/em&gt; in this code snippet.&lt;/p&gt;
&lt;p&gt;Notice that the definition of the aforementioned function starts with the &lt;em&gt;async&lt;/em&gt; keyword. &lt;a href=&quot;https://docs.python.org/3/library/asyncio.html&quot;&gt;Asyncio&lt;/a&gt; is a popular built-in Python library to write concurrent code. It is extensively used to write high performance web services.&lt;/p&gt;
&lt;p&gt;In the Ceiba web service implementation of the &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;&lt;strong&gt;queries&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/insilicoserver/mutation_resolvers.py&quot;&gt;&lt;strong&gt;mutations&lt;/strong&gt;&lt;/a&gt;, there are definitions for all the Python functions that perform the actions specified in the GraphQL schemas. For each query and mutation, there is a corresponding function.&lt;/p&gt;
&lt;h2 id=&quot;the-database&quot;&gt;The database&lt;/h2&gt;
&lt;p&gt;We need a database not only for storing the interesting data but also to store the jobs metadata, like what jobs are available. For the Ceiba web service we use &lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My personal opinion is that a &lt;a href=&quot;https://en.wikipedia.org/wiki/NoSQL&quot;&gt;NoSQL database&lt;/a&gt; like &lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB&lt;/a&gt; gives a significant advantage over traditional SQL databases on research projects where up-front design of the schemas to store data is unfeasible. The research priorities can change as the project evolves and having dynamic schemas to store the data makes the researchers’ lives easier.&lt;/p&gt;
&lt;h2 id=&quot;putting-all-together&quot;&gt;Putting all together&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Building a Web Service to Manage Scientific Simulation Data Using GraphQL&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;456&quot; src=&quot;https://blog.esciencecenter.nl/_astro/building-a-web-service-to-manage-scienti-33d7f19d.DZVFi1SS_Z1O8kwP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@frankiefoto?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;frank mckenna&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=medium&amp;#x26;utm_medium=referral&quot;&gt;Unsplash&lt;/a&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker containers&lt;/a&gt; are the perfect way to ship our web service. We just need to write a [Dockerfile](&lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/blob/master/&quot;&gt;https://github.com/nlesc-nano/insilico-server/blob/master/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dockerfile) with the recipe to install and start the service together with the &lt;a href=&quot;https://hub.docker.com/_/mongo&quot;&gt;mongo container&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to deploy the Ceiba web service to a remote server you need to follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href=&quot;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html&quot;&gt;Ansible&lt;/a&gt; in your computer.&lt;/li&gt;
&lt;li&gt;Clone the &lt;a href=&quot;https://github.com/nlesc-nano/ceiba&quot;&gt;Ceiba&lt;/a&gt; repo and go to the &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;provisioning&lt;/a&gt; folder.&lt;/li&gt;
&lt;li&gt;Edit the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html&quot;&gt;inventory&lt;/a&gt; file with the address of the server(s) where you want to install the runner.&lt;/li&gt;
&lt;li&gt;Edit the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks.html&quot;&gt;playbook&lt;/a&gt; file with the &lt;code&gt;remote_user&lt;/code&gt; name for the remote servers.&lt;/li&gt;
&lt;li&gt;Make sure that you can ssh to your server(s).&lt;/li&gt;
&lt;li&gt;Install the runner with the following command:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ansible-playbook -i inventory playbook.ymlThe Ceiba server should be up and running!&lt;/p&gt;
&lt;h2 id=&quot;the-pesky-details&quot;&gt;The pesky details&lt;/h2&gt;
&lt;p&gt;You certainly do not want to keep your web service open, so people can remove your data. You want that users are authenticated before using your service, but you also do not want to manage all the security on your own. Getting authentication right using something like &lt;a href=&quot;https://en.wikipedia.org/wiki/OAuth&quot;&gt;OAuth2&lt;/a&gt; is tricky and it needs at least an entire post on its own.&lt;/p&gt;
&lt;p&gt;Also, you need to host your web service somewhere and &lt;strong&gt;hosting costs money&lt;/strong&gt;. It is simply not viable that you host your service in your computer, it is not safe and it takes too much time to maintain. Fortunately for researchers, there are institutions like &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt; that can help you to host a web service for research purposes.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h2&gt;
&lt;p&gt;Creating the Ceiba web service would not be possible without &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt; advice and the computational resources provided by &lt;a href=&quot;https://www.surf.nl/en&quot;&gt;SURF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will also to thank &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-jens-wehner/&quot;&gt;Jens Wehner&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-nicolas-renaud-2/&quot;&gt;Nicolas Renaud,&lt;/a&gt; &lt;a href=&quot;https://www.esciencecenter.nl/team/johan-hidding-msc/&quot;&gt;Johan Hidding&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/dr-pablo-lopez-tarifa/&quot;&gt;Pablo Lopez-Tarifa&lt;/a&gt; and &lt;a href=&quot;https://www.esciencecenter.nl/team/victor-azizi-msc/&quot;&gt;Victor Azizi&lt;/a&gt; for their feedback and support.&lt;/p&gt;
&lt;p&gt;Specially thanks to [Patrick Bos,] &lt;a href=&quot;https://github.com/nlesc-nano/insilico-server/tree/master/provisioning&quot;&gt;Tom Bakker&lt;/a&gt; for their feedback.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/building-a-web-service-to-manage-scienti-33d7f19d.DZVFi1SS.jpg" medium="image"/><author>Felipe</author></item><item><title>eScience trends from ADASS 2020</title><link>https://blog.esciencecenter.nl/posts/2020-11-23---escience-trends-from-adass-2020</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-11-23---escience-trends-from-adass-2020</guid><description>&lt;h1 id=&quot;escience-trends-from-adass-2020&quot;&gt;&lt;strong&gt;eScience trends from ADASS 2020&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;scaling-up-compute-and-storage-resources-are-not-going-to-be-the-biggest-hurdles&quot;&gt;&lt;strong&gt;Scaling up compute and storage resources are not going to be the biggest hurdles.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;**8&lt;/p&gt;
&lt;h3 id=&quot;my-general-feeling-about-this-conference&quot;&gt;My general feeling about this conference&lt;/h3&gt;
&lt;p&gt;What a delight ADASS (Astronomical Data Analysis Software and Systems) 2020 was! My first virtual conference, but the same positive vibe as the previous one, ADASS 2019 in Groningen, The Netherlands. This one was in Granada, Spain, but it could have been anywhere, obviously. There were 581 participants and over 50 talks. Last year, ADASS had 353 participants, which was also quite considerable. One of the organisers said that there were quite a few participants from previously underrepresented countries. The cost of participating in this virtual conference was substantially lower than for the physical conferences, which could explain its popularity this year.&lt;/p&gt;
&lt;p&gt;In hindsight, the Discord tool for discussion and social talk was essential. This gave me a feeling of being part of this conference. It was set up nicely with separate channels for each session, that continued after the session had ended, together with a number of general channels. Talks started at 6:00 a.m. CET and ended at 20:30 CET with somewhat fewer talks during the middle of the day to accommodate for speakers and audience in other time zones. Of course, it is impossible to make a schedule that fits all time zones, but I guess the organisers wanted to avoid people having to present their work at 3 a.m. local time.&lt;/p&gt;
&lt;h3 id=&quot;highlights&quot;&gt;Highlights&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;372&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-5a8a4b9c.BSv99xzV_Z1ukvpi.webp&quot; srcset=&quot;&quot;&gt;
Slide from Matthew Graham’s presentation “&lt;a href=&quot;https://www.youtube.com/watch?v=rPb22usn7hU&amp;#x26;t=41m10s&quot;&gt;What did we get right? Lessons learned from the first 300 million alerts of ZTF&lt;/a&gt;” .Matthew Graham** (invited speaker, professor at Caltech and project scientist for ZTF, the Zwicky Transient Facility), started off by listing his predictions from his ADASS 2008 presentation: what he thought would be the main bottlenecks and achievements in astronomy by the year 2020. Here are two of those predictions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In 2008 he perceived that artificial intelligence would govern the alert streams without human interactions. We have clearly not reached that point yet. Humans are still in the loop, i.e. the current machine learning algorithms are not fully trusted.&lt;/li&gt;
&lt;li&gt;In 2020, we would have huge problems with scalability to process the data firehoses and store the data lakes. As stated clearly in the slide above, this turns out not to be the case: we do have the compute power and storage to handle all this data and we can develop software that scales well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead our focus needs to shift from data management to information and knowledge management. Present concerns are about establishing veracity, about provenance and probabilities based on astrophysical statistics. What are my assumptions and where are they coming from? These are presently much more severe concerns in delivering sound scientific conclusions than technogical challenges, they require astronomical or astrophysical expertise rather than computer engineering solutions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;341&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-fce35a68.D-tBYYNM_1P46Xj.webp&quot; srcset=&quot;&quot;&gt;
Slide from talk by Verdana Desai: “Enabling next-generation science investigations with the NASA Astrophysics Archives”.&lt;strong&gt;Vandana Desai&lt;/strong&gt; (invited speaker, associate scientist at Caltech and science lead for the Infrared Science Archive (IRSA) of IPAC, the Infrared Processing &amp;#x26; Analysis Center) gave an insightful talk: “Enabling next-generation science investigations with the NASA Astrophysics Archives”. This covered part of her white paper “&lt;a href=&quot;https://www.noao.edu/2020Decadal/files/DesaiVandana.pdf&quot;&gt;A Science Platform Network to Facilitate Astrophysics in the 2020s&lt;/a&gt;”. This white paper advocates “funding of data centers to develop and operate ‘science platforms’, which will provide storage and computing resources for the astronomical community to run analyses near the data”. “Science platforms” are envisaged as the way to enable scientific progress in the era of big data; our progress in understanding physical processes in the cosmos is enhanced by the simultaneous use of multi-wavelength observations possibly augmented with neutrino and gravitational wave detections. These platforms should accommodate the needs of a much larger group than just the ‘power users’, serving many more than the inner circle of scientists that are aware of all the complexities involved in reducing the raw data. Desai made clear that “We cannot have all of the data that an astronomer might want to use under a single, unified science platform”. This is not feasible “and probably never will be “ because of the “practicalities involved” which I suppose reflects the heterogeneity of astronomical observations. It is clear that analysis tools, including machine learning will require more compute power. The bottom panel from the slide above shows the increased use of archival data in the last decades, i.e. the use of data by others than the people near the principal investigator of a rewarded observing proposal. Until now, the combined data from astronomical sources was mostly extracted from catalogs which only include a few quantities like position on the sky, peak intensity, integrated flux and perhaps a few other quantities derived from the source pixel distribution. In the future, astronomers will need access to the actual pixels comprising the source for a more accurate analysis, which enhances the demand for storage and computing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-cf4353c4.CBfjN8-G_jh76q.webp&quot; srcset=&quot;&quot;&gt;
Slide from Cristobal Bordiu’s presentation “&lt;a href=&quot;https://www.youtube.com/watch?v=oG_Xq3FzRGU&amp;#x26;t=1h53m36s&quot;&gt;Astronomical research in the next decade: trends, barriers and needs in data access, management, visualization and analysis&lt;/a&gt;”.Some of the same conclusions, but more from a European rather than American perspective, were drawn by &lt;strong&gt;Cristobal Bordiu&lt;/strong&gt; (postdoc for the Italian National Institute of Astrophysics (INAF) at the Catania Astrophysical Observatory) from a survey for NEANIAS (Novel EOSC Services for Emerging Atmosphere, Underwater &amp;#x26; Space Challenges). This project, which emerged from EOSC, the European Open Science Cloud, aims to set solid foundations for astronomy in the coming decade, so it covers the same time span as the &lt;a href=&quot;https://www.noao.edu/2020Decadal/files/DesaiVandana.pdf&quot;&gt;white paper by Desai et al.&lt;/a&gt; The respondees showed concern about storage, about reproducibility and about findability and interopability of raw, calibrated and higher level data products, as reflected by the slide above. They also perceive the availability of visual analytics tools as a main research barrier.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The lack of science-ready data products, &lt;a href=&quot;https://blog.esciencecenter.nl/escience-trends-from-adass-2019-f68cd8cca49b&quot;&gt;which I reported on last year&lt;/a&gt;, applies mostly to radio astronomy, where the complete reduction of observations, including calibration of visibilities and subsequent imaging has to be done quite often by the researchers themselves. Fortunately, this situation is improving, with radio observatories taking up the glove. However, what ADASS 2020 made clear, is that more is needed that just these science-ready data products; to enhance scientific progress interoperable data from simultaneous observations at multiple electromagnetic wavelengths — possibly augmented with neutrino and gravitational wave detections— are required. Most conveniently, these would be analysed using “science platforms” which offer software tools for analysis, such as machine learning, that can be run in a completely hardware agnostic way.&lt;/p&gt;</description><pubDate>Mon, 23 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;escience-trends-from-adass-2020&quot;&gt;&lt;strong&gt;eScience trends from ADASS 2020&lt;/strong&gt;&lt;/h1&gt;
&lt;h2 id=&quot;scaling-up-compute-and-storage-resources-are-not-going-to-be-the-biggest-hurdles&quot;&gt;&lt;strong&gt;Scaling up compute and storage resources are not going to be the biggest hurdles.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;**8&lt;/p&gt;
&lt;h3 id=&quot;my-general-feeling-about-this-conference&quot;&gt;My general feeling about this conference&lt;/h3&gt;
&lt;p&gt;What a delight ADASS (Astronomical Data Analysis Software and Systems) 2020 was! My first virtual conference, but the same positive vibe as the previous one, ADASS 2019 in Groningen, The Netherlands. This one was in Granada, Spain, but it could have been anywhere, obviously. There were 581 participants and over 50 talks. Last year, ADASS had 353 participants, which was also quite considerable. One of the organisers said that there were quite a few participants from previously underrepresented countries. The cost of participating in this virtual conference was substantially lower than for the physical conferences, which could explain its popularity this year.&lt;/p&gt;
&lt;p&gt;In hindsight, the Discord tool for discussion and social talk was essential. This gave me a feeling of being part of this conference. It was set up nicely with separate channels for each session, that continued after the session had ended, together with a number of general channels. Talks started at 6:00 a.m. CET and ended at 20:30 CET with somewhat fewer talks during the middle of the day to accommodate for speakers and audience in other time zones. Of course, it is impossible to make a schedule that fits all time zones, but I guess the organisers wanted to avoid people having to present their work at 3 a.m. local time.&lt;/p&gt;
&lt;h3 id=&quot;highlights&quot;&gt;Highlights&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;372&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-5a8a4b9c.BSv99xzV_Z1ukvpi.webp&quot; srcset=&quot;&quot;&gt;
Slide from Matthew Graham’s presentation “&lt;a href=&quot;https://www.youtube.com/watch?v=rPb22usn7hU&amp;#x26;t=41m10s&quot;&gt;What did we get right? Lessons learned from the first 300 million alerts of ZTF&lt;/a&gt;” .Matthew Graham** (invited speaker, professor at Caltech and project scientist for ZTF, the Zwicky Transient Facility), started off by listing his predictions from his ADASS 2008 presentation: what he thought would be the main bottlenecks and achievements in astronomy by the year 2020. Here are two of those predictions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In 2008 he perceived that artificial intelligence would govern the alert streams without human interactions. We have clearly not reached that point yet. Humans are still in the loop, i.e. the current machine learning algorithms are not fully trusted.&lt;/li&gt;
&lt;li&gt;In 2020, we would have huge problems with scalability to process the data firehoses and store the data lakes. As stated clearly in the slide above, this turns out not to be the case: we do have the compute power and storage to handle all this data and we can develop software that scales well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead our focus needs to shift from data management to information and knowledge management. Present concerns are about establishing veracity, about provenance and probabilities based on astrophysical statistics. What are my assumptions and where are they coming from? These are presently much more severe concerns in delivering sound scientific conclusions than technogical challenges, they require astronomical or astrophysical expertise rather than computer engineering solutions.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;341&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-fce35a68.D-tBYYNM_1P46Xj.webp&quot; srcset=&quot;&quot;&gt;
Slide from talk by Verdana Desai: “Enabling next-generation science investigations with the NASA Astrophysics Archives”.&lt;strong&gt;Vandana Desai&lt;/strong&gt; (invited speaker, associate scientist at Caltech and science lead for the Infrared Science Archive (IRSA) of IPAC, the Infrared Processing &amp;#x26; Analysis Center) gave an insightful talk: “Enabling next-generation science investigations with the NASA Astrophysics Archives”. This covered part of her white paper “&lt;a href=&quot;https://www.noao.edu/2020Decadal/files/DesaiVandana.pdf&quot;&gt;A Science Platform Network to Facilitate Astrophysics in the 2020s&lt;/a&gt;”. This white paper advocates “funding of data centers to develop and operate ‘science platforms’, which will provide storage and computing resources for the astronomical community to run analyses near the data”. “Science platforms” are envisaged as the way to enable scientific progress in the era of big data; our progress in understanding physical processes in the cosmos is enhanced by the simultaneous use of multi-wavelength observations possibly augmented with neutrino and gravitational wave detections. These platforms should accommodate the needs of a much larger group than just the ‘power users’, serving many more than the inner circle of scientists that are aware of all the complexities involved in reducing the raw data. Desai made clear that “We cannot have all of the data that an astronomer might want to use under a single, unified science platform”. This is not feasible “and probably never will be “ because of the “practicalities involved” which I suppose reflects the heterogeneity of astronomical observations. It is clear that analysis tools, including machine learning will require more compute power. The bottom panel from the slide above shows the increased use of archival data in the last decades, i.e. the use of data by others than the people near the principal investigator of a rewarded observing proposal. Until now, the combined data from astronomical sources was mostly extracted from catalogs which only include a few quantities like position on the sky, peak intensity, integrated flux and perhaps a few other quantities derived from the source pixel distribution. In the future, astronomers will need access to the actual pixels comprising the source for a more accurate analysis, which enhances the demand for storage and computing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;eScience trends from ADASS 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-cf4353c4.CBfjN8-G_jh76q.webp&quot; srcset=&quot;&quot;&gt;
Slide from Cristobal Bordiu’s presentation “&lt;a href=&quot;https://www.youtube.com/watch?v=oG_Xq3FzRGU&amp;#x26;t=1h53m36s&quot;&gt;Astronomical research in the next decade: trends, barriers and needs in data access, management, visualization and analysis&lt;/a&gt;”.Some of the same conclusions, but more from a European rather than American perspective, were drawn by &lt;strong&gt;Cristobal Bordiu&lt;/strong&gt; (postdoc for the Italian National Institute of Astrophysics (INAF) at the Catania Astrophysical Observatory) from a survey for NEANIAS (Novel EOSC Services for Emerging Atmosphere, Underwater &amp;#x26; Space Challenges). This project, which emerged from EOSC, the European Open Science Cloud, aims to set solid foundations for astronomy in the coming decade, so it covers the same time span as the &lt;a href=&quot;https://www.noao.edu/2020Decadal/files/DesaiVandana.pdf&quot;&gt;white paper by Desai et al.&lt;/a&gt; The respondees showed concern about storage, about reproducibility and about findability and interopability of raw, calibrated and higher level data products, as reflected by the slide above. They also perceive the availability of visual analytics tools as a main research barrier.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The lack of science-ready data products, &lt;a href=&quot;https://blog.esciencecenter.nl/escience-trends-from-adass-2019-f68cd8cca49b&quot;&gt;which I reported on last year&lt;/a&gt;, applies mostly to radio astronomy, where the complete reduction of observations, including calibration of visibilities and subsequent imaging has to be done quite often by the researchers themselves. Fortunately, this situation is improving, with radio observatories taking up the glove. However, what ADASS 2020 made clear, is that more is needed that just these science-ready data products; to enhance scientific progress interoperable data from simultaneous observations at multiple electromagnetic wavelengths — possibly augmented with neutrino and gravitational wave detections— are required. Most conveniently, these would be analysed using “science platforms” which offer software tools for analysis, such as machine learning, that can be run in a completely hardware agnostic way.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/escience-trends-from-adass-2020-5a8a4b9c.BSv99xzV.png" medium="image"/><author>Hanno Spreeuw</author></item><item><title>Being a minority in fancy coding land: a Windows user.</title><link>https://blog.esciencecenter.nl/posts/2020-11-10---being-a-minority-in-fancy-coding-land-a-windows-user</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-11-10---being-a-minority-in-fancy-coding-land-a-windows-user</guid><description>&lt;h2 id=&quot;how-i-slowly-went-from-my-imposter-syndrome-hiding-to-accepting-what-i-am-a-windows-user-at-least-most-of-the-time-dont-worry-this-is-not-one-of-those-linux-vs-windows-posts&quot;&gt;How I slowly went from my imposter-syndrome hiding to accepting what I am. A Windows user, at least most of the time. (Don’t worry, this is NOT one of those Linux vs. Windows posts!)&lt;/h2&gt;
&lt;p&gt;I work at the &lt;a href=&quot;http://esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, a wonderful organization with very nice colleagues. Hopefully nice enough to stay my colleagues after the following confession: I am a Windows user.&lt;/p&gt;
&lt;p&gt;What’s so special about this? Most people use Windows, right?&lt;br&gt;
Well, not in my small &lt;em&gt;coding bubble&lt;/em&gt;.&lt;br&gt;
In the world I work in (use all your cliché imagination on nerds, hackers, computer scientists … but then remove those pictures of people wearing sun glasses indoors and desks full of pizza and caffeine-rich soft-drinks) coding from a Windows environment is often considered something between a no-go and a handicap. Breathing quickly, my fingers start to tremble as I write this, risking my career as a data scientist and machine learning practitioner. Or isn’t it all that bad?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1143&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_omI5G0XyVglCsQpBFmgf9A-744fa126.DLyAPxQw_Z1a64X8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-did-i-end-up-using-windows&quot;&gt;How did I end up using Windows?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(I see your shaking heads… why the hell did he end up there?)&lt;/em&gt;&lt;br&gt;
Let’s just say I have grown into it. All the way from &lt;a href=&quot;https://en.wikipedia.org/wiki/MS-DOS&quot;&gt;MS DOS&lt;/a&gt; through many painfully bad Windows versions and then I got so used to it that &lt;strong&gt;my skills to deal with it always felt better than my skills in handling the alternatives&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In addition, I am not a software developer or computer scientist by training. For a long time I was a physicist, a scientist, an academic. And in the scientific fields where I was working, using Windows was — believe it or not —the norm.&lt;/p&gt;
&lt;p&gt;Sure, I had already installed VirtualBox on my computer to run Ubuntu. I had even done some stuff with Ubuntu, including training some machine learning models (for implementations for which the packages didn’t support Windows…). I knew the 10 most common shell commands and everything else I would simply look up when needed. No wonder working with Linux still feels like writing a long letter with my left hand (I am right handed): I am terribly slow and in the end it looks horrible.&lt;/p&gt;
&lt;h3 id=&quot;but--why&quot;&gt;But … why?&lt;/h3&gt;
&lt;p&gt;Ah, I see. That all sounds like lame excuses to you.&lt;br&gt;
Well, it is not that I didn’t see all those golden merits of using Linux over Windows. Of course that’s the better system for many tasks, say setting up a server or handling access rights. And yes, it is much less wasteful in using hardware resources, it is considered less vulnerable, … and so on …, plus it is freely available without commercial interests. Still, I never wanted to pay the price of not having access to some of the high-end software that you would get on mac-OS or Windows (such as some MS office stuff or Adobe products). By the way: I am not trying to convince anybody that Windows is the best option. I am already happy if we can agree that it is &lt;em&gt;&lt;strong&gt;an&lt;/strong&gt;&lt;/em&gt; option.&lt;/p&gt;
&lt;p&gt;Time for another uncomfortable revelation: sometimes, being lazy simply pays off. For instance if you need to sort out a huge pile of stuff with some emotional value to you. Just put it in a box and hide it, take it out 10 years later and easily decide to dump nearly all of it. That’s a bit what I did with Linux. I survived with minimal use of VirtualBx and alike. Until recently, &lt;em&gt;finally!&lt;/em&gt;, Linux became part of Windows. And that works pretty well for me. &lt;a href=&quot;https://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/&quot;&gt;See how simple it now is to run Linux from Windows 10.&lt;/a&gt; And enjoy how easily you now can have the best of both worlds (not for nothing are more and more people arguing &lt;a href=&quot;https://towardsdatascience.com/dual-boot-is-dead-windows-and-linux-are-now-one-27555902a128&quot;&gt;that the good old “dual boot” is dead&lt;/a&gt; for exactly this reason).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1882&quot; height=&quot;1122&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ct2nr1TdVL8Qnmn5S2StDA-d5cb5a59.CpL0kF93_1djj7g.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Using Windows and Ubuntu side by side… in front of wonderful ugly-ish Windows blue… what a peaceful view, isn’t it?&lt;/p&gt;
&lt;p&gt;Enough all-united-hippie-talk. Let me share a few impressions of the actual life of an aspiring data scientist/research software engineer that happens to use Windows:&lt;/p&gt;
&lt;h3 id=&quot;starting-a-new-job&quot;&gt;Starting a new job.&lt;/h3&gt;
&lt;p&gt;I did a lot of programming as a researcher, but clearly I had never learned the proper software development basics such as testing, versioning etc. (in many academic fields those terms are often still unheard of!). No wonder I suffered a lot from imposter syndrome in the very beginning.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I hope they won’t find out I can’t write proper code!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Naturally, that means that you might not immediately ask your colleagues for help, because that would reveal your amateur level, right?&lt;br&gt;
But even worse, imagining you ask that colleague about how to get that Python package working and it turns out you are using Windows?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you help me setting up that environment? … By the way … I use Windows for that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The looks you get are suggesting that you have just asked how to import a 5GB.csv file into your Excel table (&lt;em&gt;*you don’t*&lt;/em&gt;). So little surprise I did spend a fair amount of time in Forum-Land during my first months…&lt;/p&gt;
&lt;h3 id=&quot;being-that-windows-user-in-the-room&quot;&gt;Being that Windows user in the room&lt;/h3&gt;
&lt;p&gt;You sit in that hands-on workshop on some fancy programming techniques, and the instructors asks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there anybody using Windows? (chuckles)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or, actually worse, nobody asks. Of course the instructions are only given for Linux and mac-OS. Well, at least I can hide my Windows handicap for a little longer then… but &lt;strong&gt;NO&lt;/strong&gt;!, when the instructor walks around to inspect the progress of the participants she/he will of course shout out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Wow … you are really using Windows for that!?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great. Now officially being tagged as &lt;strong&gt;the Windows user&lt;/strong&gt; in the room. Better keep quiet and not ask any silly questions then…&lt;/p&gt;
&lt;h3 id=&quot;get-used-to-rolled-eyes-then-secretly-roll-your-eyes-too&quot;&gt;Get used to rolled eyes —then secretly roll your eyes, too.&lt;/h3&gt;
&lt;p&gt;As I grew more confident of what I was doing, the imposter syndrome started to disappear. It still occasionally comes back to say hello (for instance if people speak shell over coffee), but that’s OK.&lt;/p&gt;
&lt;p&gt;In the end it’s luckily the results that matters most. I learned that you can write as good or bad code on Windows as on Linux. You can build great software on Windows that is then used by Linux people, and the other way around. Sure, for some things you better go the Linux way. But it turns out that in my projects this is less than 1% of my working time, which makes it OK to be a bit clumsy using it. And secretly (&lt;em&gt;don’t point at them, that’s mean!&lt;/em&gt;), I can also enjoy those moments when another colloquium presentation doesn’t run properly because Ubuntu did not work well with the projector, or the microphone, or both.&lt;/p&gt;
&lt;h3 id=&quot;do-better-than-pointing-at-each-other&quot;&gt;Do better than pointing at each other&lt;/h3&gt;
&lt;p&gt;Windows is more convenient for running some very common software (e.g. MS office), Linux is more stable… so go some cliches. But instead of fighting about what’s better (or hiding what feels inferior) it makes more sense to me to accept what’s there and simply go along with it. If somebody lives in a very geeky bubble it works fine to safely assume everyone runs their code on a certain operating systems and knows the in and outs of object oriented programming and containerization. But many of the more exciting projects involve people outside this bubble: researchers, users, future contributors, students. And they might as well — lo and behold — be using Windows (and by the way: containers are still primarily &lt;strong&gt;big steel boxes&lt;/strong&gt; to most people).&lt;/p&gt;
&lt;p&gt;So, even though in some IT-bubbles it can occasionally feel as if we are talking about a small unfortunate minority … in reality that’s really not true. Check out &lt;a href=&quot;https://www.freecodecamp.org/news/stack-overflow-developer-survey-2020-programming-language-framework-salary-data/&quot;&gt;the 2020 Stack Overflow Developer Survey&lt;/a&gt; to see that &lt;strong&gt;most developers actually use Windows&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-can-you-do-to-get-more-windows-users-to-adopt-your-package&quot;&gt;What can you do to get more Windows users to adopt your package?&lt;/h3&gt;
&lt;p&gt;Think of Windows what you want. I don’t work for Microsoft, and honestly, I don’t really care. But I assume that many coders out there working on great new software, methods, tools, tutorials, etc. actually want that people become happy users (paid by eternal gratitude). And that is a good enough reason to think about those Windows users as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider setting up your next continuous integration for your software package, so that it runs on all systems and will be used by more people.&lt;br&gt;
For instance with &lt;a href=&quot;https://docs.github.com/en/free-pro-team@latest/actions/guides/about-continuous-integration&quot;&gt;continuous integration using GitHub&lt;/a&gt; actions it can be as simple as adding a &lt;code&gt;‘windows-latest’&lt;/code&gt; to your matrix:&lt;br&gt;
&lt;code&gt;os: [‘ubuntu-latest’, ‘macos-latest’, ‘windows-latest’]   &lt;/code&gt; (small warning: adding different operating systems to such a continuous integration workflow is comparably easy, the later debugging sometimes is not. One option can be to work with &lt;a href=&quot;https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/&quot;&gt;Windows virtual machine&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;What about providing installation instructions for Windows users as well? Or did you just write a new tutorial? Great! But will it work for your fellow Windows users? You would be surprised how many packages and tutorials come with instructions that clearly won’t work for a Windows user.&lt;br&gt;
Don’t know how to do that? No Problem! Just ask a Windows user to help you. Believe me, they will be very glad to assist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-symmetry&quot;&gt;Final symmetry&lt;/h3&gt;
&lt;p&gt;Most of my arguments will hold when we just swap the named OS. So, obviously if you are (like me) primarily a Windows user: Think of all those Linux and mac-OS people out there. Either way, it will require learning a bit about the differences. But it will help to avoid a lot of frustration on all ends due to failing notebooks or hard to install packages.&lt;/p&gt;
&lt;h3 id=&quot;get-in-touch&quot;&gt;Get in touch&lt;/h3&gt;
&lt;p&gt;If you have comments or questions please get in touch! You can also find me on twitter: &lt;a href=&quot;https://twitter.com/me_datapoint&quot;&gt;&lt;strong&gt;me_datapoint&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 10 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-i-slowly-went-from-my-imposter-syndrome-hiding-to-accepting-what-i-am-a-windows-user-at-least-most-of-the-time-dont-worry-this-is-not-one-of-those-linux-vs-windows-posts&quot;&gt;How I slowly went from my imposter-syndrome hiding to accepting what I am. A Windows user, at least most of the time. (Don’t worry, this is NOT one of those Linux vs. Windows posts!)&lt;/h2&gt;
&lt;p&gt;I work at the &lt;a href=&quot;http://esciencecenter.nl/&quot;&gt;Netherlands eScience Center&lt;/a&gt;, a wonderful organization with very nice colleagues. Hopefully nice enough to stay my colleagues after the following confession: I am a Windows user.&lt;/p&gt;
&lt;p&gt;What’s so special about this? Most people use Windows, right?&lt;br&gt;
Well, not in my small &lt;em&gt;coding bubble&lt;/em&gt;.&lt;br&gt;
In the world I work in (use all your cliché imagination on nerds, hackers, computer scientists … but then remove those pictures of people wearing sun glasses indoors and desks full of pizza and caffeine-rich soft-drinks) coding from a Windows environment is often considered something between a no-go and a handicap. Breathing quickly, my fingers start to tremble as I write this, risking my career as a data scientist and machine learning practitioner. Or isn’t it all that bad?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2000&quot; height=&quot;1143&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_omI5G0XyVglCsQpBFmgf9A-744fa126.DLyAPxQw_Z1a64X8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-did-i-end-up-using-windows&quot;&gt;How did I end up using Windows?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(I see your shaking heads… why the hell did he end up there?)&lt;/em&gt;&lt;br&gt;
Let’s just say I have grown into it. All the way from &lt;a href=&quot;https://en.wikipedia.org/wiki/MS-DOS&quot;&gt;MS DOS&lt;/a&gt; through many painfully bad Windows versions and then I got so used to it that &lt;strong&gt;my skills to deal with it always felt better than my skills in handling the alternatives&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In addition, I am not a software developer or computer scientist by training. For a long time I was a physicist, a scientist, an academic. And in the scientific fields where I was working, using Windows was — believe it or not —the norm.&lt;/p&gt;
&lt;p&gt;Sure, I had already installed VirtualBox on my computer to run Ubuntu. I had even done some stuff with Ubuntu, including training some machine learning models (for implementations for which the packages didn’t support Windows…). I knew the 10 most common shell commands and everything else I would simply look up when needed. No wonder working with Linux still feels like writing a long letter with my left hand (I am right handed): I am terribly slow and in the end it looks horrible.&lt;/p&gt;
&lt;h3 id=&quot;but--why&quot;&gt;But … why?&lt;/h3&gt;
&lt;p&gt;Ah, I see. That all sounds like lame excuses to you.&lt;br&gt;
Well, it is not that I didn’t see all those golden merits of using Linux over Windows. Of course that’s the better system for many tasks, say setting up a server or handling access rights. And yes, it is much less wasteful in using hardware resources, it is considered less vulnerable, … and so on …, plus it is freely available without commercial interests. Still, I never wanted to pay the price of not having access to some of the high-end software that you would get on mac-OS or Windows (such as some MS office stuff or Adobe products). By the way: I am not trying to convince anybody that Windows is the best option. I am already happy if we can agree that it is &lt;em&gt;&lt;strong&gt;an&lt;/strong&gt;&lt;/em&gt; option.&lt;/p&gt;
&lt;p&gt;Time for another uncomfortable revelation: sometimes, being lazy simply pays off. For instance if you need to sort out a huge pile of stuff with some emotional value to you. Just put it in a box and hide it, take it out 10 years later and easily decide to dump nearly all of it. That’s a bit what I did with Linux. I survived with minimal use of VirtualBx and alike. Until recently, &lt;em&gt;finally!&lt;/em&gt;, Linux became part of Windows. And that works pretty well for me. &lt;a href=&quot;https://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/&quot;&gt;See how simple it now is to run Linux from Windows 10.&lt;/a&gt; And enjoy how easily you now can have the best of both worlds (not for nothing are more and more people arguing &lt;a href=&quot;https://towardsdatascience.com/dual-boot-is-dead-windows-and-linux-are-now-one-27555902a128&quot;&gt;that the good old “dual boot” is dead&lt;/a&gt; for exactly this reason).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1882&quot; height=&quot;1122&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_Ct2nr1TdVL8Qnmn5S2StDA-d5cb5a59.CpL0kF93_1djj7g.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Using Windows and Ubuntu side by side… in front of wonderful ugly-ish Windows blue… what a peaceful view, isn’t it?&lt;/p&gt;
&lt;p&gt;Enough all-united-hippie-talk. Let me share a few impressions of the actual life of an aspiring data scientist/research software engineer that happens to use Windows:&lt;/p&gt;
&lt;h3 id=&quot;starting-a-new-job&quot;&gt;Starting a new job.&lt;/h3&gt;
&lt;p&gt;I did a lot of programming as a researcher, but clearly I had never learned the proper software development basics such as testing, versioning etc. (in many academic fields those terms are often still unheard of!). No wonder I suffered a lot from imposter syndrome in the very beginning.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I hope they won’t find out I can’t write proper code!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Naturally, that means that you might not immediately ask your colleagues for help, because that would reveal your amateur level, right?&lt;br&gt;
But even worse, imagining you ask that colleague about how to get that Python package working and it turns out you are using Windows?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you help me setting up that environment? … By the way … I use Windows for that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The looks you get are suggesting that you have just asked how to import a 5GB.csv file into your Excel table (&lt;em&gt;*you don’t*&lt;/em&gt;). So little surprise I did spend a fair amount of time in Forum-Land during my first months…&lt;/p&gt;
&lt;h3 id=&quot;being-that-windows-user-in-the-room&quot;&gt;Being that Windows user in the room&lt;/h3&gt;
&lt;p&gt;You sit in that hands-on workshop on some fancy programming techniques, and the instructors asks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there anybody using Windows? (chuckles)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or, actually worse, nobody asks. Of course the instructions are only given for Linux and mac-OS. Well, at least I can hide my Windows handicap for a little longer then… but &lt;strong&gt;NO&lt;/strong&gt;!, when the instructor walks around to inspect the progress of the participants she/he will of course shout out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Wow … you are really using Windows for that!?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great. Now officially being tagged as &lt;strong&gt;the Windows user&lt;/strong&gt; in the room. Better keep quiet and not ask any silly questions then…&lt;/p&gt;
&lt;h3 id=&quot;get-used-to-rolled-eyes-then-secretly-roll-your-eyes-too&quot;&gt;Get used to rolled eyes —then secretly roll your eyes, too.&lt;/h3&gt;
&lt;p&gt;As I grew more confident of what I was doing, the imposter syndrome started to disappear. It still occasionally comes back to say hello (for instance if people speak shell over coffee), but that’s OK.&lt;/p&gt;
&lt;p&gt;In the end it’s luckily the results that matters most. I learned that you can write as good or bad code on Windows as on Linux. You can build great software on Windows that is then used by Linux people, and the other way around. Sure, for some things you better go the Linux way. But it turns out that in my projects this is less than 1% of my working time, which makes it OK to be a bit clumsy using it. And secretly (&lt;em&gt;don’t point at them, that’s mean!&lt;/em&gt;), I can also enjoy those moments when another colloquium presentation doesn’t run properly because Ubuntu did not work well with the projector, or the microphone, or both.&lt;/p&gt;
&lt;h3 id=&quot;do-better-than-pointing-at-each-other&quot;&gt;Do better than pointing at each other&lt;/h3&gt;
&lt;p&gt;Windows is more convenient for running some very common software (e.g. MS office), Linux is more stable… so go some cliches. But instead of fighting about what’s better (or hiding what feels inferior) it makes more sense to me to accept what’s there and simply go along with it. If somebody lives in a very geeky bubble it works fine to safely assume everyone runs their code on a certain operating systems and knows the in and outs of object oriented programming and containerization. But many of the more exciting projects involve people outside this bubble: researchers, users, future contributors, students. And they might as well — lo and behold — be using Windows (and by the way: containers are still primarily &lt;strong&gt;big steel boxes&lt;/strong&gt; to most people).&lt;/p&gt;
&lt;p&gt;So, even though in some IT-bubbles it can occasionally feel as if we are talking about a small unfortunate minority … in reality that’s really not true. Check out &lt;a href=&quot;https://www.freecodecamp.org/news/stack-overflow-developer-survey-2020-programming-language-framework-salary-data/&quot;&gt;the 2020 Stack Overflow Developer Survey&lt;/a&gt; to see that &lt;strong&gt;most developers actually use Windows&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-can-you-do-to-get-more-windows-users-to-adopt-your-package&quot;&gt;What can you do to get more Windows users to adopt your package?&lt;/h3&gt;
&lt;p&gt;Think of Windows what you want. I don’t work for Microsoft, and honestly, I don’t really care. But I assume that many coders out there working on great new software, methods, tools, tutorials, etc. actually want that people become happy users (paid by eternal gratitude). And that is a good enough reason to think about those Windows users as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider setting up your next continuous integration for your software package, so that it runs on all systems and will be used by more people.&lt;br&gt;
For instance with &lt;a href=&quot;https://docs.github.com/en/free-pro-team@latest/actions/guides/about-continuous-integration&quot;&gt;continuous integration using GitHub&lt;/a&gt; actions it can be as simple as adding a &lt;code&gt;‘windows-latest’&lt;/code&gt; to your matrix:&lt;br&gt;
&lt;code&gt;os: [‘ubuntu-latest’, ‘macos-latest’, ‘windows-latest’]   &lt;/code&gt; (small warning: adding different operating systems to such a continuous integration workflow is comparably easy, the later debugging sometimes is not. One option can be to work with &lt;a href=&quot;https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/&quot;&gt;Windows virtual machine&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;What about providing installation instructions for Windows users as well? Or did you just write a new tutorial? Great! But will it work for your fellow Windows users? You would be surprised how many packages and tutorials come with instructions that clearly won’t work for a Windows user.&lt;br&gt;
Don’t know how to do that? No Problem! Just ask a Windows user to help you. Believe me, they will be very glad to assist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-symmetry&quot;&gt;Final symmetry&lt;/h3&gt;
&lt;p&gt;Most of my arguments will hold when we just swap the named OS. So, obviously if you are (like me) primarily a Windows user: Think of all those Linux and mac-OS people out there. Either way, it will require learning a bit about the differences. But it will help to avoid a lot of frustration on all ends due to failing notebooks or hard to install packages.&lt;/p&gt;
&lt;h3 id=&quot;get-in-touch&quot;&gt;Get in touch&lt;/h3&gt;
&lt;p&gt;If you have comments or questions please get in touch! You can also find me on twitter: &lt;a href=&quot;https://twitter.com/me_datapoint&quot;&gt;&lt;strong&gt;me_datapoint&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_omI5G0XyVglCsQpBFmgf9A-744fa126.DLyAPxQw.png" medium="image"/><author>Florian Huber</author></item><item><title>Coalition polls for the people with Coalitiewijzer</title><link>https://blog.esciencecenter.nl/posts/2020-11-10---coalition-polls-for-the-people-with-coalitiewijzer</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-11-10---coalition-polls-for-the-people-with-coalitiewijzer</guid><description>&lt;h2 id=&quot;build-interactive-web-apps-with-polling-data-voilà--heroku&quot;&gt;Build interactive web apps with polling data, Voilà &amp;#x26; Heroku&lt;/h2&gt;
&lt;p&gt;My first attempt at actual visualization was to make another grid, but this time consisting of 150 HTML widgets, one for each seat. Then we can adjust &lt;code&gt;on_toggle&lt;/code&gt; to modify the &lt;code&gt;value&lt;/code&gt; attribute of each HTML widget, which is the character it displays. This gives us a poor man’s ASCII based seats visualization (see the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/explore_things.ipynb&quot;&gt;explore_things notebook on GitHub&lt;/a&gt; for the code). I was already pretty happy at this point…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;221&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-beb03350.DhGoA2Ue_1gIqFT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;fancy-vuetify-widgets&quot;&gt;Fancy Vuetify widgets&lt;/h3&gt;
&lt;p&gt;However, to make sure I wasn’t reinventing the wheel in the form of a square block of granite, I asked [Maarten Breddels], who is strongly involved in ipywidgets development, whether he knew of any existing options in the landscape of available widgets.&lt;/p&gt;
&lt;p&gt;He helped me set up a really fancy seats widget using &lt;a href=&quot;https://ipyvuetify.readthedocs.io/&quot;&gt;ipyvuetify&lt;/a&gt;, an alternative widget library built by [Mario Buikhuizen] on top of ipywidgets using the &lt;a href=&quot;https://vuetifyjs.com/en/&quot;&gt;Vuetify&lt;/a&gt; Javascript UI library, a Vue library.&lt;/p&gt;
&lt;p&gt;I won’t go into Vue here, because I don’t know much about it myself, except that it is a web framework like React. Apparently, though, it is not that hard to write Vue template based widgets. Vue templates have their own programming syntax with for-loops, conditionals and other useful stuff. What Maarten then came up with was something like this:&lt;/p&gt;
&lt;p&gt;from ipyvuetify import VuetifyTemplate
import traitletsclass PartyWidget(VuetifyTemplate):
rows** = traitlets.Int(10).tag(sync=True)**    cols** = traitlets.Int(15).tag(sync=True)**    low** = traitlets.Int(0).tag(sync=True)**    exp** = traitlets.Int(0).tag(sync=True)**    high** = traitlets.Int(0).tag(sync=True)**    template = traitlets.Unicode(&apos;&apos;&apos;
&amp;#x3C;template&gt;
&amp;#x3C;div&gt;
&amp;#x3C;table&gt;&amp;#x3C;tr v-for=“i in rows”&lt;strong&gt;&gt;&lt;/strong&gt;&amp;#x3C;td v-for=“j in cols”&lt;strong&gt;&gt;&lt;/strong&gt;    &amp;#x3C;div&gt;&amp;#x3C;v-icon v-if=“(j + i * cols) &amp;#x3C; low”&lt;strong&gt;&gt;mdi-seat*&amp;#x3C;/v-icon&gt;&lt;/strong&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) &amp;#x3C; exp”
style=“color: orange”&gt;&lt;strong&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&lt;/strong&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) == exp” style=“color: green”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) &amp;#x3C; high” style=“color: red”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&amp;#x3C;v-icon v-else** style=“color: pink”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;**    &amp;#x3C;/div&gt;
&amp;#x3C;/td&gt;
&amp;#x3C;/tr&gt;
&amp;#x3C;/div&gt;
&amp;#x3C;/template&gt;
&apos;&apos;&apos;).tag(sync=True)&lt;/p&gt;
&lt;p&gt;pw = PartyWidget()**Let’s break that down, looking at the bold-face parts especially. The first, Pythonic part of the class defines five &lt;code&gt;traitlets&lt;/code&gt; properties which we’re going to use to interactively change things. We use 10 rows and 15 columns here, giving a total of 150 seats. We can use the three other numbers &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; for showing the expected number of seats estimates and the lower and higher uncertainty region boundaries.&lt;/p&gt;
&lt;p&gt;Then comes the Vue magic in some kind of generative dialect of HTML. We’re going to generate a table with rows and columns using the &lt;code&gt;v-for&lt;/code&gt; attribute which automatically generates a bunch of them.&lt;/p&gt;
&lt;p&gt;Then, inside the table cells, we use a bunch of fancy seat icons, &lt;code&gt;*mdi-seat*&lt;/code&gt;, with if/else conditionals with the &lt;code&gt;v-if&lt;/code&gt; and &lt;code&gt;v-else-if&lt;/code&gt; attributes. The point here is that we want to create different looking seats to indicate the expected number of seats and the lower and upper boundaries. We can simply use CSS style attributes for this.&lt;/p&gt;
&lt;p&gt;Finally, we create an instance of the class. With that in hand, we can now put our &lt;code&gt;on_toggle&lt;/code&gt; function to better use by modifying the PartyWidget &lt;code&gt;pw&lt;/code&gt;’s values on each trigger:&lt;/p&gt;
&lt;p&gt;def on_toggle(&lt;strong&gt;toggles):&lt;/strong&gt;    pw.low  = int(numbers[list(toggles.values())].ZetelsLaag.sum())
pw.exp  = int(numbers[list(toggles.values())].Zetels.sum())
pw.high = int(numbers[list(toggles.values())].ZetelsHoog.sum())And that’s it! Now when we &lt;code&gt;display(pw)&lt;/code&gt; our fancy new widget and the button grid with &lt;code&gt;interact_out&lt;/code&gt; as before, we get something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;258&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-f8399c3a.GVXbs8L4_19Ggy0.webp&quot; srcset=&quot;&quot;&gt;
Fancy McSchmancyton!&lt;/p&gt;
&lt;p&gt;And what is even more amazing (as you can experience &lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;in the actual live app&lt;/a&gt;): the changing of CSS properties is animated! The colors smoothly change from one to the next when you click a button. The same goes for other properties like opacity and even rotation. All this comes for free with ipyvuetify (I guess with Vuetify itself as well).&lt;/p&gt;
&lt;h2 id=&quot;voilà&quot;&gt;Voilà&lt;/h2&gt;
&lt;p&gt;So, now we have a fancy interactive addition visualizer. However, it is in a notebook, which I do not want to share with my non-data scientist friends.&lt;/p&gt;
&lt;p&gt;Enter Voilà.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/voila-dashboards/voila/&quot;&gt;Voilà&lt;/a&gt; is essentially a Jupyter Notebook server, with one big difference: it &lt;em&gt;only displays the output&lt;/em&gt;** of running all the cells. Converting from a notebook to an actual app is just a matter of one command:&lt;/p&gt;
&lt;p&gt;voila your_notebook.ipynbJust like with Jupyter notebook, this starts up a server and opens a webpage in your browser showing the output of cells, including the widgets you created (if you put &lt;code&gt;display&lt;/code&gt; commands in).&lt;/p&gt;
&lt;p&gt;An active Python kernel is still running secretly in the background, though. This means you can still use the interactive functionality you setup between the widgets. You just cannot touch the code anymore. And this is exactly what we want when deploying our widgets as a user-facing interactive app.&lt;/p&gt;
&lt;p&gt;Since this Python kernel does all the magic of updating and connecting the widgets behind the scenes, unfortunately we cannot do without. I’m hoping one day there will be a static page output option, but I guess that basically requires a Python to Javascript or webassembly transpiler… &lt;a href=&quot;https://blog.esciencecenter.nl/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;Could be lots of fun&lt;/a&gt;, but we’re not there yet, I’m afraid.&lt;/p&gt;
&lt;h2 id=&quot;deploying-on-heroku&quot;&gt;Deploying on Heroku&lt;/h2&gt;
&lt;p&gt;So, if we want to put this app on the web, we need a place to host the Voilà server. If you happen to run your own server, that’s great (&lt;a href=&quot;https://voila.readthedocs.io/en/stable/deploy.html#running-voila-on-a-private-server&quot;&gt;here’s the guide on how to setup Voilà to run from there&lt;/a&gt;). If you don’t, read on (or, again, read the Voilà guide itself, which is what I did).&lt;/p&gt;
&lt;p&gt;Deploying on Heroku is a really easy way to get online apps going quickly and free of charge (with limits, of course), which makes it ideal for testing. There’s even an official &lt;a href=&quot;https://voila.readthedocs.io/en/stable/deploy.html#deployment-on-heroku&quot;&gt;guide on how to deploy a Voilà server on Heroku&lt;/a&gt;. There’s just a few catches to be aware of.&lt;/p&gt;
&lt;p&gt;First, it’s good to notice this &lt;a href=&quot;https://devcenter.heroku.com/articles/python-pip#scientific-python-users&quot;&gt;really weird piece of Heroku documentation&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-6b0211fc.BSVXvRNi_Uquy3.webp&quot; srcset=&quot;&quot;&gt;
“obscure” :DOkay, fine, I can pickle the necessary Peilingwijzer data and only use Python standard library functionality, instead of Pandas, numpy, matplotlib and some other weird and arcane packages that I’m sure nobody except me uses. I put this &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;conversion process in this script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Second, I ran into &lt;a href=&quot;https://stackoverflow.com/questions/62618948/heroku-voila-app-error-process-exited-with-status-1&quot;&gt;a weird error&lt;/a&gt;, which was already documented earlier by someone on Stack Overflow. The Heroku app, despite the straightforward setup procedure, would not immediately run. Luckily the &lt;a href=&quot;https://github.com/voila-dashboards/voila-heroku&quot;&gt;solution was found in another repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So with those things in mind, after rewriting things to make use of as little scientific Python packages as possible putting the app on Heroku was a matter of following the steps in the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;Voilà Heroku deployment guide&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devcenter.heroku.com/articles/getting-started-with-python#set-up&quot;&gt;Login using the Heroku CLI&lt;/a&gt; on your machine&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;runtime.txt&lt;/code&gt; file to your project/repo directory containing only a line with the Python runtime, which I set to &lt;code&gt;python-3.9.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;Procfile&lt;/code&gt; file to the directory containing the following line: &lt;code&gt;web: voila --port=$PORT --no-browser --enable_nbextensions=True your_notebook.ipynb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Commit these files, a requirements.txt file with Python dependencies and the notebook to a git repo, if you haven’t done so yet.&lt;/li&gt;
&lt;li&gt;Create a Heroku app and push your code to it:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;heroku create [appname]
git push heroku master&lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;And then, just like that, you are live&lt;/a&gt;! You can open the app in your browser using &lt;code&gt;heroku open&lt;/code&gt;, or just click the link. If you omit the app name in the &lt;code&gt;heroku create&lt;/code&gt; command, Heroku will randomly generate a name for you. The name can be important, since it determines your URL, which will be [appname].herokuapp.com. You can change it later on, though.&lt;/p&gt;
&lt;p&gt;Note that when you want to use a different clone of your repo to update your existing app (e.g. when coding on different machines), you have to reconnect Heroku to your app. If you would just run &lt;code&gt;heroku create&lt;/code&gt; again, it would create a new app. To connect the repo to the existing app, run&lt;/p&gt;
&lt;p&gt;heroku git:remote -a [appname]The &lt;code&gt;[appname]&lt;/code&gt; is the part of the app’s URL in front of herokuapp.com. You can also find it by running &lt;code&gt;heroku apps&lt;/code&gt; on your command line, which gives you a list of all your apps.&lt;/p&gt;
&lt;p&gt;So, if you hadn’t done so already, check out the resulting Coalitiewijzer app at &lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;https://coalitiewijzer.herokuapp.com/&lt;/a&gt; and let me know what you think!&lt;/p&gt;
&lt;p&gt;For those that don’t like discussing on Medium: &lt;a href=&quot;https://www.reddit.com/r/Python/comments/jrjegk/built_a_voila_webapp_from_jupyter_with_a_fancy/&quot;&gt;Reddit thread here&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/eScienceCenter/status/1325755219142201350&quot;&gt;Twitter here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This was my first time putting ipywidgets, Voilà and Heroku to use and I was really pleasantly surprised with how smooth all of them work. If you’re used to working in Jupyter notebooks, it’s an actual breeze to break out your exploration or visualization or other fun nugget of knowledge into something non-developers can also make good use of.&lt;/p&gt;
&lt;p&gt;It just so happens that this time I needed it to scratch a politics itch, but I can see this workflow being very useful for science communication as well. I’ll definitely be using it again. Let me know what you built with it!&lt;/p&gt;</description><pubDate>Tue, 10 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;build-interactive-web-apps-with-polling-data-voilà--heroku&quot;&gt;Build interactive web apps with polling data, Voilà &amp;#x26; Heroku&lt;/h2&gt;
&lt;p&gt;My first attempt at actual visualization was to make another grid, but this time consisting of 150 HTML widgets, one for each seat. Then we can adjust &lt;code&gt;on_toggle&lt;/code&gt; to modify the &lt;code&gt;value&lt;/code&gt; attribute of each HTML widget, which is the character it displays. This gives us a poor man’s ASCII based seats visualization (see the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/explore_things.ipynb&quot;&gt;explore_things notebook on GitHub&lt;/a&gt; for the code). I was already pretty happy at this point…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;221&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-beb03350.DhGoA2Ue_1gIqFT.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;fancy-vuetify-widgets&quot;&gt;Fancy Vuetify widgets&lt;/h3&gt;
&lt;p&gt;However, to make sure I wasn’t reinventing the wheel in the form of a square block of granite, I asked [Maarten Breddels], who is strongly involved in ipywidgets development, whether he knew of any existing options in the landscape of available widgets.&lt;/p&gt;
&lt;p&gt;He helped me set up a really fancy seats widget using &lt;a href=&quot;https://ipyvuetify.readthedocs.io/&quot;&gt;ipyvuetify&lt;/a&gt;, an alternative widget library built by [Mario Buikhuizen] on top of ipywidgets using the &lt;a href=&quot;https://vuetifyjs.com/en/&quot;&gt;Vuetify&lt;/a&gt; Javascript UI library, a Vue library.&lt;/p&gt;
&lt;p&gt;I won’t go into Vue here, because I don’t know much about it myself, except that it is a web framework like React. Apparently, though, it is not that hard to write Vue template based widgets. Vue templates have their own programming syntax with for-loops, conditionals and other useful stuff. What Maarten then came up with was something like this:&lt;/p&gt;
&lt;p&gt;from ipyvuetify import VuetifyTemplate
import traitletsclass PartyWidget(VuetifyTemplate):
rows** = traitlets.Int(10).tag(sync=True)**    cols** = traitlets.Int(15).tag(sync=True)**    low** = traitlets.Int(0).tag(sync=True)**    exp** = traitlets.Int(0).tag(sync=True)**    high** = traitlets.Int(0).tag(sync=True)**    template = traitlets.Unicode(&apos;&apos;&apos;
&amp;#x3C;template&gt;
&amp;#x3C;div&gt;
&amp;#x3C;table&gt;&amp;#x3C;tr v-for=“i in rows”&lt;strong&gt;&gt;&lt;/strong&gt;&amp;#x3C;td v-for=“j in cols”&lt;strong&gt;&gt;&lt;/strong&gt;    &amp;#x3C;div&gt;&amp;#x3C;v-icon v-if=“(j + i * cols) &amp;#x3C; low”&lt;strong&gt;&gt;mdi-seat*&amp;#x3C;/v-icon&gt;&lt;/strong&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) &amp;#x3C; exp”
style=“color: orange”&gt;&lt;strong&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&lt;/strong&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) == exp” style=“color: green”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&amp;#x3C;v-icon v-else-if=“(j + i * cols) &amp;#x3C; high” style=“color: red”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;&amp;#x3C;v-icon v-else** style=“color: pink”&gt;&lt;em&gt;mdi-seat&lt;/em&gt;&amp;#x3C;/v-icon&gt;**    &amp;#x3C;/div&gt;
&amp;#x3C;/td&gt;
&amp;#x3C;/tr&gt;
&amp;#x3C;/div&gt;
&amp;#x3C;/template&gt;
&apos;&apos;&apos;).tag(sync=True)&lt;/p&gt;
&lt;p&gt;pw = PartyWidget()**Let’s break that down, looking at the bold-face parts especially. The first, Pythonic part of the class defines five &lt;code&gt;traitlets&lt;/code&gt; properties which we’re going to use to interactively change things. We use 10 rows and 15 columns here, giving a total of 150 seats. We can use the three other numbers &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; for showing the expected number of seats estimates and the lower and higher uncertainty region boundaries.&lt;/p&gt;
&lt;p&gt;Then comes the Vue magic in some kind of generative dialect of HTML. We’re going to generate a table with rows and columns using the &lt;code&gt;v-for&lt;/code&gt; attribute which automatically generates a bunch of them.&lt;/p&gt;
&lt;p&gt;Then, inside the table cells, we use a bunch of fancy seat icons, &lt;code&gt;*mdi-seat*&lt;/code&gt;, with if/else conditionals with the &lt;code&gt;v-if&lt;/code&gt; and &lt;code&gt;v-else-if&lt;/code&gt; attributes. The point here is that we want to create different looking seats to indicate the expected number of seats and the lower and upper boundaries. We can simply use CSS style attributes for this.&lt;/p&gt;
&lt;p&gt;Finally, we create an instance of the class. With that in hand, we can now put our &lt;code&gt;on_toggle&lt;/code&gt; function to better use by modifying the PartyWidget &lt;code&gt;pw&lt;/code&gt;’s values on each trigger:&lt;/p&gt;
&lt;p&gt;def on_toggle(&lt;strong&gt;toggles):&lt;/strong&gt;    pw.low  = int(numbers[list(toggles.values())].ZetelsLaag.sum())
pw.exp  = int(numbers[list(toggles.values())].Zetels.sum())
pw.high = int(numbers[list(toggles.values())].ZetelsHoog.sum())And that’s it! Now when we &lt;code&gt;display(pw)&lt;/code&gt; our fancy new widget and the button grid with &lt;code&gt;interact_out&lt;/code&gt; as before, we get something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;258&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-f8399c3a.GVXbs8L4_19Ggy0.webp&quot; srcset=&quot;&quot;&gt;
Fancy McSchmancyton!&lt;/p&gt;
&lt;p&gt;And what is even more amazing (as you can experience &lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;in the actual live app&lt;/a&gt;): the changing of CSS properties is animated! The colors smoothly change from one to the next when you click a button. The same goes for other properties like opacity and even rotation. All this comes for free with ipyvuetify (I guess with Vuetify itself as well).&lt;/p&gt;
&lt;h2 id=&quot;voilà&quot;&gt;Voilà&lt;/h2&gt;
&lt;p&gt;So, now we have a fancy interactive addition visualizer. However, it is in a notebook, which I do not want to share with my non-data scientist friends.&lt;/p&gt;
&lt;p&gt;Enter Voilà.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/voila-dashboards/voila/&quot;&gt;Voilà&lt;/a&gt; is essentially a Jupyter Notebook server, with one big difference: it &lt;em&gt;only displays the output&lt;/em&gt;** of running all the cells. Converting from a notebook to an actual app is just a matter of one command:&lt;/p&gt;
&lt;p&gt;voila your_notebook.ipynbJust like with Jupyter notebook, this starts up a server and opens a webpage in your browser showing the output of cells, including the widgets you created (if you put &lt;code&gt;display&lt;/code&gt; commands in).&lt;/p&gt;
&lt;p&gt;An active Python kernel is still running secretly in the background, though. This means you can still use the interactive functionality you setup between the widgets. You just cannot touch the code anymore. And this is exactly what we want when deploying our widgets as a user-facing interactive app.&lt;/p&gt;
&lt;p&gt;Since this Python kernel does all the magic of updating and connecting the widgets behind the scenes, unfortunately we cannot do without. I’m hoping one day there will be a static page output option, but I guess that basically requires a Python to Javascript or webassembly transpiler… &lt;a href=&quot;https://blog.esciencecenter.nl/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;Could be lots of fun&lt;/a&gt;, but we’re not there yet, I’m afraid.&lt;/p&gt;
&lt;h2 id=&quot;deploying-on-heroku&quot;&gt;Deploying on Heroku&lt;/h2&gt;
&lt;p&gt;So, if we want to put this app on the web, we need a place to host the Voilà server. If you happen to run your own server, that’s great (&lt;a href=&quot;https://voila.readthedocs.io/en/stable/deploy.html#running-voila-on-a-private-server&quot;&gt;here’s the guide on how to setup Voilà to run from there&lt;/a&gt;). If you don’t, read on (or, again, read the Voilà guide itself, which is what I did).&lt;/p&gt;
&lt;p&gt;Deploying on Heroku is a really easy way to get online apps going quickly and free of charge (with limits, of course), which makes it ideal for testing. There’s even an official &lt;a href=&quot;https://voila.readthedocs.io/en/stable/deploy.html#deployment-on-heroku&quot;&gt;guide on how to deploy a Voilà server on Heroku&lt;/a&gt;. There’s just a few catches to be aware of.&lt;/p&gt;
&lt;p&gt;First, it’s good to notice this &lt;a href=&quot;https://devcenter.heroku.com/articles/python-pip#scientific-python-users&quot;&gt;really weird piece of Heroku documentation&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Coalition polls for the people with Coalitiewijzer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;700&quot; height=&quot;120&quot; src=&quot;https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-6b0211fc.BSVXvRNi_Uquy3.webp&quot; srcset=&quot;&quot;&gt;
“obscure” :DOkay, fine, I can pickle the necessary Peilingwijzer data and only use Python standard library functionality, instead of Pandas, numpy, matplotlib and some other weird and arcane packages that I’m sure nobody except me uses. I put this &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;conversion process in this script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Second, I ran into &lt;a href=&quot;https://stackoverflow.com/questions/62618948/heroku-voila-app-error-process-exited-with-status-1&quot;&gt;a weird error&lt;/a&gt;, which was already documented earlier by someone on Stack Overflow. The Heroku app, despite the straightforward setup procedure, would not immediately run. Luckily the &lt;a href=&quot;https://github.com/voila-dashboards/voila-heroku&quot;&gt;solution was found in another repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So with those things in mind, after rewriting things to make use of as little scientific Python packages as possible putting the app on Heroku was a matter of following the steps in the &lt;a href=&quot;https://github.com/egpbos/coalitiewijzer/blob/main/update_numbers.py&quot;&gt;Voilà Heroku deployment guide&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devcenter.heroku.com/articles/getting-started-with-python#set-up&quot;&gt;Login using the Heroku CLI&lt;/a&gt; on your machine&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;runtime.txt&lt;/code&gt; file to your project/repo directory containing only a line with the Python runtime, which I set to &lt;code&gt;python-3.9.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;Procfile&lt;/code&gt; file to the directory containing the following line: &lt;code&gt;web: voila --port=$PORT --no-browser --enable_nbextensions=True your_notebook.ipynb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Commit these files, a requirements.txt file with Python dependencies and the notebook to a git repo, if you haven’t done so yet.&lt;/li&gt;
&lt;li&gt;Create a Heroku app and push your code to it:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;heroku create [appname]
git push heroku master&lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;And then, just like that, you are live&lt;/a&gt;! You can open the app in your browser using &lt;code&gt;heroku open&lt;/code&gt;, or just click the link. If you omit the app name in the &lt;code&gt;heroku create&lt;/code&gt; command, Heroku will randomly generate a name for you. The name can be important, since it determines your URL, which will be [appname].herokuapp.com. You can change it later on, though.&lt;/p&gt;
&lt;p&gt;Note that when you want to use a different clone of your repo to update your existing app (e.g. when coding on different machines), you have to reconnect Heroku to your app. If you would just run &lt;code&gt;heroku create&lt;/code&gt; again, it would create a new app. To connect the repo to the existing app, run&lt;/p&gt;
&lt;p&gt;heroku git:remote -a [appname]The &lt;code&gt;[appname]&lt;/code&gt; is the part of the app’s URL in front of herokuapp.com. You can also find it by running &lt;code&gt;heroku apps&lt;/code&gt; on your command line, which gives you a list of all your apps.&lt;/p&gt;
&lt;p&gt;So, if you hadn’t done so already, check out the resulting Coalitiewijzer app at &lt;a href=&quot;https://coalitiewijzer.herokuapp.com/&quot;&gt;https://coalitiewijzer.herokuapp.com/&lt;/a&gt; and let me know what you think!&lt;/p&gt;
&lt;p&gt;For those that don’t like discussing on Medium: &lt;a href=&quot;https://www.reddit.com/r/Python/comments/jrjegk/built_a_voila_webapp_from_jupyter_with_a_fancy/&quot;&gt;Reddit thread here&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/eScienceCenter/status/1325755219142201350&quot;&gt;Twitter here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This was my first time putting ipywidgets, Voilà and Heroku to use and I was really pleasantly surprised with how smooth all of them work. If you’re used to working in Jupyter notebooks, it’s an actual breeze to break out your exploration or visualization or other fun nugget of knowledge into something non-developers can also make good use of.&lt;/p&gt;
&lt;p&gt;It just so happens that this time I needed it to scratch a politics itch, but I can see this workflow being very useful for science communication as well. I’ll definitely be using it again. Let me know what you built with it!&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/coalition-polls-for-the-people-with-coal-beb03350.DhGoA2Ue.png" medium="image"/><author>Patrick Bos</author></item><item><title>C++ web app with WebAssembly, Vega, Web Worker and React</title><link>https://blog.esciencecenter.nl/posts/2020-10-27---c-web-app-with-webassembly-vega-web-worker-and-react</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-27---c-web-app-with-webassembly-vega-web-worker-and-react</guid><description>&lt;p&gt;To generate the Vega-Lite specification we can write a function like so&lt;/p&gt;
&lt;p&gt;To wrap the Vega-Lite visualization in React component we will use &lt;code&gt;useRef&lt;/code&gt; to get a DOM element as container and use &lt;code&gt;useEffect&lt;/code&gt; to call vegaEmbed when the iterations or container changes. The React component to render the visualization is&lt;/p&gt;
&lt;h2 id=&quot;pack-it-up&quot;&gt;Pack it up&lt;/h2&gt;
&lt;p&gt;The React components and React render call can be packed up all together in a JavaScript file called &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/kitchen-sink/app.js&quot;&gt;app.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The web applications needs a HTML page to fetch all the React and Vega dependencies, define a HTML tag for rendering the React app to and finally include the application JavaScript file.&lt;/p&gt;
&lt;p&gt;File: app.html*&lt;/p&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the http.server module from Python 3 to host all files on port 8000, like so:&lt;/p&gt;
&lt;p&gt;python3 -m http.server 8000Visiting the page at &lt;a href=&quot;http://localhost:8000/app.html&quot;&gt;http://localhost:8000/app.html&lt;/a&gt; should give us a plot like&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html)(Click&quot;&gt;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html)(Click&lt;/a&gt; on image to get interactive version)You can try out different initial guesses to get different amount of iterations. For example having initial guess located in a local minimum like &lt;code&gt;2&lt;/code&gt; will make the algorithm use many iterations to jump over the minimum.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;p&gt;In this series of blog posts we introduced a lot of different technologies to able to take an algorithm written in C++ and make a interactive web application that will run fully in a web browser.&lt;/p&gt;
&lt;p&gt;All the source code shown is available at &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web&quot;&gt;https://github.com/NLESC-JCER/run-cpp-on-web&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed this series of blogs and if you have suggestions or questions please post a comment below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogere written as part of the “Passing XSAMS” project. To learn more about the project, check out its &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Tue, 27 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To generate the Vega-Lite specification we can write a function like so&lt;/p&gt;
&lt;p&gt;To wrap the Vega-Lite visualization in React component we will use &lt;code&gt;useRef&lt;/code&gt; to get a DOM element as container and use &lt;code&gt;useEffect&lt;/code&gt; to call vegaEmbed when the iterations or container changes. The React component to render the visualization is&lt;/p&gt;
&lt;h2 id=&quot;pack-it-up&quot;&gt;Pack it up&lt;/h2&gt;
&lt;p&gt;The React components and React render call can be packed up all together in a JavaScript file called &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/kitchen-sink/app.js&quot;&gt;app.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The web applications needs a HTML page to fetch all the React and Vega dependencies, define a HTML tag for rendering the React app to and finally include the application JavaScript file.&lt;/p&gt;
&lt;p&gt;File: app.html*&lt;/p&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the http.server module from Python 3 to host all files on port 8000, like so:&lt;/p&gt;
&lt;p&gt;python3 -m http.server 8000Visiting the page at &lt;a href=&quot;http://localhost:8000/app.html&quot;&gt;http://localhost:8000/app.html&lt;/a&gt; should give us a plot like&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html)(Click&quot;&gt;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html)(Click&lt;/a&gt; on image to get interactive version)You can try out different initial guesses to get different amount of iterations. For example having initial guess located in a local minimum like &lt;code&gt;2&lt;/code&gt; will make the algorithm use many iterations to jump over the minimum.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;p&gt;In this series of blog posts we introduced a lot of different technologies to able to take an algorithm written in C++ and make a interactive web application that will run fully in a web browser.&lt;/p&gt;
&lt;p&gt;All the source code shown is available at &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web&quot;&gt;https://github.com/NLESC-JCER/run-cpp-on-web&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed this series of blogs and if you have suggestions or questions please post a comment below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogere written as part of the “Passing XSAMS” project. To learn more about the project, check out its &lt;em&gt;&lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><author>eScience Editorial Team</author></item><item><title>How is the end of daylight saving time going to affect me?</title><link>https://blog.esciencecenter.nl/posts/2020-10-22---how-is-the-end-of-daylight-saving-time-going-to-affect-me</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-22---how-is-the-end-of-daylight-saving-time-going-to-affect-me</guid><description>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;3200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VGVs2sUcNP-lFLjO-c4642dd2.CzbvTntQ_6Pfi1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by insung yoon on Unsplash&lt;/p&gt;
&lt;p&gt;It happens every year. Twice. And it can be pretty annoying. I am talking about the clock shift to re-adapt our schedules to wintertime or summertime. But did you know that this October 25 may be the last time this happens? Well… at least if you are reading these lines from Europe.&lt;/p&gt;
&lt;h2 id=&quot;farewell-to-the-two-clocks&quot;&gt;Farewell to the (two) clocks&lt;/h2&gt;
&lt;p&gt;The European Parliament &lt;a href=&quot;https://oeil.secure.europarl.europa.eu/oeil/popups/ficheprocedure.do?lang=en&amp;#x26;reference=2018%2F0332%28COD%29&quot;&gt;decided to stop&lt;/a&gt; the practice of &lt;em&gt;“spring forward, fall back”&lt;/em&gt;. This decision has been backed by a &lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX%3A52018SC0406&amp;#x26;from=EN&quot;&gt;public consultation&lt;/a&gt; to 4.6 million Europeans, 84% of them were in favor of stopping the biyearly clock readjustment.&lt;/p&gt;
&lt;p&gt;The reasons to abandon the traditional clock readjustment are manifold. Most of us agree with the most obvious of all: it causes a couple of days of annoyance to get used to the new timetable. There is, additionally, some controversy about &lt;a href=&quot;https://doi.org/10.5547%2F01956574.39.2.thav&quot;&gt;how much energy is saved&lt;/a&gt;, plus some evidence about an &lt;a href=&quot;https://doi.org/10.1016/S1389-9457(00)00032-0&quot;&gt;increase in car crashes&lt;/a&gt; in the days after a clock change.&lt;/p&gt;
&lt;p&gt;The members of the European Union have been asked to choose between winter and summertime clocks, and stick to their choice during the whole year. The deadline for this decision is April 2021… and sticking permanently to one of these clocks is not an easy choice.&lt;/p&gt;
&lt;p&gt;From a sociopolitical point of view, one of the obvious concerns is the possibility of causing a de-synchronization between countries that currently share the same clock. It would not be very convenient, for instance, to use different timezones in The Netherlands and Belgium. Efficient coordination between the EU members will certainly require communication and diplomacy.&lt;/p&gt;
&lt;p&gt;But there is an even deeper problem. Changing the clocks reduces the undesirable effects of an astronomical phenomenon: that of the variability of sunlight hours during the year. To make it even more difficult, this variability depends not only on the day of the year but also on the location on Earth.&lt;/p&gt;
&lt;p&gt;Luckily, the study of the relationship between daylight duration, position, and date is one of the oldest objects of study. There are some early references in the Babylonian time, the topic was already covered in Ptolemy’s &lt;em&gt;Almagest&lt;/em&gt;, and it is part of the everyday life of sailors since, at least, the publication of the first nautical almanacs in the 1700s. Nowadays, all the knowledge we need is just a few clicks away.&lt;/p&gt;
&lt;h2 id=&quot;daylight-charts-and-how-to-read-them&quot;&gt;Daylight charts and how to read them&lt;/h2&gt;
&lt;p&gt;The easiest way to visualize this kind of information is by using a daylight chart. They look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1075&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3FqjKUwigVDSvM02muy99A-75be3bb6.D2_OnLzj_GHNuO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight chart corresponding to the city of Barcelona, Spain, in the year 2020. The abrupt changes correspond with the spring and autumn clock shifts. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nowadays, quick and simple access to astronomical databases makes it easier than ever to simulate daylight charts at any point in the world. In particular, I wrote &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;this code&lt;/a&gt; in R to generate such diagrams. It can be run as an interactive applet, either in &lt;a href=&quot;https://pabrod.shinyapps.io/cambio-de-hora/&quot;&gt;Shinyapps&lt;/a&gt; or &lt;a href=&quot;https://github.com/PabRod/daylight-charts/readme.md&quot;&gt;locally&lt;/a&gt;, to query for any city in the EU with a population over 100k. Additionally, I precalculated a collection of daylight charts for &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/nl&quot;&gt;Dutch&lt;/a&gt;, &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/es&quot;&gt;Spanish&lt;/a&gt;, and other &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/eu&quot;&gt;European&lt;/a&gt; towns with a population over 100k.&lt;/p&gt;
&lt;p&gt;By playing with these diagrams we can learn some lessons about the reasons for using two clocks, and we can also simulate possible new scenarios. For instance, we can compare the daylight charts of Barcelona with clock shift and with permanent summer clock:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;537&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LbW2hvwtIHIok0urCki4YA-407cbda5.Bb_z53MR_Z17Fn9y.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight charts of Barcelona with clock shift (left) and permanent summer clock (right). Note how the clock shift keeps the sunrise centered around 7:30. With permanent summer time, the sunrise in winter will happen after 9:00. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The three possible scenarios can be visualized in a more compact way using a single chart with different colors:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;900&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EY-C9YiELqJfFlfS8yGy9g-0946c5b1.B9uipH_f_q7EEh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In yellow, sunlight hours with clock shift (current situation). In blue, sunrise and sunset times using winter clock. In red, the same with summer clock. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Just for fun, we can explore the effect of latitude (the position in the South-North line) by, for instance, comparing two of the southernmost and northernmost big towns in the EU:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_fcHq8E9C2451Ql8LLT7WHw-4704b303.BrbW-l-d_ZXrYK6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Comparison of daylight charts in Santa Cruz de Tenerife, Canary Islands (28º N) and Stockholm, Sweden (59ºN). We notice that the further from the equator, the more irregular the sunlight is throughout the year. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Longitude, that is, the position in the direction West-East, also plays a role. This is the direction of the Earth’s rotation and, thus, we can imagine the sunrise “traveling” through it. Indeed, this the reason we have different timezones.&lt;/p&gt;
&lt;p&gt;Timezones are decided not only due to astronomical considerations but also due to commercial and political ones. Lots of them are actually wider than the distance the sun covers in one hour, and this causes interesting effects.&lt;/p&gt;
&lt;p&gt;Take a look at the map below. It shows the night advancing over Europe the day of the September equinox, together with the European timezones. Do you see something strange?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;582&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pj09DF2WUG0x0Y_fUg6DmA-44f8ef1f.C7NfSdKp_1CwW6G.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Line of sunset advancing over Europe on a day in mid-September. The different colors represent different timezones. Note that, particularly, the Central European Timezone (in dark green) is much wider than the distance the sunset covers in one hour. Source: &lt;a href=&quot;https://naukas.com/2013/10/15/espana-esta-que-se-sale-el-meridiano-y-la-hora-oficial/&quot;&gt;https://naukas.com/2013/10/15/espana-esta-que-se-sale-el-meridiano-y-la-hora-oficial/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Central European Timezone, for instance, is huge. The sun takes more than two hours to cover it. And remember, for all the people who live there, the clock shows the same time.&lt;/p&gt;
&lt;p&gt;Let’s imagine two Europeans, Mateusz and Breixo. Mateusz lives in Lublin, in the East of Poland, and Breixo lives in Tuy, in Northwestern Spain. They both leave the office where they work, simultaneously, when the clock reads 18:00, but their experience is very different. For Mateusz, 18:00 is almost night, while for Breixo it will still be clear daylight for two more hours. Something similar will happen with the sunrise: it will happen roughly two hours earlier for Mateusz than for Breixo. And all of this happens although their clocks are synchronized (actually, it happens &lt;strong&gt;because&lt;/strong&gt; their clocks are synchronized).&lt;/p&gt;
&lt;p&gt;Interestingly enough, Vânia, who lives in the Portuguese town of Valença do Minho, only one kilometer away from Breixo, is in a different timezone. So her clock will read one hour less than that of her neighbor Breixo when the night arrives, simultaneously, at both towns. Pretty confusing, right?&lt;/p&gt;
&lt;p&gt;We can see also these effects on our diagrams. In the one below we see an example with two of the most occidental/oriental cities in the CET timezone:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_XmJMmrLlobteENfTgOqwog-4c0105d3.BHh7Z0Ec_10IS2b.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight chart for A Coruña, Spain, and Split, Croatia. Both cities lie at the same approximate latitude (43ºN), but are separated by 2000 km in the West-East direction. As a consequence, all astronomical events, including sunrise, happen in Split roughly 2 hours earlier than in A Coruña, although they lay in the same timezone (CET). Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A well-informed decision is a good decision. The socioeconomic aspects of this problem are pretty difficult to predict, but the astronomical ones, on the contrary, are almost as predictable as the movement of a clock. Whenever we can, let’s base our decisions on data.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The final version of this short essay was greatly improved by the suggestions and comments of Zeger van der Sterre, &lt;a href=&quot;https://medium.com/@lourensveen&quot;&gt;Lourens Veen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@egpbos&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@s.georgievska&quot;&gt;Sonja Georgievska&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@maartenvm&quot;&gt;Maarten van Meersbergen&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 22 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;4800&quot; height=&quot;3200&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_VGVs2sUcNP-lFLjO-c4642dd2.CzbvTntQ_6Pfi1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by insung yoon on Unsplash&lt;/p&gt;
&lt;p&gt;It happens every year. Twice. And it can be pretty annoying. I am talking about the clock shift to re-adapt our schedules to wintertime or summertime. But did you know that this October 25 may be the last time this happens? Well… at least if you are reading these lines from Europe.&lt;/p&gt;
&lt;h2 id=&quot;farewell-to-the-two-clocks&quot;&gt;Farewell to the (two) clocks&lt;/h2&gt;
&lt;p&gt;The European Parliament &lt;a href=&quot;https://oeil.secure.europarl.europa.eu/oeil/popups/ficheprocedure.do?lang=en&amp;#x26;reference=2018%2F0332%28COD%29&quot;&gt;decided to stop&lt;/a&gt; the practice of &lt;em&gt;“spring forward, fall back”&lt;/em&gt;. This decision has been backed by a &lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX%3A52018SC0406&amp;#x26;from=EN&quot;&gt;public consultation&lt;/a&gt; to 4.6 million Europeans, 84% of them were in favor of stopping the biyearly clock readjustment.&lt;/p&gt;
&lt;p&gt;The reasons to abandon the traditional clock readjustment are manifold. Most of us agree with the most obvious of all: it causes a couple of days of annoyance to get used to the new timetable. There is, additionally, some controversy about &lt;a href=&quot;https://doi.org/10.5547%2F01956574.39.2.thav&quot;&gt;how much energy is saved&lt;/a&gt;, plus some evidence about an &lt;a href=&quot;https://doi.org/10.1016/S1389-9457(00)00032-0&quot;&gt;increase in car crashes&lt;/a&gt; in the days after a clock change.&lt;/p&gt;
&lt;p&gt;The members of the European Union have been asked to choose between winter and summertime clocks, and stick to their choice during the whole year. The deadline for this decision is April 2021… and sticking permanently to one of these clocks is not an easy choice.&lt;/p&gt;
&lt;p&gt;From a sociopolitical point of view, one of the obvious concerns is the possibility of causing a de-synchronization between countries that currently share the same clock. It would not be very convenient, for instance, to use different timezones in The Netherlands and Belgium. Efficient coordination between the EU members will certainly require communication and diplomacy.&lt;/p&gt;
&lt;p&gt;But there is an even deeper problem. Changing the clocks reduces the undesirable effects of an astronomical phenomenon: that of the variability of sunlight hours during the year. To make it even more difficult, this variability depends not only on the day of the year but also on the location on Earth.&lt;/p&gt;
&lt;p&gt;Luckily, the study of the relationship between daylight duration, position, and date is one of the oldest objects of study. There are some early references in the Babylonian time, the topic was already covered in Ptolemy’s &lt;em&gt;Almagest&lt;/em&gt;, and it is part of the everyday life of sailors since, at least, the publication of the first nautical almanacs in the 1700s. Nowadays, all the knowledge we need is just a few clicks away.&lt;/p&gt;
&lt;h2 id=&quot;daylight-charts-and-how-to-read-them&quot;&gt;Daylight charts and how to read them&lt;/h2&gt;
&lt;p&gt;The easiest way to visualize this kind of information is by using a daylight chart. They look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1075&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_3FqjKUwigVDSvM02muy99A-75be3bb6.D2_OnLzj_GHNuO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight chart corresponding to the city of Barcelona, Spain, in the year 2020. The abrupt changes correspond with the spring and autumn clock shifts. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nowadays, quick and simple access to astronomical databases makes it easier than ever to simulate daylight charts at any point in the world. In particular, I wrote &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;this code&lt;/a&gt; in R to generate such diagrams. It can be run as an interactive applet, either in &lt;a href=&quot;https://pabrod.shinyapps.io/cambio-de-hora/&quot;&gt;Shinyapps&lt;/a&gt; or &lt;a href=&quot;https://github.com/PabRod/daylight-charts/readme.md&quot;&gt;locally&lt;/a&gt;, to query for any city in the EU with a population over 100k. Additionally, I precalculated a collection of daylight charts for &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/nl&quot;&gt;Dutch&lt;/a&gt;, &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/es&quot;&gt;Spanish&lt;/a&gt;, and other &lt;a href=&quot;https://github.com/PabRod/daylight-charts/tree/master/figs/eu&quot;&gt;European&lt;/a&gt; towns with a population over 100k.&lt;/p&gt;
&lt;p&gt;By playing with these diagrams we can learn some lessons about the reasons for using two clocks, and we can also simulate possible new scenarios. For instance, we can compare the daylight charts of Barcelona with clock shift and with permanent summer clock:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;537&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_LbW2hvwtIHIok0urCki4YA-407cbda5.Bb_z53MR_Z17Fn9y.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight charts of Barcelona with clock shift (left) and permanent summer clock (right). Note how the clock shift keeps the sunrise centered around 7:30. With permanent summer time, the sunrise in winter will happen after 9:00. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The three possible scenarios can be visualized in a more compact way using a single chart with different colors:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;900&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_EY-C9YiELqJfFlfS8yGy9g-0946c5b1.B9uipH_f_q7EEh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In yellow, sunlight hours with clock shift (current situation). In blue, sunrise and sunset times using winter clock. In red, the same with summer clock. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Just for fun, we can explore the effect of latitude (the position in the South-North line) by, for instance, comparing two of the southernmost and northernmost big towns in the EU:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_fcHq8E9C2451Ql8LLT7WHw-4704b303.BrbW-l-d_ZXrYK6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Comparison of daylight charts in Santa Cruz de Tenerife, Canary Islands (28º N) and Stockholm, Sweden (59ºN). We notice that the further from the equator, the more irregular the sunlight is throughout the year. Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Longitude, that is, the position in the direction West-East, also plays a role. This is the direction of the Earth’s rotation and, thus, we can imagine the sunrise “traveling” through it. Indeed, this the reason we have different timezones.&lt;/p&gt;
&lt;p&gt;Timezones are decided not only due to astronomical considerations but also due to commercial and political ones. Lots of them are actually wider than the distance the sun covers in one hour, and this causes interesting effects.&lt;/p&gt;
&lt;p&gt;Take a look at the map below. It shows the night advancing over Europe the day of the September equinox, together with the European timezones. Do you see something strange?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;582&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_pj09DF2WUG0x0Y_fUg6DmA-44f8ef1f.C7NfSdKp_1CwW6G.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Line of sunset advancing over Europe on a day in mid-September. The different colors represent different timezones. Note that, particularly, the Central European Timezone (in dark green) is much wider than the distance the sunset covers in one hour. Source: &lt;a href=&quot;https://naukas.com/2013/10/15/espana-esta-que-se-sale-el-meridiano-y-la-hora-oficial/&quot;&gt;https://naukas.com/2013/10/15/espana-esta-que-se-sale-el-meridiano-y-la-hora-oficial/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Central European Timezone, for instance, is huge. The sun takes more than two hours to cover it. And remember, for all the people who live there, the clock shows the same time.&lt;/p&gt;
&lt;p&gt;Let’s imagine two Europeans, Mateusz and Breixo. Mateusz lives in Lublin, in the East of Poland, and Breixo lives in Tuy, in Northwestern Spain. They both leave the office where they work, simultaneously, when the clock reads 18:00, but their experience is very different. For Mateusz, 18:00 is almost night, while for Breixo it will still be clear daylight for two more hours. Something similar will happen with the sunrise: it will happen roughly two hours earlier for Mateusz than for Breixo. And all of this happens although their clocks are synchronized (actually, it happens &lt;strong&gt;because&lt;/strong&gt; their clocks are synchronized).&lt;/p&gt;
&lt;p&gt;Interestingly enough, Vânia, who lives in the Portuguese town of Valença do Minho, only one kilometer away from Breixo, is in a different timezone. So her clock will read one hour less than that of her neighbor Breixo when the night arrives, simultaneously, at both towns. Pretty confusing, right?&lt;/p&gt;
&lt;p&gt;We can see also these effects on our diagrams. In the one below we see an example with two of the most occidental/oriental cities in the CET timezone:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;525&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_XmJMmrLlobteENfTgOqwog-4c0105d3.BHh7Z0Ec_10IS2b.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Daylight chart for A Coruña, Spain, and Split, Croatia. Both cities lie at the same approximate latitude (43ºN), but are separated by 2000 km in the West-East direction. As a consequence, all astronomical events, including sunrise, happen in Split roughly 2 hours earlier than in A Coruña, although they lay in the same timezone (CET). Source: &lt;a href=&quot;https://github.com/PabRod/daylight-charts&quot;&gt;https://github.com/PabRod/daylight-charts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A well-informed decision is a good decision. The socioeconomic aspects of this problem are pretty difficult to predict, but the astronomical ones, on the contrary, are almost as predictable as the movement of a clock. Whenever we can, let’s base our decisions on data.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The final version of this short essay was greatly improved by the suggestions and comments of Zeger van der Sterre, &lt;a href=&quot;https://medium.com/@lourensveen&quot;&gt;Lourens Veen&lt;/a&gt;, &lt;a href=&quot;https://www.esciencecenter.nl/team/stefan-verhoeven-bsc/&quot;&gt;Stefan Verhoeven&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@egpbos&quot;&gt;Patrick Bos&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@s.georgievska&quot;&gt;Sonja Georgievska&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@maartenvm&quot;&gt;Maarten van Meersbergen&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_3FqjKUwigVDSvM02muy99A-75be3bb6.D2_OnLzj.png" medium="image"/><author>Pablo Rodríguez-Sánchez</author></item><item><title>Help! My C++ web app is not responding</title><link>https://blog.esciencecenter.nl/posts/2020-10-09---help-my-c-web-app-is-not-responding</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-09---help-my-c-web-app-is-not-responding</guid><description>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In an &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;earlier blogpost&lt;/a&gt; we discussed how to run C++ code on the web using JavaScript. We created a web app that executed some C++ code and then showed the result in the browser. While the page was running the C++ code, the page was blocked and unresponsive. This was not noticeable, because the computation done in the code was very quick. An unresponsive User Interface (UI) becomes a problem when we are performing tasks that take a bit longer to run.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How to prevent blocking when running long running tasks in C++?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this blog post, we will use web workers to solve this problem by offloading tasks to another thread.&lt;/p&gt;
&lt;h2 id=&quot;long-running-tasks-with-web-worker&quot;&gt;Long-running tasks with web worker&lt;/h2&gt;
&lt;p&gt;Let’s have a look at the code we ended up with in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;first blog&lt;/a&gt; of the series. When loading the page, the WebAssembly code is executed, after which the page can finish rendering. Because the WebAssembly code was very quick, this was fine. For the current blog, we assume we have a longer running task. We create such a task artificially, by adding a few seconds of &lt;code&gt;sleep&lt;/code&gt; in the &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/web-worker/newtonraphson.cpp&quot;&gt;C++ code&lt;/a&gt;. Like in the first post of the series, we compile the C++ code to create WebAssembly code. The example page with our slow task can be found &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/web-worker/example-blocking.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notice that we also added a slider to the page. This slider simply serves to illustrate UI unresponsiveness — it has no attached function. Notice that while the WebAssembly code is still running, the slider is completely blocked. If this was an actual web app and not just a demo, the blocked UI would surely annoy users and possibly make working with the app cumbersome and impractical. We can easily solve this, and keep the UI responsive at all times, using web workers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;509&quot; height=&quot;163&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_GFkQlI6sOZUxjhbEE8U5UQ-0fc27ea2.C073jd4K_1jywBO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Blocked UI while code is running.&lt;/p&gt;
&lt;h2 id=&quot;web-workers&quot;&gt;Web workers&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API&quot;&gt;web worker&lt;/a&gt; is an object that handles execution of a piece of code in another thread.&lt;/p&gt;
&lt;p&gt;The way the page communicates with the worker object is through sending messages. The page will send a message to the worker to start doing work, and the message will include all data that the worker needs. The worker then starts executing the task, using only the data that was in the message. When finished, the worker needs to communicate the results back to the web app. It will do this by sending a message, so the web app knows when to update.&lt;/p&gt;
&lt;h2 id=&quot;the-resulting-page&quot;&gt;The resulting page&lt;/h2&gt;
&lt;p&gt;The code snippet below shows the web page that uses a web worker. Notice the creation of the &lt;code&gt;Worker&lt;/code&gt; object, posting of the message, as well as the instructions for handling of any returned messages containing results.&lt;/p&gt;
&lt;p&gt;The web worker code only contains handling of the incoming message. The web worker unpacks the message, does the root finding calculation, and packs the results in a new message that it will send back.&lt;/p&gt;
&lt;p&gt;The code for the worker in &lt;code&gt;worker.js&lt;/code&gt; is:&lt;/p&gt;
&lt;p&gt;The figure below illustrates what is happening in parallel in the two threads.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;666&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1__Knkh9aTq85_WNvyZjRPlQ-ad4c9f5c.CBM67MGz_Z1tSPLi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can see the code in action &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/web-worker/example-web-worker.html&quot;&gt;here&lt;/a&gt;. The calculation still takes the same time to perform, but as you will notice, the slider remains responsive.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;508&quot; height=&quot;158&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_efp-XCZJWs0yNveDPrq38w-bdc1dd9c.BcldFPYW_Z12E1tA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Responsive UI thanks to offloading the root finding procedure to the web worker.&lt;/p&gt;
&lt;h2 id=&quot;recap-and-what-next&quot;&gt;Recap and what next?&lt;/h2&gt;
&lt;p&gt;In this blog post, we learned how to keep a web app from freezing while executing computationally intensive C++ code. We learned how to create a web worker and how to use the web worker in a simple web app.&lt;/p&gt;
&lt;p&gt;Now you can take this web app a step further by reading some of the other blogs in this series, for example &lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;how to interact with your app using forms&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;how to spice up your app up with visualizations&lt;/a&gt;. A final blog shows you &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;how to combine all of the above in a single web app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looking for the first blog and introduction to this series? &lt;a href=&quot;https://blog.esciencecenter.nl/efd78c08469-using-c-in-a-web-app-with-webassembly&quot;&gt;This blog post&lt;/a&gt; will show you how to get started running your C++ on the web using WebAssembly.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thank you to our proof reader&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 09 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In an &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;earlier blogpost&lt;/a&gt; we discussed how to run C++ code on the web using JavaScript. We created a web app that executed some C++ code and then showed the result in the browser. While the page was running the C++ code, the page was blocked and unresponsive. This was not noticeable, because the computation done in the code was very quick. An unresponsive User Interface (UI) becomes a problem when we are performing tasks that take a bit longer to run.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How to prevent blocking when running long running tasks in C++?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this blog post, we will use web workers to solve this problem by offloading tasks to another thread.&lt;/p&gt;
&lt;h2 id=&quot;long-running-tasks-with-web-worker&quot;&gt;Long-running tasks with web worker&lt;/h2&gt;
&lt;p&gt;Let’s have a look at the code we ended up with in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;first blog&lt;/a&gt; of the series. When loading the page, the WebAssembly code is executed, after which the page can finish rendering. Because the WebAssembly code was very quick, this was fine. For the current blog, we assume we have a longer running task. We create such a task artificially, by adding a few seconds of &lt;code&gt;sleep&lt;/code&gt; in the &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/web-worker/newtonraphson.cpp&quot;&gt;C++ code&lt;/a&gt;. Like in the first post of the series, we compile the C++ code to create WebAssembly code. The example page with our slow task can be found &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/web-worker/example-blocking.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notice that we also added a slider to the page. This slider simply serves to illustrate UI unresponsiveness — it has no attached function. Notice that while the WebAssembly code is still running, the slider is completely blocked. If this was an actual web app and not just a demo, the blocked UI would surely annoy users and possibly make working with the app cumbersome and impractical. We can easily solve this, and keep the UI responsive at all times, using web workers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;509&quot; height=&quot;163&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_GFkQlI6sOZUxjhbEE8U5UQ-0fc27ea2.C073jd4K_1jywBO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Blocked UI while code is running.&lt;/p&gt;
&lt;h2 id=&quot;web-workers&quot;&gt;Web workers&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API&quot;&gt;web worker&lt;/a&gt; is an object that handles execution of a piece of code in another thread.&lt;/p&gt;
&lt;p&gt;The way the page communicates with the worker object is through sending messages. The page will send a message to the worker to start doing work, and the message will include all data that the worker needs. The worker then starts executing the task, using only the data that was in the message. When finished, the worker needs to communicate the results back to the web app. It will do this by sending a message, so the web app knows when to update.&lt;/p&gt;
&lt;h2 id=&quot;the-resulting-page&quot;&gt;The resulting page&lt;/h2&gt;
&lt;p&gt;The code snippet below shows the web page that uses a web worker. Notice the creation of the &lt;code&gt;Worker&lt;/code&gt; object, posting of the message, as well as the instructions for handling of any returned messages containing results.&lt;/p&gt;
&lt;p&gt;The web worker code only contains handling of the incoming message. The web worker unpacks the message, does the root finding calculation, and packs the results in a new message that it will send back.&lt;/p&gt;
&lt;p&gt;The code for the worker in &lt;code&gt;worker.js&lt;/code&gt; is:&lt;/p&gt;
&lt;p&gt;The figure below illustrates what is happening in parallel in the two threads.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;666&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1__Knkh9aTq85_WNvyZjRPlQ-ad4c9f5c.CBM67MGz_Z1tSPLi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can see the code in action &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/web-worker/example-web-worker.html&quot;&gt;here&lt;/a&gt;. The calculation still takes the same time to perform, but as you will notice, the slider remains responsive.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;508&quot; height=&quot;158&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_efp-XCZJWs0yNveDPrq38w-bdc1dd9c.BcldFPYW_Z12E1tA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Responsive UI thanks to offloading the root finding procedure to the web worker.&lt;/p&gt;
&lt;h2 id=&quot;recap-and-what-next&quot;&gt;Recap and what next?&lt;/h2&gt;
&lt;p&gt;In this blog post, we learned how to keep a web app from freezing while executing computationally intensive C++ code. We learned how to create a web worker and how to use the web worker in a simple web app.&lt;/p&gt;
&lt;p&gt;Now you can take this web app a step further by reading some of the other blogs in this series, for example &lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;how to interact with your app using forms&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;how to spice up your app up with visualizations&lt;/a&gt;. A final blog shows you &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;how to combine all of the above in a single web app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looking for the first blog and introduction to this series? &lt;a href=&quot;https://blog.esciencecenter.nl/efd78c08469-using-c-in-a-web-app-with-webassembly&quot;&gt;This blog post&lt;/a&gt; will show you how to get started running your C++ on the web using WebAssembly.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thank you to our proof reader&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-5565-7577&quot;&gt;&lt;em&gt;Carlos Martinez-Ortiz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/1_GFkQlI6sOZUxjhbEE8U5UQ-0fc27ea2.C073jd4K.gif" medium="image"/><author>eScience Editorial Team</author></item><item><title>Interact with your C++ web app using React forms</title><link>https://blog.esciencecenter.nl/posts/2020-10-09---interact-with-your-c-web-app-using-react-forms</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-09---interact-with-your-c-web-app-using-react-forms</guid><description>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog post&lt;/a&gt;, we compiled the C++ algorithm into WebAssembly. In the current blog post, we will create a web application using &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. The web application will have a web form that allows us to change the parameters of the algorithm.&lt;/p&gt;
&lt;p&gt;We feel your pain: there are too many things to learn, too many skills to get, but too little time available — which reminds me of our extraordinary friend &lt;a href=&quot;https://www.imdb.com/title/tt0374900/&quot;&gt;Napoleon Dynamite&lt;/a&gt;. This blog post will guide you through the process of making a React web application without getting lost.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;658&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_XHTFs5--uJCCcQuI-9cccbcb9.DVTzmuKc_Z1K5bYU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you haven’t met Napoleon yet, click here to see how he was struggling with his skills. Screenshot from Napoleon Dynamite movie.&lt;/p&gt;
&lt;h2 id=&quot;react-web-application&quot;&gt;React web application&lt;/h2&gt;
&lt;p&gt;The web application we developed so far needs to update the entire page to display the results. Even for small changes in the web page, this has to happen. Thanks to modern web browsers and JavaScript, Single Page Applications (SPAs) can update only required elements in the web page. We will use one of the most popular web frameworks, React, to develop the SPA. We chose React over vanilla JavaScript because building a web application is made easier by letting React deal with all the magic behind the scenes. &lt;a href=&quot;https://www.freecodecamp.org/news/do-we-still-need-javascript-frameworks-42576735949b/&quot;&gt;This blog post&lt;/a&gt; may help you to understand why we made this choice.&lt;/p&gt;
&lt;p&gt;The form in the web application will collect the user inputs and uses them to initialize the algorithm. When the form is submitted, a WebAssembly code starts the calculation and the result is rendered. With this architecture, the application only needs cheap static file hosting to host the HTML, JavaScript, and WebAssembly files. The algorithm will be running in the web browser on the end-user’s machine instead of a server.&lt;/p&gt;
&lt;h3 id=&quot;the-html-code&quot;&gt;The HTML code&lt;/h3&gt;
&lt;p&gt;To render the React application we need an HTML element as a container. We will give it the identifier &lt;strong&gt;container&lt;/strong&gt; which will use later when we implement the &lt;strong&gt;React&lt;/strong&gt; application.&lt;/p&gt;
&lt;p&gt;We will keep the HTML code very minimal. The code will contain three essential elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt; element to set the title and to load the required external dependencies (JavaScript libraries).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div&gt; element to display the result&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;script&gt;&lt;/script&gt; elements to load the Javascript application and the &lt;code&gt;NewtonRaphson&lt;/code&gt; class.&lt;/strong&gt;&lt;/p&gt;&lt;strong&gt;
&lt;/strong&gt;&lt;/li&gt;&lt;strong&gt;
&lt;/strong&gt;&lt;/ul&gt;&lt;strong&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We use the same &lt;code&gt;newtonraphson.js&lt;/code&gt; and &lt;code&gt;newtonraphson.wasm&lt;/code&gt; files as in the &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/webassembly/README.md&quot;&gt;first post&lt;/a&gt; of this series. Make sure you download &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/newtonraphson.js&quot;&gt;newtonraphson.js&lt;/a&gt; and &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/newtonraphson.wasm&quot;&gt;newtonraphson.wasm&lt;/a&gt; files from GitHub.&lt;/p&gt;
&lt;p&gt;The complete HTML code will look like this:&lt;/p&gt;
&lt;h3 id=&quot;javascript-code-react&quot;&gt;JavaScript code (React)&lt;/h3&gt;
&lt;p&gt;Similarly, we will split the JavaScript code into sections and build up the React application from React components.&lt;/p&gt;
&lt;p&gt;Let’s start with the header part. We will define a JavaScript function that returns the header element which will be rendered by the web browser when the user visits the page.&lt;/p&gt;
&lt;p&gt;The return statement of this function looks weird, right? It is indeed not HTML. React uses a syntax extension called &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX&lt;/a&gt; to describe the UI. With the magical conversion of &lt;a href=&quot;https://babeljs.io/docs/en/next/babel-standalone.html&quot;&gt;Babel&lt;/a&gt; we can convert JSX into JavaScript code. After this conversion the generated JavaScript code will look like:&lt;/p&gt;
&lt;p&gt;In order for the header element to be rendered we need to tell &lt;strong&gt;ReactDOM&lt;/strong&gt; which element it should render and where it should be displayed. Do you still remember the &lt;strong&gt;container&lt;/strong&gt; &lt;code&gt;div&lt;/code&gt; we defined in the HTML part?&lt;/p&gt;
&lt;p&gt;The complete code should look like this:&lt;/p&gt;
&lt;p&gt;When the page is rendered, the generated HTML code will be like:&lt;/p&gt;
&lt;h2 id=&quot;adding-the-web-form&quot;&gt;Adding the web form&lt;/h2&gt;
&lt;p&gt;The web application in our example should have a form with &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt; input fields, as well as a submit button. The form in JSX can be written in the following way:&lt;/p&gt;
&lt;p&gt;The form tag has an &lt;code&gt;onSubmit&lt;/code&gt; property, which is set to a function ( &lt;code&gt;handleSubmit&lt;/code&gt;) that will handle the form submission. The input tag has a &lt;code&gt;value&lt;/code&gt; property to set the variable ( &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt;) and it also has an &lt;code&gt;onChange&lt;/code&gt; property to set the function ( &lt;code&gt;onToleranceChange&lt;/code&gt; and &lt;code&gt;onGuessChange&lt;/code&gt;) which will be triggered when the user changes the value.&lt;/p&gt;
&lt;p&gt;Let’s implement the &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;onChange&lt;/code&gt; for the &lt;code&gt;tolerance&lt;/code&gt; input. To store the value we will use the &lt;a href=&quot;https://reactjs.org/docs/hooks-state.html&quot;&gt;React useState hook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The argument of the &lt;code&gt;useState&lt;/code&gt; function is the initial value. The &lt;code&gt;tolerance&lt;/code&gt; variable contains the current value for tolerance and &lt;code&gt;setTolerance&lt;/code&gt; is a function to set the &lt;code&gt;tolerance&lt;/code&gt; to a new value. The same logic is also used for the &lt;code&gt;initial_guess&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;The input tag in the form will call the &lt;code&gt;onChange&lt;/code&gt; function with an event object. We need to extract the user input from the event and pass it to &lt;code&gt;setTolerance&lt;/code&gt; or &lt;code&gt;setGuess&lt;/code&gt;. The value should be a number, so we use &lt;code&gt;Number()&lt;/code&gt; to cast the string from the event to a number.&lt;/p&gt;
&lt;p&gt;We are now ready to implement the &lt;code&gt;handleSubmit&lt;/code&gt; function which will process the submitted form data. The function will get an event object, similar to the &lt;code&gt;onChange&lt;/code&gt; of the input tag. Normally when you submit a form, the form fields will be sent to the server, but we want to perform the calculation in the browser, so we have to disable the default action with &lt;code&gt;preventDefault()&lt;/code&gt;. We will then construct a WebAssembly module as we did in &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/webassembly/README.md&quot;&gt;a previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We need a place to store the result of the calculation ( &lt;code&gt;root&lt;/code&gt; value), we will use &lt;code&gt;useState&lt;/code&gt; function again. The initial value of the result is set to &lt;code&gt;undefined&lt;/code&gt; as the result is only known after the calculation has been completed.&lt;/p&gt;
&lt;p&gt;When the calculation is done it will store the result value ( &lt;code&gt;root&lt;/code&gt;) using &lt;code&gt;setRoot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To render the result we can use a React Component which has &lt;code&gt;root&lt;/code&gt; as a property. When the calculation has not been done yet, it will render &lt;code&gt;Not submitted&lt;/code&gt;. We will show the &lt;code&gt;root&lt;/code&gt; property value once it is set.&lt;/p&gt;
&lt;p&gt;Finally we can render the &lt;code&gt;App&lt;/code&gt; component to the HTML container with &lt;code&gt;id&lt;/code&gt; equal to &lt;code&gt;container&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can combine the heading, form and result components and all the states and &lt;code&gt;handleSubmit&lt;/code&gt; function into the &lt;code&gt;App&lt;/code&gt; React component and its rendering and save it as &lt;code&gt;app.js&lt;/code&gt;. You can find the resulting code &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/app.js&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like before, we also need to host the files in a web server with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;754&quot; height=&quot;222&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_smvfh5MifrSGsY10-8c73001a.6WsYx5Pj_Z1bngGr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The final page if everything works.&lt;/p&gt;
&lt;p&gt;Visit &lt;a href=&quot;http://localhost:8000/app.html&quot;&gt;http://localhost:8000/app.html&lt;/a&gt; to see the root answer, or go to &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/react/app.html&quot;&gt;GitHub pages&lt;/a&gt; to see a hosted version of the example app.&lt;/p&gt;
&lt;h2 id=&quot;extra-notes&quot;&gt;Extra notes&lt;/h2&gt;
&lt;p&gt;The code supplied here should not be used in production as converting JSX in the web browser is slow. It’s better to use &lt;a href=&quot;http://create-react-app.dev/&quot;&gt;Create React App&lt;/a&gt;, which gives you an infrastructure to perform the transformation offline.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By writing React components we were able to create an interactive page with a form that executes the WebAssembly module compiled from the C++ code we introduced in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;first blog&lt;/a&gt; of the series.&lt;/p&gt;
&lt;p&gt;We went over JSX, props, state, and components, which together constitute the core building blocks of a React web application.&lt;/p&gt;
&lt;p&gt;In other blogs of the series that might be of interest we cover&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;Using C++ in a web app with WebAssembly&lt;/a&gt;: How to turn C++ code into a web app.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;: How to use web workers to perform computations without blocking the user interface.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;Spice up your C++ web app with visualizations&lt;/a&gt;: Plotting data from the C++ web app using web visualization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in a &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thank you to our proof reader&lt;/em&gt; &lt;a href=&quot;https://github.com/DAANBOER&quot;&gt;&lt;em&gt;Daan Boer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/strong&gt;</description><pubDate>Fri, 09 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog post&lt;/a&gt;, we compiled the C++ algorithm into WebAssembly. In the current blog post, we will create a web application using &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. The web application will have a web form that allows us to change the parameters of the algorithm.&lt;/p&gt;
&lt;p&gt;We feel your pain: there are too many things to learn, too many skills to get, but too little time available — which reminds me of our extraordinary friend &lt;a href=&quot;https://www.imdb.com/title/tt0374900/&quot;&gt;Napoleon Dynamite&lt;/a&gt;. This blog post will guide you through the process of making a React web application without getting lost.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;658&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_XHTFs5--uJCCcQuI-9cccbcb9.DVTzmuKc_Z1K5bYU.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you haven’t met Napoleon yet, click here to see how he was struggling with his skills. Screenshot from Napoleon Dynamite movie.&lt;/p&gt;
&lt;h2 id=&quot;react-web-application&quot;&gt;React web application&lt;/h2&gt;
&lt;p&gt;The web application we developed so far needs to update the entire page to display the results. Even for small changes in the web page, this has to happen. Thanks to modern web browsers and JavaScript, Single Page Applications (SPAs) can update only required elements in the web page. We will use one of the most popular web frameworks, React, to develop the SPA. We chose React over vanilla JavaScript because building a web application is made easier by letting React deal with all the magic behind the scenes. &lt;a href=&quot;https://www.freecodecamp.org/news/do-we-still-need-javascript-frameworks-42576735949b/&quot;&gt;This blog post&lt;/a&gt; may help you to understand why we made this choice.&lt;/p&gt;
&lt;p&gt;The form in the web application will collect the user inputs and uses them to initialize the algorithm. When the form is submitted, a WebAssembly code starts the calculation and the result is rendered. With this architecture, the application only needs cheap static file hosting to host the HTML, JavaScript, and WebAssembly files. The algorithm will be running in the web browser on the end-user’s machine instead of a server.&lt;/p&gt;
&lt;h3 id=&quot;the-html-code&quot;&gt;The HTML code&lt;/h3&gt;
&lt;p&gt;To render the React application we need an HTML element as a container. We will give it the identifier &lt;strong&gt;container&lt;/strong&gt; which will use later when we implement the &lt;strong&gt;React&lt;/strong&gt; application.&lt;/p&gt;
&lt;p&gt;We will keep the HTML code very minimal. The code will contain three essential elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt; element to set the title and to load the required external dependencies (JavaScript libraries).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div&gt; element to display the result&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;script&gt;&lt;/script&gt; elements to load the Javascript application and the &lt;code&gt;NewtonRaphson&lt;/code&gt; class.&lt;/strong&gt;&lt;/p&gt;&lt;strong&gt;
&lt;/strong&gt;&lt;/li&gt;&lt;strong&gt;
&lt;/strong&gt;&lt;/ul&gt;&lt;strong&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We use the same &lt;code&gt;newtonraphson.js&lt;/code&gt; and &lt;code&gt;newtonraphson.wasm&lt;/code&gt; files as in the &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/webassembly/README.md&quot;&gt;first post&lt;/a&gt; of this series. Make sure you download &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/newtonraphson.js&quot;&gt;newtonraphson.js&lt;/a&gt; and &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/newtonraphson.wasm&quot;&gt;newtonraphson.wasm&lt;/a&gt; files from GitHub.&lt;/p&gt;
&lt;p&gt;The complete HTML code will look like this:&lt;/p&gt;
&lt;h3 id=&quot;javascript-code-react&quot;&gt;JavaScript code (React)&lt;/h3&gt;
&lt;p&gt;Similarly, we will split the JavaScript code into sections and build up the React application from React components.&lt;/p&gt;
&lt;p&gt;Let’s start with the header part. We will define a JavaScript function that returns the header element which will be rendered by the web browser when the user visits the page.&lt;/p&gt;
&lt;p&gt;The return statement of this function looks weird, right? It is indeed not HTML. React uses a syntax extension called &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX&lt;/a&gt; to describe the UI. With the magical conversion of &lt;a href=&quot;https://babeljs.io/docs/en/next/babel-standalone.html&quot;&gt;Babel&lt;/a&gt; we can convert JSX into JavaScript code. After this conversion the generated JavaScript code will look like:&lt;/p&gt;
&lt;p&gt;In order for the header element to be rendered we need to tell &lt;strong&gt;ReactDOM&lt;/strong&gt; which element it should render and where it should be displayed. Do you still remember the &lt;strong&gt;container&lt;/strong&gt; &lt;code&gt;div&lt;/code&gt; we defined in the HTML part?&lt;/p&gt;
&lt;p&gt;The complete code should look like this:&lt;/p&gt;
&lt;p&gt;When the page is rendered, the generated HTML code will be like:&lt;/p&gt;
&lt;h2 id=&quot;adding-the-web-form&quot;&gt;Adding the web form&lt;/h2&gt;
&lt;p&gt;The web application in our example should have a form with &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt; input fields, as well as a submit button. The form in JSX can be written in the following way:&lt;/p&gt;
&lt;p&gt;The form tag has an &lt;code&gt;onSubmit&lt;/code&gt; property, which is set to a function ( &lt;code&gt;handleSubmit&lt;/code&gt;) that will handle the form submission. The input tag has a &lt;code&gt;value&lt;/code&gt; property to set the variable ( &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt;) and it also has an &lt;code&gt;onChange&lt;/code&gt; property to set the function ( &lt;code&gt;onToleranceChange&lt;/code&gt; and &lt;code&gt;onGuessChange&lt;/code&gt;) which will be triggered when the user changes the value.&lt;/p&gt;
&lt;p&gt;Let’s implement the &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;onChange&lt;/code&gt; for the &lt;code&gt;tolerance&lt;/code&gt; input. To store the value we will use the &lt;a href=&quot;https://reactjs.org/docs/hooks-state.html&quot;&gt;React useState hook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The argument of the &lt;code&gt;useState&lt;/code&gt; function is the initial value. The &lt;code&gt;tolerance&lt;/code&gt; variable contains the current value for tolerance and &lt;code&gt;setTolerance&lt;/code&gt; is a function to set the &lt;code&gt;tolerance&lt;/code&gt; to a new value. The same logic is also used for the &lt;code&gt;initial_guess&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;The input tag in the form will call the &lt;code&gt;onChange&lt;/code&gt; function with an event object. We need to extract the user input from the event and pass it to &lt;code&gt;setTolerance&lt;/code&gt; or &lt;code&gt;setGuess&lt;/code&gt;. The value should be a number, so we use &lt;code&gt;Number()&lt;/code&gt; to cast the string from the event to a number.&lt;/p&gt;
&lt;p&gt;We are now ready to implement the &lt;code&gt;handleSubmit&lt;/code&gt; function which will process the submitted form data. The function will get an event object, similar to the &lt;code&gt;onChange&lt;/code&gt; of the input tag. Normally when you submit a form, the form fields will be sent to the server, but we want to perform the calculation in the browser, so we have to disable the default action with &lt;code&gt;preventDefault()&lt;/code&gt;. We will then construct a WebAssembly module as we did in &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/webassembly/README.md&quot;&gt;a previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We need a place to store the result of the calculation ( &lt;code&gt;root&lt;/code&gt; value), we will use &lt;code&gt;useState&lt;/code&gt; function again. The initial value of the result is set to &lt;code&gt;undefined&lt;/code&gt; as the result is only known after the calculation has been completed.&lt;/p&gt;
&lt;p&gt;When the calculation is done it will store the result value ( &lt;code&gt;root&lt;/code&gt;) using &lt;code&gt;setRoot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To render the result we can use a React Component which has &lt;code&gt;root&lt;/code&gt; as a property. When the calculation has not been done yet, it will render &lt;code&gt;Not submitted&lt;/code&gt;. We will show the &lt;code&gt;root&lt;/code&gt; property value once it is set.&lt;/p&gt;
&lt;p&gt;Finally we can render the &lt;code&gt;App&lt;/code&gt; component to the HTML container with &lt;code&gt;id&lt;/code&gt; equal to &lt;code&gt;container&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can combine the heading, form and result components and all the states and &lt;code&gt;handleSubmit&lt;/code&gt; function into the &lt;code&gt;App&lt;/code&gt; React component and its rendering and save it as &lt;code&gt;app.js&lt;/code&gt;. You can find the resulting code &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/react/app.js&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like before, we also need to host the files in a web server with&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;754&quot; height=&quot;222&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_smvfh5MifrSGsY10-8c73001a.6WsYx5Pj_Z1bngGr.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The final page if everything works.&lt;/p&gt;
&lt;p&gt;Visit &lt;a href=&quot;http://localhost:8000/app.html&quot;&gt;http://localhost:8000/app.html&lt;/a&gt; to see the root answer, or go to &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/react/app.html&quot;&gt;GitHub pages&lt;/a&gt; to see a hosted version of the example app.&lt;/p&gt;
&lt;h2 id=&quot;extra-notes&quot;&gt;Extra notes&lt;/h2&gt;
&lt;p&gt;The code supplied here should not be used in production as converting JSX in the web browser is slow. It’s better to use &lt;a href=&quot;http://create-react-app.dev/&quot;&gt;Create React App&lt;/a&gt;, which gives you an infrastructure to perform the transformation offline.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By writing React components we were able to create an interactive page with a form that executes the WebAssembly module compiled from the C++ code we introduced in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;first blog&lt;/a&gt; of the series.&lt;/p&gt;
&lt;p&gt;We went over JSX, props, state, and components, which together constitute the core building blocks of a React web application.&lt;/p&gt;
&lt;p&gt;In other blogs of the series that might be of interest we cover&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;Using C++ in a web app with WebAssembly&lt;/a&gt;: How to turn C++ code into a web app.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;: How to use web workers to perform computations without blocking the user interface.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;Spice up your C++ web app with visualizations&lt;/a&gt;: Plotting data from the C++ web app using web visualization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in a &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thank you to our proof reader&lt;/em&gt; &lt;a href=&quot;https://github.com/DAANBOER&quot;&gt;&lt;em&gt;Daan Boer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/strong&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_XHTFs5--uJCCcQuI-9cccbcb9.DVTzmuKc.png" medium="image"/><author>eScience Editorial Team</author></item><item><title>Spice up your C++ web app with visualizations</title><link>https://blog.esciencecenter.nl/posts/2020-10-09---spice-up-your-c-web-app-with-visualizations</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-09---spice-up-your-c-web-app-with-visualizations</guid><description>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog&lt;/a&gt; we found the root of an equation using the Newton-Raphson algorithm implemented in C++ and compiled to a WebAsssembly module. In this blog, we’re going to expand on that by visualizing the iterations that Newton-Raphson used to get from the initial guess to the estimate of the root.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2097&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_q33p383lsb3jlUV9-ca283010.CJQRcRqz_Z1V5IMO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Visualization allows us to track what’s going on under the hood of our program. Image courtesy of Nenad Stojkovic via flickr.&lt;/p&gt;
&lt;h2 id=&quot;iterations&quot;&gt;Iterations&lt;/h2&gt;
&lt;p&gt;The Newton-Raphson algorithm approximates the value of the target equation’s root in a series of iterations. We capture the data of each iteration using the following &lt;code&gt;struct&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;: x value, starting with the value of &lt;code&gt;initial_guess&lt;/code&gt; and ending with the estimate of the &lt;code&gt;equation&lt;/code&gt; ‘s root&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt;: result of passing &lt;code&gt;x&lt;/code&gt; through &lt;code&gt;equation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slope&lt;/code&gt;: result of passing &lt;code&gt;x&lt;/code&gt; through &lt;code&gt;derivative&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extending the &lt;code&gt;NewtonRaphson&lt;/code&gt; class accordingly yields the following header file:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.hpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;do&lt;/code&gt; loop in &lt;code&gt;newtonraphson.cpp&lt;/code&gt; is updated to include a &lt;code&gt;push_back&lt;/code&gt; to the &lt;code&gt;iterations&lt;/code&gt; vector. This way, we can record the value of relevant variables in each cycle, as follows:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we go into the Emscripten world, let’s first test our C++ code. We can check if the iteration property is populated correctly, by extending the command line interface we made in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog&lt;/a&gt; as follows:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;cli.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Compile it with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;./&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;186.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 128.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.45&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.55&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;52.99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 59.29&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.89&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.65&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;13.97&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 29.63&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.47&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.18&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.89&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 17.83&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.02&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.28&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 14.40&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 14.01&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last iteration has &lt;code&gt;x = -1.00&lt;/code&gt;, which is what we expected.&lt;/p&gt;
&lt;h2 id=&quot;bindings&quot;&gt;Bindings&lt;/h2&gt;
&lt;p&gt;Emscripten can handle simple types like &lt;code&gt;float&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;, but needs help exposing more complex types to JavaScript like the &lt;code&gt;iterations&lt;/code&gt; property. We need to use &lt;code&gt;value_object&lt;/code&gt; to expose the &lt;code&gt;Iteration&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; and &lt;code&gt;register_vector&lt;/code&gt; as the &lt;code&gt;iterations&lt;/code&gt; property type.&lt;/p&gt;
&lt;p&gt;So the bindings look like this:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;bindings.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We can now compile our C++ code to a WebAssembly module with Emscripten using &lt;code&gt;emcc&lt;/code&gt; command, exactly &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;like we did before&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;emcc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;I.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;js &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Oz&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;EXPORT_NAME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;createModule &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--bind \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp bindings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the iteration data in JavaScript we use the following code&lt;/p&gt;
&lt;p&gt;Let’s have a look at the data we want to plot, by logging it to the console with &lt;code&gt;console.log(JSON.stringify(iterations, null, 2))&lt;/code&gt;, which should return the following data:&lt;/p&gt;
&lt;p&gt;Great, that looks very similar to the output we got from the command line.&lt;/p&gt;
&lt;h2 id=&quot;vega-lite-specification&quot;&gt;Vega-Lite specification&lt;/h2&gt;
&lt;p&gt;There &lt;a href=&quot;https://github.com/sorrycc/awesome-javascript#data-visualization&quot;&gt;many ways to do visualizations&lt;/a&gt; on the web. One of our favorites is &lt;a href=&quot;https://vega.github.io/vega-lite/&quot;&gt;Vega-Lite&lt;/a&gt;, a JavaScript library which describes a plot using a JSON document called a &lt;em&gt;specification&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The root finding algorithm tries to find the &lt;code&gt;x&lt;/code&gt; where &lt;code&gt;y&lt;/code&gt; is zero using a series of iterations. Let’s plot the iteration &lt;code&gt;index&lt;/code&gt; against the &lt;code&gt;y&lt;/code&gt; found in each iteration to see how quickly it converged to an answer.&lt;/p&gt;
&lt;p&gt;The generic structure of our Vega-Lite specification looks like this:&lt;/p&gt;
&lt;p&gt;To render a specification we need to use the &lt;code&gt;vegaEmbed(element, spec)&lt;/code&gt; method which accepts an HTML element and a Vega-Lite specification.&lt;/p&gt;
&lt;p&gt;Combining the three snippets above (get iteration data, Vega specification and vegaEmbed) and filling in their respective details yields an HTML document with the complete web app:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;scatter.html&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the &lt;code&gt;http.server&lt;/code&gt; module from Python 3 again to host all files on port 8000, like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we visit the web page at &lt;a href=&quot;http://localhost:8000/scatter.html&quot;&gt;http://localhost:8000/scatter.html&lt;/a&gt;, we will be greeted by the following plot. We can zoom with the mouse wheel and pan by dragging. Hovering over a point shows a tooltip with relevant data at that point.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;888&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_iP7zrZjQTIoAX2Zq-a9c14462.Q3UBIzG9_Z7LnFF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Click on image to get interactive version)&lt;/p&gt;
&lt;h2 id=&quot;advanced-plot&quot;&gt;Advanced plot&lt;/h2&gt;
&lt;p&gt;In the first blog of this series we plotted the equation and root as&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;857&quot; height=&quot;880&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RUHNAgWlcRCfGzf1-8a8b79de.BjAjlaJh_2u6jK4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It would be nice to write a specification of this plot together with the iterations that the root finding algorithm went through. Vega-Lite can superimpose one chart on top of another with the keyword. Let’s construct each layer separately and then superimpose them at the end.&lt;/p&gt;
&lt;p&gt;The 2x³ — 4x² + 6 equation is plotted by using a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/data.html#sequence&quot;&gt;sequence generator&lt;/a&gt; to generate a range of &lt;code&gt;x&lt;/code&gt; values and a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/calculate.html&quot;&gt;formula transform&lt;/a&gt; is used to calculate the &lt;code&gt;y&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;To show where the root is, we draw a dotted vertical line using a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/rule.html&quot;&gt;rule marker&lt;/a&gt; at &lt;code&gt;x = -1&lt;/code&gt; and label it &lt;code&gt;root&lt;/code&gt; with a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/text.html&quot;&gt;text marker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When we plot the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; of each iteration we can no longer see the order of iterations, so we will use a text marker above each circle to indicate which iteration it belongs to.&lt;/p&gt;
&lt;p&gt;Superimpose the equation line, root ruler, and iteration scatter into a single visualization with:&lt;/p&gt;
&lt;p&gt;The HTML page with all JavaScript put together to make a composite plot is available &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/vega/app.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Visiting the page should give us a plot like&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;883&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_b72R67dWgF3M1Igc-32392a5a.DqrD48sd_2dCGNi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Click on image to get interactive version)&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;In this blog we have learned how to get complex data types from a WebAssembly module using Emscripten bindings and how to write a Vega-Lite specifications to get interactive visualizations.&lt;/p&gt;
&lt;p&gt;Other blogs of the series that might be of interest&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;Interact with your C++ web app using React forms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in a &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application.&lt;/p&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 09 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog&lt;/a&gt; we found the root of an equation using the Newton-Raphson algorithm implemented in C++ and compiled to a WebAsssembly module. In this blog, we’re going to expand on that by visualizing the iterations that Newton-Raphson used to get from the initial guess to the estimate of the root.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;2097&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_q33p383lsb3jlUV9-ca283010.CJQRcRqz_Z1V5IMO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Visualization allows us to track what’s going on under the hood of our program. Image courtesy of Nenad Stojkovic via flickr.&lt;/p&gt;
&lt;h2 id=&quot;iterations&quot;&gt;Iterations&lt;/h2&gt;
&lt;p&gt;The Newton-Raphson algorithm approximates the value of the target equation’s root in a series of iterations. We capture the data of each iteration using the following &lt;code&gt;struct&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;: x value, starting with the value of &lt;code&gt;initial_guess&lt;/code&gt; and ending with the estimate of the &lt;code&gt;equation&lt;/code&gt; ‘s root&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt;: result of passing &lt;code&gt;x&lt;/code&gt; through &lt;code&gt;equation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slope&lt;/code&gt;: result of passing &lt;code&gt;x&lt;/code&gt; through &lt;code&gt;derivative&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extending the &lt;code&gt;NewtonRaphson&lt;/code&gt; class accordingly yields the following header file:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.hpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;do&lt;/code&gt; loop in &lt;code&gt;newtonraphson.cpp&lt;/code&gt; is updated to include a &lt;code&gt;push_back&lt;/code&gt; to the &lt;code&gt;iterations&lt;/code&gt; vector. This way, we can record the value of relevant variables in each cycle, as follows:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we go into the Emscripten world, let’s first test our C++ code. We can check if the iteration property is populated correctly, by extending the command line interface we made in the &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;previous blog&lt;/a&gt; as follows:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;cli.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Compile it with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;./&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;186.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 128.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.45&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.55&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;52.99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 59.29&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.89&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.65&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;13.97&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 29.63&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.47&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.18&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.89&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 17.83&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.02&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.28&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 14.40&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.00&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 14.01&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta_x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last iteration has &lt;code&gt;x = -1.00&lt;/code&gt;, which is what we expected.&lt;/p&gt;
&lt;h2 id=&quot;bindings&quot;&gt;Bindings&lt;/h2&gt;
&lt;p&gt;Emscripten can handle simple types like &lt;code&gt;float&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;, but needs help exposing more complex types to JavaScript like the &lt;code&gt;iterations&lt;/code&gt; property. We need to use &lt;code&gt;value_object&lt;/code&gt; to expose the &lt;code&gt;Iteration&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; and &lt;code&gt;register_vector&lt;/code&gt; as the &lt;code&gt;iterations&lt;/code&gt; property type.&lt;/p&gt;
&lt;p&gt;So the bindings look like this:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;bindings.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We can now compile our C++ code to a WebAssembly module with Emscripten using &lt;code&gt;emcc&lt;/code&gt; command, exactly &lt;a href=&quot;https://medium.com/@eScienceCenter/using-c-in-a-web-app-with-webassembly-efd78c08469&quot;&gt;like we did before&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;emcc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;I.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;js &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Oz&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;EXPORT_NAME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;createModule &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--bind \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp bindings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the iteration data in JavaScript we use the following code&lt;/p&gt;
&lt;p&gt;Let’s have a look at the data we want to plot, by logging it to the console with &lt;code&gt;console.log(JSON.stringify(iterations, null, 2))&lt;/code&gt;, which should return the following data:&lt;/p&gt;
&lt;p&gt;Great, that looks very similar to the output we got from the command line.&lt;/p&gt;
&lt;h2 id=&quot;vega-lite-specification&quot;&gt;Vega-Lite specification&lt;/h2&gt;
&lt;p&gt;There &lt;a href=&quot;https://github.com/sorrycc/awesome-javascript#data-visualization&quot;&gt;many ways to do visualizations&lt;/a&gt; on the web. One of our favorites is &lt;a href=&quot;https://vega.github.io/vega-lite/&quot;&gt;Vega-Lite&lt;/a&gt;, a JavaScript library which describes a plot using a JSON document called a &lt;em&gt;specification&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The root finding algorithm tries to find the &lt;code&gt;x&lt;/code&gt; where &lt;code&gt;y&lt;/code&gt; is zero using a series of iterations. Let’s plot the iteration &lt;code&gt;index&lt;/code&gt; against the &lt;code&gt;y&lt;/code&gt; found in each iteration to see how quickly it converged to an answer.&lt;/p&gt;
&lt;p&gt;The generic structure of our Vega-Lite specification looks like this:&lt;/p&gt;
&lt;p&gt;To render a specification we need to use the &lt;code&gt;vegaEmbed(element, spec)&lt;/code&gt; method which accepts an HTML element and a Vega-Lite specification.&lt;/p&gt;
&lt;p&gt;Combining the three snippets above (get iteration data, Vega specification and vegaEmbed) and filling in their respective details yields an HTML document with the complete web app:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;scatter.html&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the &lt;code&gt;http.server&lt;/code&gt; module from Python 3 again to host all files on port 8000, like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we visit the web page at &lt;a href=&quot;http://localhost:8000/scatter.html&quot;&gt;http://localhost:8000/scatter.html&lt;/a&gt;, we will be greeted by the following plot. We can zoom with the mouse wheel and pan by dragging. Hovering over a point shows a tooltip with relevant data at that point.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;888&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_iP7zrZjQTIoAX2Zq-a9c14462.Q3UBIzG9_Z7LnFF.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Click on image to get interactive version)&lt;/p&gt;
&lt;h2 id=&quot;advanced-plot&quot;&gt;Advanced plot&lt;/h2&gt;
&lt;p&gt;In the first blog of this series we plotted the equation and root as&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;857&quot; height=&quot;880&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RUHNAgWlcRCfGzf1-8a8b79de.BjAjlaJh_2u6jK4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It would be nice to write a specification of this plot together with the iterations that the root finding algorithm went through. Vega-Lite can superimpose one chart on top of another with the keyword. Let’s construct each layer separately and then superimpose them at the end.&lt;/p&gt;
&lt;p&gt;The 2x³ — 4x² + 6 equation is plotted by using a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/data.html#sequence&quot;&gt;sequence generator&lt;/a&gt; to generate a range of &lt;code&gt;x&lt;/code&gt; values and a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/calculate.html&quot;&gt;formula transform&lt;/a&gt; is used to calculate the &lt;code&gt;y&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;To show where the root is, we draw a dotted vertical line using a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/rule.html&quot;&gt;rule marker&lt;/a&gt; at &lt;code&gt;x = -1&lt;/code&gt; and label it &lt;code&gt;root&lt;/code&gt; with a &lt;a href=&quot;https://vega.github.io/vega-lite/docs/text.html&quot;&gt;text marker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When we plot the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; of each iteration we can no longer see the order of iterations, so we will use a text marker above each circle to indicate which iteration it belongs to.&lt;/p&gt;
&lt;p&gt;Superimpose the equation line, root ruler, and iteration scatter into a single visualization with:&lt;/p&gt;
&lt;p&gt;The HTML page with all JavaScript put together to make a composite plot is available &lt;a href=&quot;https://github.com/NLESC-JCER/run-cpp-on-web/blob/master/vega/app.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Visiting the page should give us a plot like&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;883&quot; height=&quot;695&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_b72R67dWgF3M1Igc-32392a5a.DqrD48sd_2dCGNi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Click on image to get interactive version)&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;In this blog we have learned how to get complex data types from a WebAssembly module using Emscripten bindings and how to write a Vega-Lite specifications to get interactive visualizations.&lt;/p&gt;
&lt;p&gt;Other blogs of the series that might be of interest&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;Interact with your C++ web app using React forms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in a &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application.&lt;/p&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_q33p383lsb3jlUV9-ca283010.CJQRcRqz.jpg" medium="image"/><author>eScience Editorial Team</author></item><item><title>Using C++ in a web app with WebAssembly</title><link>https://blog.esciencecenter.nl/posts/2020-10-09---using-c-in-a-web-app-with-webassembly</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-10-09---using-c-in-a-web-app-with-webassembly</guid><description>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let’s say you have some C++ code laying around that you would like to make available to a wider audience, by putting it on the web as a ready to use web tool. Until recently, this used to be pretty difficult, and may even have required reimplementation of the software in JavaScript, the programming language that browsers use.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Wouldn’t it be great if you could run your existing C++ code on the web with only minor effort?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That way, loads more people would be able to see your results, interact with your algorithm, and apply it for their own purposes.&lt;/p&gt;
&lt;p&gt;In this blog, we’ll show you how to take a simple algorithm written in C++ and make it available as a web application. Subsequent blogs in this series will expand on the current one by laying out more advanced topics, specifically how to &lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;make the app interactive&lt;/a&gt;, how to &lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;visualize the results&lt;/a&gt;, and how to &lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;deal with long running tasks&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;root-finding&quot;&gt;Root finding&lt;/h2&gt;
&lt;p&gt;So today’s aim is to have a simple web app that determines the root of a mathematical function &lt;em&gt;2x³ — 4x² + 6&lt;/em&gt;, i.e. the value of &lt;em&gt;x&lt;/em&gt; where &lt;em&gt;y = 0&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;857&quot; height=&quot;880&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RUHNAgWlcRCfGzf1-8a8b79de.BjAjlaJh_2u6jK4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Function 2x³ — 4x² + 6.&lt;/p&gt;
&lt;p&gt;For this, we’ll use an iterative method known as the &lt;a href=&quot;https://www.youtube.com/watch?v=cOmAk82cr9M&quot;&gt;&lt;em&gt;Newton-Raphson&lt;/em&gt; root finding method&lt;/a&gt;. Remember Newton? Quiet fellow, fabulous hair? Yes, &lt;em&gt;that&lt;/em&gt; Newton. The way Newton-Raphson works is, you give it the equation whose root you want to find, along with the derivative of that equation. Then you take an &lt;code&gt;initial_guess&lt;/code&gt; of what you think the value of the root could be, then let the method iterate towards the solution. The solution is approximate within a &lt;code&gt;tolerance&lt;/code&gt;, which you can also set. Anyway, the algorithm is written C++, but &lt;strong&gt;with some trickery, we’ll be able to use that C++ code from the browser, without the need to port it first&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1275&quot; height=&quot;1777&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_GL19nE2yCZ-loY6y-2b0130c2.CGMtxH0u_ZFBCi1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Newton (and his hair). Image courtesy of Wikimedia Commons.&lt;/p&gt;
&lt;p&gt;Now before you say &lt;em&gt;“That’ll be so much slower than running it native!”&lt;/em&gt; or &lt;em&gt;“C++ from the browser? Impossible!”&lt;/em&gt;, just hold your horses for a sec. With the right tools, it is possible to run C++ code in the browser, with an acceptable performance penalty. For example, Gabriel Cuvillier was able to run the video game &lt;em&gt;Doom 3&lt;/em&gt; &lt;a href=&quot;http://wasm.continuation-labs.com/d3demo/&quot;&gt;in the browser&lt;/a&gt;. He was able to do this by compiling the game’s source code into WebAssembly, a low-level language that browsers can run. And if it works for video games, it will likely work for your research software, too.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;910&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_WILEEGqVA7Izb05c-277ca307.CDJdkOwM_23fGz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Hold your horses. Image courtesy of Luciano Marelli via pixabay.&lt;/p&gt;
&lt;h2 id=&quot;what-well-need&quot;&gt;What we’ll need&lt;/h2&gt;
&lt;p&gt;OK, now that you’re fully on board with this, let’s get to it. Here’s a list of what we need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We are going to write a small HTML page, so you will need basic knowledge of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics&quot;&gt;HTML&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript&quot;&gt;JavaScript&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some C++ code to illustrate the process. We’ll use our Newton-Raphson C++ code.&lt;/li&gt;
&lt;li&gt;A program ==that== can take our existing C++ code and compile it into a WebAssembly module. For this, we’ll use &lt;a href=&quot;https://emscripten.org/&quot;&gt;Emscripten&lt;/a&gt; ’s &lt;code&gt;emcc&lt;/code&gt; compiler, the most popular C++ to WebAssembly compiler of the bunch.&lt;/li&gt;
&lt;li&gt;To use the WebAssembly functionality from JavaScript, a binding is required. The binding will map C++ constructs to their JavaScript equivalent and back. For this, we’ll use &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#embind&quot;&gt;embind&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A web server to serve our files. We’ll use Python 3’s &lt;code&gt;http.server&lt;/code&gt;, but other web servers work equally well.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;tying-it-all-together&quot;&gt;Tying it all together&lt;/h2&gt;
&lt;h3 id=&quot;the-c-code&quot;&gt;The C++ code&lt;/h3&gt;
&lt;p&gt;Here is the equation whose root we want to find, along with its derivative, since that’s what Newton-Raphson requires:&lt;/p&gt;
&lt;p&gt;File: problem.hpp&lt;/p&gt;
&lt;p&gt;File: problem.cpp&lt;/p&gt;
&lt;p&gt;The snippet below shows the contents of the file &lt;code&gt;newtonraphson.hpp&lt;/code&gt;. It is the header file for the Newton-Raphson iterative root finding algorithm. It defines a class named &lt;code&gt;NewtonRaphson&lt;/code&gt;. Besides the constructor method &lt;code&gt;NewtonRaphson(float tolerance_in)&lt;/code&gt;, &lt;code&gt;NewtonRaphson&lt;/code&gt; has one other public method, &lt;code&gt;solve&lt;/code&gt;, which takes a &lt;code&gt;float&lt;/code&gt;, and returns another &lt;code&gt;float&lt;/code&gt;. Furthermore, &lt;code&gt;NewtonRaphson&lt;/code&gt; also has a private member, &lt;code&gt;tolerance&lt;/code&gt; of type &lt;code&gt;float&lt;/code&gt;, which is used to store the class instance’s private data.&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.hpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;File &lt;code&gt;newtonraphson.cpp&lt;/code&gt; contains the corresponding implementation:&lt;/p&gt;
&lt;p&gt;File: newtonraphson.cpp&lt;/p&gt;
&lt;p&gt;From this definition, &lt;code&gt;NewtonRaphson&lt;/code&gt; instances need to be initialized with a value for &lt;code&gt;tolerance_in&lt;/code&gt;, which is then stored as the private member &lt;code&gt;tolerance&lt;/code&gt;. Once the object instance has been constructed, users can call its &lt;code&gt;solve&lt;/code&gt; method to iteratively find &lt;code&gt;equation&lt;/code&gt; ‘s root, with &lt;code&gt;equation&lt;/code&gt; and its &lt;code&gt;derivative&lt;/code&gt; being imported from &lt;code&gt;problem.hpp&lt;/code&gt; via the &lt;code&gt;include&lt;/code&gt; line near the top.&lt;/p&gt;
&lt;h3 id=&quot;check-on-command-line&quot;&gt;Check on command line&lt;/h3&gt;
&lt;p&gt;The following code is a minimal command line program that we can use to check if everything is working correctly:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;cli.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our command line program can be compiled with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Subsequently running it should give the following output:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;./&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;The&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the root is &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’re ready to move on to the WebAssembly part.&lt;/p&gt;
&lt;h3 id=&quot;binding&quot;&gt;Binding&lt;/h3&gt;
&lt;p&gt;To use the Newton-Raphson code from JavaScript, we’ll need to define the &lt;em&gt;bindings&lt;/em&gt; file. The binding allows compiled code to be called from JavaScript. For our Newton-Raphson code, the binding file looks like this:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;bindings.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The binding file uses &lt;code&gt;embind&lt;/code&gt; &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#classes&quot;&gt;binding statements&lt;/a&gt; to expose the &lt;code&gt;NewtonRaphson&lt;/code&gt; class, its constructor method, as well as its public method &lt;code&gt;solve&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;compiling-to-webassembly&quot;&gt;Compiling to WebAssembly&lt;/h3&gt;
&lt;p&gt;First we need to &lt;a href=&quot;https://emscripten.org/docs/getting_started/downloads.html&quot;&gt;download and install&lt;/a&gt; Emscripten to get the compiler. The Newton-Raphson source and its binding can be compiled into a WebAssembly module with Emscripten’s &lt;code&gt;emcc&lt;/code&gt; compiler, as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;emcc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;I.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;js &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Oz&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;EXPORT_NAME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;createModule &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--bind \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp bindings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate a WebAssembly module &lt;code&gt;newtonraphson.wasm&lt;/code&gt;, along with a JavaScript file &lt;code&gt;newtonraphson.js&lt;/code&gt;. We also export the &lt;code&gt;createModule&lt;/code&gt; JavaScript function in the compile command so it can be used to load and initialize the WebAssembly ==module==. Using the &lt;code&gt;newtonraphson.js&lt;/code&gt; JavaScript library, we can find the root of the mathematical function, and subsequently display its value with the following HTML:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;index.html&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;hosting-the-app-with-a-web-server&quot;&gt;Hosting the app with a web server&lt;/h3&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the &lt;a href=&quot;https://docs.python.org/3/library/http.server.html&quot;&gt;http.server&lt;/a&gt; module from Python 3 to host all files in the current directory on port 8000, like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# change to directory with index.html and newtonraphson.* files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the figure at the top of the article, the root of the equation should be at &lt;code&gt;x = -1.00&lt;/code&gt;. Visit &lt;a href=&quot;http://localhost:8000/&quot;&gt;http://localhost:8000/&lt;/a&gt; to see if your browser shows the correct result.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;212&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_sgmpFtqMZRHKIBW4-19d2b6c1.lHGtXvuX_28fnXD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The resulting page if everything works. See the live version of the app on GitHub pages.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;We wrote a simple algorithm in C++&lt;/li&gt;
&lt;li&gt;We defined the JavaScript interface by writing Emscripten bindings&lt;/li&gt;
&lt;li&gt;We compiled the algorithm and bindings to a WebAssembly module with Emscripten compiler&lt;/li&gt;
&lt;li&gt;We ran the algorithm in a web browser using some JavaScript to talk to the WebAssembly module.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The nice thing about this solution is that we don’t need expensive infrastructure to perform computation as the computation is done in the user’s web browser — we just need somewhere to host the files.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to go from here?&lt;/h2&gt;
&lt;p&gt;In upcoming blogs we will cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;: how to perform computations without blocking the user interface.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;Interact with your C++ web app using React forms&lt;/a&gt;: how to let the user supply their own input values for &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;Spice up your C++ web app with visualizations&lt;/a&gt;: how to visualize data from the algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;a final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application. If you’re curious what that’s going to look like, make sure to check out the &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html&quot;&gt;live demo&lt;/a&gt; on GitHub Pages.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Thank you to our proof readers&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-8002-5459&quot;&gt;&lt;em&gt;Jan van Dijk&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://github.com/DAANBOER&quot;&gt;&lt;em&gt;Daan Boer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-6311-1168&quot;&gt;&lt;em&gt;Lourens Veen&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-6033-960X&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</description><pubDate>Fri, 09 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;By&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5821-2060&quot;&gt;&lt;em&gt;Stefan Verhoeven&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-0989-929X&quot;&gt;&lt;em&gt;Faruk Diblen&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-7064-4069&quot;&gt;&lt;em&gt;Jurriaan H. Spaaks&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-6306-6937&quot;&gt;&lt;em&gt;Adam Belloum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-5529-5761&quot;&gt;&lt;em&gt;Christiaan Meijer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let’s say you have some C++ code laying around that you would like to make available to a wider audience, by putting it on the web as a ready to use web tool. Until recently, this used to be pretty difficult, and may even have required reimplementation of the software in JavaScript, the programming language that browsers use.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Wouldn’t it be great if you could run your existing C++ code on the web with only minor effort?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That way, loads more people would be able to see your results, interact with your algorithm, and apply it for their own purposes.&lt;/p&gt;
&lt;p&gt;In this blog, we’ll show you how to take a simple algorithm written in C++ and make it available as a web application. Subsequent blogs in this series will expand on the current one by laying out more advanced topics, specifically how to &lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;make the app interactive&lt;/a&gt;, how to &lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;visualize the results&lt;/a&gt;, and how to &lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;deal with long running tasks&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;root-finding&quot;&gt;Root finding&lt;/h2&gt;
&lt;p&gt;So today’s aim is to have a simple web app that determines the root of a mathematical function &lt;em&gt;2x³ — 4x² + 6&lt;/em&gt;, i.e. the value of &lt;em&gt;x&lt;/em&gt; where &lt;em&gt;y = 0&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;857&quot; height=&quot;880&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_RUHNAgWlcRCfGzf1-8a8b79de.BjAjlaJh_2u6jK4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Function 2x³ — 4x² + 6.&lt;/p&gt;
&lt;p&gt;For this, we’ll use an iterative method known as the &lt;a href=&quot;https://www.youtube.com/watch?v=cOmAk82cr9M&quot;&gt;&lt;em&gt;Newton-Raphson&lt;/em&gt; root finding method&lt;/a&gt;. Remember Newton? Quiet fellow, fabulous hair? Yes, &lt;em&gt;that&lt;/em&gt; Newton. The way Newton-Raphson works is, you give it the equation whose root you want to find, along with the derivative of that equation. Then you take an &lt;code&gt;initial_guess&lt;/code&gt; of what you think the value of the root could be, then let the method iterate towards the solution. The solution is approximate within a &lt;code&gt;tolerance&lt;/code&gt;, which you can also set. Anyway, the algorithm is written C++, but &lt;strong&gt;with some trickery, we’ll be able to use that C++ code from the browser, without the need to port it first&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1275&quot; height=&quot;1777&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_GL19nE2yCZ-loY6y-2b0130c2.CGMtxH0u_ZFBCi1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Newton (and his hair). Image courtesy of Wikimedia Commons.&lt;/p&gt;
&lt;p&gt;Now before you say &lt;em&gt;“That’ll be so much slower than running it native!”&lt;/em&gt; or &lt;em&gt;“C++ from the browser? Impossible!”&lt;/em&gt;, just hold your horses for a sec. With the right tools, it is possible to run C++ code in the browser, with an acceptable performance penalty. For example, Gabriel Cuvillier was able to run the video game &lt;em&gt;Doom 3&lt;/em&gt; &lt;a href=&quot;http://wasm.continuation-labs.com/d3demo/&quot;&gt;in the browser&lt;/a&gt;. He was able to do this by compiling the game’s source code into WebAssembly, a low-level language that browsers can run. And if it works for video games, it will likely work for your research software, too.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;910&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_WILEEGqVA7Izb05c-277ca307.CDJdkOwM_23fGz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Hold your horses. Image courtesy of Luciano Marelli via pixabay.&lt;/p&gt;
&lt;h2 id=&quot;what-well-need&quot;&gt;What we’ll need&lt;/h2&gt;
&lt;p&gt;OK, now that you’re fully on board with this, let’s get to it. Here’s a list of what we need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We are going to write a small HTML page, so you will need basic knowledge of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics&quot;&gt;HTML&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript&quot;&gt;JavaScript&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some C++ code to illustrate the process. We’ll use our Newton-Raphson C++ code.&lt;/li&gt;
&lt;li&gt;A program ==that== can take our existing C++ code and compile it into a WebAssembly module. For this, we’ll use &lt;a href=&quot;https://emscripten.org/&quot;&gt;Emscripten&lt;/a&gt; ’s &lt;code&gt;emcc&lt;/code&gt; compiler, the most popular C++ to WebAssembly compiler of the bunch.&lt;/li&gt;
&lt;li&gt;To use the WebAssembly functionality from JavaScript, a binding is required. The binding will map C++ constructs to their JavaScript equivalent and back. For this, we’ll use &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#embind&quot;&gt;embind&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A web server to serve our files. We’ll use Python 3’s &lt;code&gt;http.server&lt;/code&gt;, but other web servers work equally well.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;tying-it-all-together&quot;&gt;Tying it all together&lt;/h2&gt;
&lt;h3 id=&quot;the-c-code&quot;&gt;The C++ code&lt;/h3&gt;
&lt;p&gt;Here is the equation whose root we want to find, along with its derivative, since that’s what Newton-Raphson requires:&lt;/p&gt;
&lt;p&gt;File: problem.hpp&lt;/p&gt;
&lt;p&gt;File: problem.cpp&lt;/p&gt;
&lt;p&gt;The snippet below shows the contents of the file &lt;code&gt;newtonraphson.hpp&lt;/code&gt;. It is the header file for the Newton-Raphson iterative root finding algorithm. It defines a class named &lt;code&gt;NewtonRaphson&lt;/code&gt;. Besides the constructor method &lt;code&gt;NewtonRaphson(float tolerance_in)&lt;/code&gt;, &lt;code&gt;NewtonRaphson&lt;/code&gt; has one other public method, &lt;code&gt;solve&lt;/code&gt;, which takes a &lt;code&gt;float&lt;/code&gt;, and returns another &lt;code&gt;float&lt;/code&gt;. Furthermore, &lt;code&gt;NewtonRaphson&lt;/code&gt; also has a private member, &lt;code&gt;tolerance&lt;/code&gt; of type &lt;code&gt;float&lt;/code&gt;, which is used to store the class instance’s private data.&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;newtonraphson.hpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;File &lt;code&gt;newtonraphson.cpp&lt;/code&gt; contains the corresponding implementation:&lt;/p&gt;
&lt;p&gt;File: newtonraphson.cpp&lt;/p&gt;
&lt;p&gt;From this definition, &lt;code&gt;NewtonRaphson&lt;/code&gt; instances need to be initialized with a value for &lt;code&gt;tolerance_in&lt;/code&gt;, which is then stored as the private member &lt;code&gt;tolerance&lt;/code&gt;. Once the object instance has been constructed, users can call its &lt;code&gt;solve&lt;/code&gt; method to iteratively find &lt;code&gt;equation&lt;/code&gt; ‘s root, with &lt;code&gt;equation&lt;/code&gt; and its &lt;code&gt;derivative&lt;/code&gt; being imported from &lt;code&gt;problem.hpp&lt;/code&gt; via the &lt;code&gt;include&lt;/code&gt; line near the top.&lt;/p&gt;
&lt;h3 id=&quot;check-on-command-line&quot;&gt;Check on command line&lt;/h3&gt;
&lt;p&gt;The following code is a minimal command line program that we can use to check if everything is working correctly:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;cli.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our command line program can be compiled with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Subsequently running it should give the following output:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;./&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cli&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;The&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; the root is &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’re ready to move on to the WebAssembly part.&lt;/p&gt;
&lt;h3 id=&quot;binding&quot;&gt;Binding&lt;/h3&gt;
&lt;p&gt;To use the Newton-Raphson code from JavaScript, we’ll need to define the &lt;em&gt;bindings&lt;/em&gt; file. The binding allows compiled code to be called from JavaScript. For our Newton-Raphson code, the binding file looks like this:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;bindings.cpp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The binding file uses &lt;code&gt;embind&lt;/code&gt; &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#classes&quot;&gt;binding statements&lt;/a&gt; to expose the &lt;code&gt;NewtonRaphson&lt;/code&gt; class, its constructor method, as well as its public method &lt;code&gt;solve&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;compiling-to-webassembly&quot;&gt;Compiling to WebAssembly&lt;/h3&gt;
&lt;p&gt;First we need to &lt;a href=&quot;https://emscripten.org/docs/getting_started/downloads.html&quot;&gt;download and install&lt;/a&gt; Emscripten to get the compiler. The Newton-Raphson source and its binding can be compiled into a WebAssembly module with Emscripten’s &lt;code&gt;emcc&lt;/code&gt; compiler, as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;emcc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;I.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;o newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;js &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Oz&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;EXPORT_NAME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;createModule &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;--bind \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; problem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp newtonraphson&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp bindings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate a WebAssembly module &lt;code&gt;newtonraphson.wasm&lt;/code&gt;, along with a JavaScript file &lt;code&gt;newtonraphson.js&lt;/code&gt;. We also export the &lt;code&gt;createModule&lt;/code&gt; JavaScript function in the compile command so it can be used to load and initialize the WebAssembly ==module==. Using the &lt;code&gt;newtonraphson.js&lt;/code&gt; JavaScript library, we can find the root of the mathematical function, and subsequently display its value with the following HTML:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;index.html&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;hosting-the-app-with-a-web-server&quot;&gt;Hosting the app with a web server&lt;/h3&gt;
&lt;p&gt;We’ll need a web server to display the HTML page in a web browser. For this, we’ll use the &lt;a href=&quot;https://docs.python.org/3/library/http.server.html&quot;&gt;http.server&lt;/a&gt; module from Python 3 to host all files in the current directory on port 8000, like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;# change to directory with index.html and newtonraphson.* files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;python3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;m http&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the figure at the top of the article, the root of the equation should be at &lt;code&gt;x = -1.00&lt;/code&gt;. Visit &lt;a href=&quot;http://localhost:8000/&quot;&gt;http://localhost:8000/&lt;/a&gt; to see if your browser shows the correct result.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;640&quot; height=&quot;212&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_sgmpFtqMZRHKIBW4-19d2b6c1.lHGtXvuX_28fnXD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The resulting page if everything works. See the live version of the app on GitHub pages.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;We wrote a simple algorithm in C++&lt;/li&gt;
&lt;li&gt;We defined the JavaScript interface by writing Emscripten bindings&lt;/li&gt;
&lt;li&gt;We compiled the algorithm and bindings to a WebAssembly module with Emscripten compiler&lt;/li&gt;
&lt;li&gt;We ran the algorithm in a web browser using some JavaScript to talk to the WebAssembly module.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The nice thing about this solution is that we don’t need expensive infrastructure to perform computation as the computation is done in the user’s web browser — we just need somewhere to host the files.&lt;/p&gt;
&lt;h2 id=&quot;get-in-touch-with-us&quot;&gt;Get in touch with us&lt;/h2&gt;
&lt;p&gt;This blog was written by the Generalization Team of the Netherlands eScience Center. The team consists of Stefan Verhoeven, Faruk Diblen, Jurriaan H. Spaaks, Adam Belloum and Christiaan Meijer. Feel free to get in touch with the generalization team at &lt;a href=&quot;mailto:generalization@esciencecenter.nl&quot;&gt;generalization@esciencecenter.nl&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to go from here?&lt;/h2&gt;
&lt;p&gt;In upcoming blogs we will cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/help-my-c-web-app-is-not-responding-b930ca3034ad&quot;&gt;Help! My C++ web app is not responding&lt;/a&gt;: how to perform computations without blocking the user interface.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/interact-with-your-c-web-app-using-react-forms-543e676a7634&quot;&gt;Interact with your C++ web app using React forms&lt;/a&gt;: how to let the user supply their own input values for &lt;code&gt;tolerance&lt;/code&gt; and &lt;code&gt;initial_guess&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@eScienceCenter/spice-up-your-c-web-app-with-visualizations-bcc1e888ec25&quot;&gt;Spice up your C++ web app with visualizations&lt;/a&gt;: how to visualize data from the algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll wrap up the series in &lt;a href=&quot;https://medium.com/@eScienceCenter/c-web-app-with-webassembly-vega-web-worker-and-react-1e5b750c88df&quot;&gt;a final blog&lt;/a&gt; that combines the topics of the whole series in a full-featured web application. If you’re curious what that’s going to look like, make sure to check out the &lt;a href=&quot;https://nlesc-jcer.github.io/run-cpp-on-web/kitchen-sink/app.html&quot;&gt;live demo&lt;/a&gt; on GitHub Pages.&lt;/p&gt;
&lt;p&gt;If you enjoyed this article, leave a comment and give us a clap!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;These blogs were written as part of the “Passing XSAMS” project. To learn more about the project, check out its&lt;/em&gt; &lt;a href=&quot;https://www.esciencecenter.nl/projects/passing-xsams/&quot;&gt;&lt;em&gt;project page&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Thank you to our proof readers&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0001-8002-5459&quot;&gt;&lt;em&gt;Jan van Dijk&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://github.com/DAANBOER&quot;&gt;&lt;em&gt;Daan Boer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-6311-1168&quot;&gt;&lt;em&gt;Lourens Veen&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;https://orcid.org/0000-0002-6033-960X&quot;&gt;&lt;em&gt;Patrick Bos&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://blog.esciencecenter.nl/_astro/0_RUHNAgWlcRCfGzf1-8a8b79de.BjAjlaJh.webp" medium="image"/><author>eScience Editorial Team</author></item><item><title>Use-after-free? No more with Valgrind</title><link>https://blog.esciencecenter.nl/posts/2020-09-28---use-after-free-no-more-with-valgrind</link><guid isPermaLink="true">https://blog.esciencecenter.nl/posts/2020-09-28---use-after-free-no-more-with-valgrind</guid><description>&lt;p&gt;In my long career as a code detective, I have seen it all. I have travelled the high Cs, found Rubies and wrestled Pythons, and walked the alleyways of Fortran at night. Of course, as with any job most cases are run-of-the-mill, but some of them are not. Those are the ones you remember. The ones you tell your grandchildren about, if you live to tell the tale.&lt;/p&gt;
&lt;p&gt;This is the story of a programming mistake that caused a C++ program to crash, and how it was fixed using &lt;a href=&quot;https://valgrind.org/&quot;&gt;Valgrind&lt;/a&gt;. It features mysterious artefacts, C++ memory management, and fixing and avoiding mistakes in (scientific) software. I hope it will teach you something about use-after-free issues, and inspire you to try Valgrind for memory debugging next time you have a similar problem. Let’s dive right in, shall we?&lt;/p&gt;
&lt;h2 id=&quot;the-curious-case-of-the-crashing-simulation&quot;&gt;The Curious Case of the Crashing Simulation&lt;/h2&gt;
&lt;p&gt;It was a dark and stormy ni…no wait, it was actually a sunny afternoon in spring, when I received an email from a scientist named Pavel. Pavel is a postdoc at the University of Amsterdam and the Erasmus University Medical Center in Rotterdam, and he was working on porting a rather complicated computer simulation of something called an &lt;a href=&quot;https://en.wikipedia.org/wiki/Restenosis&quot;&gt;In-Stent Restenosis&lt;/a&gt; to &lt;a href=&quot;https://github.com/multiscale/muscle3&quot;&gt;MUSCLE3&lt;/a&gt;. His program was crashing. And he suspected the problem was with MUSCLE3. Which I created and currently maintain. Which would mean… &lt;em&gt;DUH-DUH-DUUUUUH&lt;/em&gt; (organ sound effect) &lt;em&gt;THERE WAS A MISTAKE IN MY CODE&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;By the way, why can’t you include sound effects in blog posts? I think blog posts are much better with sound effects. Someone should fix this. Meanwhile, here’s an image depicting the horror:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An ink drawing of a face with its eyes and mouth wide open in horror. It is flanked by raised arms on both sides.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;982&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_g4Uw0OcyPSJMyeKP-89e7e8c7.D3nu8NeI_ZgkqUt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;“The Scream” Undated drawing by Edvard Munch (via Wikipedia )&lt;/p&gt;
&lt;p&gt;Anyway, yes, there was a mistake in MUSCLE3. But to explain the problem, I need to explain what MUSCLE3 does first. MUSCLE3 is a coupling system for multiscale simulations. In a multiscale simulation, a part of the world is simulated in which multiple processes take place, and where some of those processes are much smaller and/or faster than others.&lt;/p&gt;
&lt;p&gt;In this particular simulation, there are some slow-growing cells (simulated using agents), and some fast-moving blood (simulated using computational fluid dynamics). This is not that relevant, but it is fortunate, because what’s a hard-boiled detective story without some fast-moving blood? Anyway, each process is simulated by a separate computer program, and the programs exchange information by sending messages back and forth. This communication is one of the things MUSCLE3 helps with. And now Pavel was saying that whenever he received a large message, his simulation crashed.&lt;/p&gt;
&lt;p&gt;Messages in MUSCLE3 contain data, and that data can be of a range of types, including the standard built-in types such as strings and integers, but also lists, dictionaries, and grids (arrays) of numbers. You don’t need to tell MUSCLE3 what you’re going to send, you just build a &lt;code&gt;Message&lt;/code&gt; object containing whatever kind of data you want to send, and pass it to MUSCLE3, and on the other side the receiver receives a &lt;code&gt;Message&lt;/code&gt; object containing the same data.&lt;/p&gt;
&lt;p&gt;For a dynamic language like Python, this is all simple enough, but, dear reader, this case would prove to be much more complicated. Pavel’s model was not written in Python. It was written in… &lt;em&gt;DUH-DUH-DUUUUUH&lt;/em&gt; C++!&lt;/p&gt;
&lt;p&gt;See? I told you, sound effects. They make things better.&lt;/p&gt;
&lt;p&gt;Anyway, C++ is a statically typed language. C++ programs are &lt;em&gt;compiled&lt;/em&gt; into an executable file, which is then run in a second step. In C++, each variable can only store values of a particular type (e.g. strings, or integers), and that type must be known when the program is compiled. Of course, we don’t know the type of the data in a message until we receive that message, which happens when the program is running, which comes &lt;em&gt;after&lt;/em&gt; it is compiled. So there is a problem.&lt;/p&gt;
&lt;p&gt;To solve this, the C++ API of MUSCLE3 has a &lt;code&gt;Data&lt;/code&gt; class. Variables of type &lt;code&gt;Data&lt;/code&gt; can contain an object of any type that MUSCLE3 can send and receive. In your C++ code, you can ask the &lt;code&gt;Data&lt;/code&gt; object which type of data it contains, and extract an object of that type. If the data is a grid (for instance because the sender is a Python program that sent you a NumPy array), then you can obtain a pointer to the raw array of elements using the &lt;code&gt;elements()&lt;/code&gt; member function of &lt;code&gt;Data&lt;/code&gt; (C++ doesn’t have a standard multi-dimensional array class, so this is the best we can do).&lt;/p&gt;
&lt;p&gt;That is exactly what Pavel did: he called that function, then copied the elements into another data structure. And then his program crashed. At least, it crashed if the grid was large, a test program receiving a small test grid with only a handful of elements worked fine. Which makes no sense, because MUSCLE3 treats large and small grids exactly the same.&lt;/p&gt;
&lt;p&gt;And thus, our mystery. Why did it crash? Why only for large grids? How should it be fixed? How do we keep this from happening again in the future?&lt;/p&gt;
&lt;h2 id=&quot;detective-its-what-you-are-not-what-you-do&quot;&gt;Detective. It’s what you are, not what you do.&lt;/h2&gt;
&lt;p&gt;It was time to get to work. I collected my hat and put on my trench coat, then dialled in the combination on my wall safe. This job would require some tools. My gaze swept across my collection, carefully assembled over the years. On the left, there were two boxes of print statements. One contained a large pile of cheap plastic mass-produced ones, the other was a velvet-lined display case showcasing a set of two exquisite hand-made examples, made in Japan during the Kamakura period and razor-sharp. While the pride of my collection, and the pinnacle of debugging tools in their time, I would need something more modern for this.&lt;/p&gt;
&lt;p&gt;Next were the linters. They would only protect me from Python formatting issues however. Useless, in this case. A debugger then, maybe? My safe contained a perfectly good copy of gdb, but the truth is that it’s kind of uncomfortable to use. Also, it’s more suited to logic problems than to finding the cause of crashes. I put it aside for now.&lt;/p&gt;
&lt;p&gt;I moved on to a shiny white box. AddressSanitizer it said on the top, in colourful letters. That could work. I’d never liked the sterility of it however. It was too neat, too perfect. A tool of the Empire. No. No, for this job, I would need the final box. A steel chest rather, decorated with ancient runic symbols and adorned with the word &lt;em&gt;Valgrind&lt;/em&gt; in large, Gothic script. Gateway to Valhalla, the great hall where brave programmers go after they retire to await Ragnarök, the end of times when hardware issues and compiler bugs arise for one final epic debugging session before the Great Simulation is rebooted. Yes, Valgrind. I took the chest, put it on my desk, opened it. Removed the gleaming artefact, and put it in my pocket. I was ready to go.&lt;/p&gt;
&lt;p&gt;(If the above procedure sounds a bit over-the-top, &lt;code&gt;apt-get install valgrind&lt;/code&gt; will work just fine as well.)&lt;/p&gt;
&lt;p&gt;It was only a short walk to the site of the crime, a &lt;a href=&quot;https://github.com/multiscale/muscle3&quot;&gt;large building&lt;/a&gt; with the word &lt;code&gt;git&lt;/code&gt; on a sign at the entrance. I walked in and asked the receptionist to see MUSCLE3. She gave me a nasty look. Understandable, given the fact that I look ridiculous in a hat, and that no one has worn a beige trench coat since the 1980’s unless they were a dirty old man. But, having explained that I was in fact a detective, I was waved on and soon found myself in a room with a series of filing cabinets. It was time to start my investigation.&lt;/p&gt;
&lt;p&gt;First, I looked at a cabinet labelled &lt;code&gt;libmuscle/cpp/src/libmuscle/tests&lt;/code&gt;. I knew that there had to be a test which tested that grids could be sent and received. In fact there was; a file conveniently named &lt;code&gt;test_data.cpp&lt;/code&gt; contained a large number of tests for &lt;code&gt;Data&lt;/code&gt; objects, including ones for various aspects of using grids. One of those did exactly what Pavel did. I ran the tests to be sure, and they passed just fine.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OK&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;120&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_serialisation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OK&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_serialisation (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ms)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, the test only used a small grid. I modified it to use a larger grid. Re-ran the tests. And sure enough…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Segmentation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fault (core dumped)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, I had verified that indeed there had been a crime, erm, that there was a mistake in my code. But where? It was time to deploy Valgrind. I modified the &lt;code&gt;Makefile&lt;/code&gt; that runs the tests to run &lt;code&gt;valgrind &amp;#x3C;test_executable&gt;&lt;/code&gt; instead of just &lt;code&gt;&amp;#x3C;test_executable&gt;&lt;/code&gt;. Having thus installed the Valgrind onto the filing cabinet, I took cover behind another cabinet filled with Fortran code (heavy, voluminous, and in this case auto-generated and therefore expendable) and restarted the test suite.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An arch-shaped angular metal object with a letter V and two viking heads on it sits on top of a wooden cabinet.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_oGKL4SYDYiHd9ggSmp_mpw-7c311286.ChVArLxo_ZqH1yL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Valgrind in action&lt;/p&gt;
&lt;p&gt;As the first tests ran, a bluish light filled the room and the ancient artefact started vibrating, emitting a faint hum of approval. Then, suddenly, a horrifying screech emanated from it.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Invalid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; read &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13F848&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::CmpHelperEQ&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1444&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1368DF&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::EqHelper&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::Compare&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1472&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1288B1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle_mcp_data_grid_Test&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::TestBody&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (test_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;526&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1A21E6&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::HandleSehExceptionsInMethodIfSupported&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, void (testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test::*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x19C810&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::HandleExceptionsInMethodIfSupported&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, void (testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test::*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x17BBBB&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::Test::Run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (in muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x17C518&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::TestInfo::Run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (in muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x17CB9B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::TestCase::Run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (in muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x187987&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl::RunAllTests&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (in muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1A32F8&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bool testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::HandleSehExceptionsInMethodIfSupported&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool (testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl::*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x19D576&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bool testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::HandleExceptionsInMethodIfSupported&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool (testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTestImpl::*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x18640F&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::UnitTest::Run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (in muscle3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tests&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;test_data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Address&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0x6488628&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; is &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bytes inside a block &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;262&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;152&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; free&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x4C30D3B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; free (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;usr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;valgrind&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vgpreload_memcheck&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amd64&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;linux&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13317B&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chunk_list&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::~&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chunk_list&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (cpp11_zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;127&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13554D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::~&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (cpp11_zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;27&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x152D7D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void __gnu_cxx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;new_allocator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (new_allocator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;140&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x152D50&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocator_traits&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (alloc_traits&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;487&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1520AA&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Sp_counted_ptr_inplace&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone, std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (__gnu_cxx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Lock_policy)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_M_dispose&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (shared_ptr_base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;535&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13A385&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Sp_counted_base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(__gnu_cxx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Lock_policy)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_M_release&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (shared_ptr_base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;154&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x135CCC&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;__shared_count&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(__gnu_cxx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Lock_policy)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::~&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;__shared_count&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (shared_ptr_base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;684&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1345AF&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;__shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone, (__gnu_cxx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Lock_policy)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::~&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;__shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (shared_ptr_base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1123&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1345CB&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::~&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;93&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x14E99D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Destroy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (stl_construct&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;98&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x14DE43&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;_Destroy_aux&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;__destroy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;*&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (stl_construct&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;108&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Block&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; was alloc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x4C2FB0F&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; malloc (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;usr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;valgrind&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;vgpreload_memcheck&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amd64&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;linux&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;so)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13335A&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocate_expand(unsigned long) (cpp11_zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;281&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x133280&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;allocate_align(unsigned long, unsigned long) (cpp11_zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;245&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x157F74&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;visit_bin(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned int) (create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;133&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x165DC3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;parse_helper&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;execute(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, unsigned long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (parse&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;584&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x162A3D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;parse_helper&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;execute(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, unsigned long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (parse&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1027&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x160F33&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;parse_return msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;parse_imp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, unsigned long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;create_object_visitor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (parse&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1044&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1587F5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_imp(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, unsigned long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;object_type, unsigned long, void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_limit const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (unpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;331&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x16C6BE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, unsigned long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, bool (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;object_type, unsigned long, void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_limit const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (unpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;141&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x16C766&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long, bool (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;object_type, unsigned long, void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_limit const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (unpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;hpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;182&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x16C5D8&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;mcp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_data(std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, unsigned long) (data_pack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;13&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1563C4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::DataConstRef::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_dict_&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const (data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;722&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It ended quickly, fortunately, and was replaced again by the soothing hum. When that too had faded away, I emerged from my shelter and approached the filing cabinet. The Valgrind felt warm to the touch, but it appeared to be intact. I took out my magnifying glass and inspected the symbols on its side.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Invalid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; read &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13F848&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::CmpHelperEQ&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1444&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1368DF&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::EqHelper&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::Compare&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1472&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1288B1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle_mcp_data_grid_Test&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::TestBody&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (test_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;526&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Invalid read of size 4. Apparently, the test had attempted to read a 4-byte variable in a memory location where there was none. I followed the backtrace, through some Google Test-related functions to my &lt;code&gt;test_data.cpp&lt;/code&gt;. Line 526 was where the invalid read had occurred. I checked the test’s code. Bingo. Exactly the place where the grid elements were accessed. I seemed to be on to something.&lt;/p&gt;
&lt;p&gt;At this point, there were several possible causes of the crash. Clearly, the pointer returned by the call to &lt;code&gt;elements()&lt;/code&gt; was bad, pointing to some memory that did not contain the requested elements. I read on.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Address&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0x6488628&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; is &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bytes inside a block &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;262&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;152&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; free&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;…&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Block&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; was alloc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;…&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1563C4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::DataConstRef::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_dict_&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const (data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;722&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That, in fact, told me enough to find the problem. But to understand what went wrong, we need to dive into the implementation of the &lt;code&gt;Data&lt;/code&gt; class for a bit.&lt;/p&gt;
&lt;h2 id=&quot;how-to-lose-your-users-data&quot;&gt;How to lose your users’ data&lt;/h2&gt;
&lt;p&gt;To send objects from one program to another, MUSCLE3 uses a binary data format called MessagePack. A MessagePack-encoded object is an array of bytes, which can be decoded to determine the type and value of the encoded value. For example, a message consisting of a single byte with value &lt;code&gt;33&lt;/code&gt; represents an integer with value 33. A single byte with value &lt;code&gt;195&lt;/code&gt; represents the Boolean value True, and &lt;code&gt;167 77 85 83 67 76 69 51&lt;/code&gt; encodes the string MUSCLE3 (167 starts a 7-byte string, and then there are the 7 characters’ ASCII values).&lt;/p&gt;
&lt;p&gt;MessagePack has fixed ways of encoding all the common basic types, as well as dictionaries and lists, but it doesn’t do (multidimensional) arrays. Fortunately, it has an extension mechanism, which lets you send an array of bytes accompanied by a one-byte tag that specifies what kind of object it represents. You are then free to represent your object as an array of bytes in any way you like. A common trick is to simply use MessagePack again to encode a dictionary or list containing some values which together represent the object. This is how MUSCLE3 sends grids.&lt;/p&gt;
&lt;p&gt;When MUSCLE3 receives a message, it calls an internal function to decode the received array of bytes. This function in turn calls the MessagePack library, which returns a library-specific object that represents the decoded value. This object is wrapped in a &lt;code&gt;Data&lt;/code&gt; object, and eventually returned to the user. When the user then asks this &lt;code&gt;Data&lt;/code&gt; object whether it contains a &lt;code&gt;Grid&lt;/code&gt;, it inspects its MessagePack-object to see whether it represents an extension type with the correct tag. If you ask for the elements, it has to actually decode the bytes still. It uses MessagePack to do that, creating another &lt;code&gt;Data&lt;/code&gt; object containing a dictionary that has the shape of the array and the elements (the difference between &lt;code&gt;Data&lt;/code&gt; and &lt;code&gt;DataConstRef&lt;/code&gt; is beyond the scope of this blog, you can consider them the same here).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DataConstRef&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; DataConstRef&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_dict_&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    auto ext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mp_obj_&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    auto oh &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack(ext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (oh&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::MAP&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        throw std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;runtime_error(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;Invalid grid format. Bug in MUSCLE 3?&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    auto zone &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;make_shared&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;msgpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;zone&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DataConstRef&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        mcp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;unpack_data(zone, ext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it has this &lt;code&gt;Data&lt;/code&gt; object, &lt;code&gt;elements()&lt;/code&gt; can extract the location of the elements from it and return the location to the user as a pointer of the appropriate type:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; DataConstRef&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;elements&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;is_a_grid_of&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        throw std&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;runtime_error(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;Tried to get grid data, but this object is not&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot; a grid or not of the correct type.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    char const &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; data_bytes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; grid_dict_&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;as_byte_array&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    return reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(data_bytes);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Valgrind said the following about this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Address&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0x6488628&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; is &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bytes inside a block &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;262&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;152&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; free&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;…&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Block&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; was alloc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;’&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;d at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;…&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1563C4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::DataConstRef::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_dict_&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; const (data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;722&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that the pointer returned by &lt;code&gt;elements()&lt;/code&gt; points to a variable that used to exist, but that had been deleted by the time the pointer was used by the test case. It also says that the deleted variable was created on the last line of the &lt;code&gt;grid_dict_()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;That makes it clear what happened: &lt;code&gt;elements()&lt;/code&gt; calls &lt;code&gt;grid_dict_()&lt;/code&gt;, which creates (as noted by Valgrind) and returns a &lt;code&gt;Data&lt;/code&gt; object containing the elements. A pointer to the elements is extracted (the &lt;code&gt;[&quot;data&quot;].as_byte_array()&lt;/code&gt; part in &lt;code&gt;elements()&lt;/code&gt;), and then, since it’s a temporary value and it’s not assigned to anything, the &lt;code&gt;Data&lt;/code&gt; object returned by &lt;code&gt;grid_dict_()&lt;/code&gt; is cleaned up. This deletes the dictionary including the elements from memory, leaving the pointer to point to something which no longer exists. The pointer is then returned to the user, who tries to access the nonexistent data, causing the program to crash (or not, sometimes).&lt;/p&gt;
&lt;p&gt;Accessing a variable which no longer exists is called a &lt;em&gt;use after free&lt;/em&gt; error and it can, but doesn’t have to, crash your program. Here’s why. The memory in your computer is divided up into blocks called segments, and each running program is assigned a data segment to work with. If it needs more memory, it can &lt;a href=&quot;https://linux.die.net/man/2/sbrk&quot;&gt;ask the operating system to increase the size of its data segment&lt;/a&gt;, and if it doesn’t need the extra memory any more, it can ask to shrink its data segment again so that other running programs can use the memory. If a program tries to read or write to memory outside of a segment assigned to it, the CPU will block the operation and then the operating system will shut down the program, citing a &lt;em&gt;segmentation fault&lt;/em&gt; or &lt;em&gt;segmentation violation&lt;/em&gt; (colloquially, a &lt;em&gt;segfault&lt;/em&gt;). It does this to protect other running programs, which would get messed up if their data is overwritten by their errant colleague.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_8SlZc56wbJqiw0AZmh0o_A-e222a716.Dh7zCyxb_Z2jK80M.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;An errant colleague trying to overwrite your data. At this point you may want to call a detective! Photo by Andrea Piacquadio from Pexels.&lt;/p&gt;
&lt;p&gt;Resizing the data segment is done by the C++ standard library behind the scenes, so you don’t have to do it by hand, you can just &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; variables (or better, use &lt;code&gt;std::make_unique()&lt;/code&gt; and &lt;code&gt;std::make_shared()&lt;/code&gt;). The standard library typically doesn’t change the size of the data segment every time you create or delete a variable, as it’s quite expensive to do so. It’s quite common for programs to create and delete small variables all the time, so it makes sense to hold on to a bit of spare memory. However, if a large enough amount is freed, it should be given back to the operating system for use by someone else, so that’s what the standard library typically does.&lt;/p&gt;
&lt;p&gt;This is probably the explanation for why the test only crashes if the test grid is large: the small grid is still inside our data segment, and although its memory has been marked as available, it hasn’t been overwritten or returned to the OS, so that the pointer returned by &lt;code&gt;elements()&lt;/code&gt; still works even if it’s technically invalid. The segment checking system is not intended to detect mistakes inside a program like this, it’s just there to protect programs from each other. So we get away with it, and the test passes. For the larger grid, the memory has been returned to the OS, so it does trigger a segfault, but it’s somewhat accidental.&lt;/p&gt;
&lt;p&gt;When you run a program with Valgrind’s memcheck (which is what we did here), it actually redirects the calls to create, delete and access variables that the program makes away from the standard library, and to its memcheck tool. This does a lot of extra checking and bookkeeping, allowing it to detect invalid accesses within the program and tell you what happened. All these extra checks do slow down your program a lot, so you don’t want to run under Valgrind all the time, but when you have an issue like this, it’s well worth a bit of a wait if needed. As we saw above, it does a pretty good job showing what’s going wrong, and it’s not so easy to find these kinds of mistakes with other tools.&lt;/p&gt;
&lt;h2 id=&quot;fixing-the-problem&quot;&gt;Fixing the problem&lt;/h2&gt;
&lt;p&gt;Satisfied with these results, I removed the Valgrind from the test cabinet and returned it to my coat pocket. It had proven its worth once again. I wasn’t done however, as the mistake still needed to be rectified. I pulled up a chair to another filing cabinet, this one labeled &lt;code&gt;libmuscle/cpp/src/libmuscle&lt;/code&gt;, and pulled up the &lt;code&gt;data.cpp&lt;/code&gt; file to consider my options.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Data&lt;/code&gt; object actually contains two things: the MessagePack object representing the data, and a MessagePack &lt;em&gt;zone&lt;/em&gt; object. Zones are used by MessagePack to manage memory. If you decode, say, a dictionary, then you get MessagePack objects for the dictionary itself, and also for each key and value, recursively. That’s a lot of objects, so MessagePack puts them all together into a zone. When you’re done with the data, you just delete the zone, cleaning them all up in one go. This is not as easy as automatic memory management, but it is much more efficient.&lt;/p&gt;
&lt;p&gt;Now, our problem is that we create a second &lt;code&gt;Data&lt;/code&gt; object containing the grid dictionary, and that we need to put it somewhere where it will continue to exist for as long as the user accesses the pointer returned by &lt;code&gt;elements()&lt;/code&gt;. MUSCLE3 promises the user that that pointer is valid for as long as the &lt;code&gt;Data&lt;/code&gt; object representing the grid exists, so we need to somehow attach the decoded elements to the grid’s &lt;code&gt;Data&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;One option is to put the elements in the main &lt;code&gt;Data&lt;/code&gt; object’s zone. That will keep them around, but it becomes an issue if the user calls &lt;code&gt;elements()&lt;/code&gt; multiple times, maybe in a loop. On every call, a new &lt;code&gt;Data&lt;/code&gt; object will be created for the dictionary and added to the zone, so we keep using more and more memory. It’ll eventually be freed again, but if it’s a large grid, then we may run out of memory before that. So that’s not great.&lt;/p&gt;
&lt;p&gt;A second option would be to add a pointer-to- &lt;code&gt;Data&lt;/code&gt; to the &lt;code&gt;Data&lt;/code&gt; class, which could be used to store the dictionary &lt;code&gt;Data&lt;/code&gt; object if the &lt;code&gt;Data&lt;/code&gt; object represents a grid. That way, we would only have to decode once, and any subsequent calls to &lt;code&gt;elements()&lt;/code&gt; or &lt;code&gt;shape()&lt;/code&gt; could used the cached object. And using a smart pointer would automatically delete the dictionary &lt;code&gt;Data&lt;/code&gt; object when the grid &lt;code&gt;Data&lt;/code&gt; object is deleted. The downside to this is that it makes &lt;code&gt;Data&lt;/code&gt; objects larger, which could cost some performance even for &lt;code&gt;Data&lt;/code&gt; objects that don’t contain a grid.&lt;/p&gt;
&lt;p&gt;Finally, since the MessagePack format is not so complicated, it would also be possible to make custom decoding routines which decode the grid in one stage, so that there is no need for a second &lt;code&gt;Data&lt;/code&gt; object at all. This could also help to reduce copying, thus improving performance further. That’s a lot of work however.&lt;/p&gt;
&lt;p&gt;At the moment, the focus for MUSCLE3 is on making things work, and on making the life of the users easy. Performance is not crucial, because in multiscale models (unlike in scale-overlapping multiphysics models) communication performance is rarely the bottleneck. I want to spend my time on solving problems for users, but not problems they don’t have. Since the first option could actually make things worse, and the third option is expensive, &lt;a href=&quot;https://github.com/multiscale/muscle3/commit/281c75b8907da5b2d5150c36472705e0916cc2bd&quot;&gt;I chose the second option&lt;/a&gt;. It’s not the prettiest solution, but it will do. If performance does become an issue in the future, then I can always come back and revisit.&lt;/p&gt;
&lt;p&gt;Having fixed the problem, there was one more thing to do: keep similar problems from appearing in the future. Mistakes in software are inevitable, as it’s made by humans and nobody’s perfect. But whenever we discover a mistake, it helps to see if there’s an easy way to avoid doing the same thing in the future, so that over time the software gets better and better. In this case, I added a check for Valgrind to the build system, and it will now run all the tests under Valgrind if it is installed. I also modified the continuous integration container to install Valgrind. This didn’t uncover any other memory management issues in MUSCLE3, but if I make another mistake like this in the future, then there’s a good chance that the tooling will catch it before it ends up with the users.&lt;/p&gt;
&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;My job done, it was time to go home. I grabbed my coat and my hat, verified that the Valgrind was still securely in my pocket, turned off the lights, and carefully closed the door behind me. It was late. The hallways were deserted, the reception desk downstairs vacant. I opened the after-hours side door and stepped out onto the street, into the golden light of a beautiful spring evening. Life was good. I turned towards home, pulled my hat a bit deeper over my eyes to keep the sun out, and started walking, detective-at-ease. I ignored the funny looks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_nAya0dMSUBd58C_5c8ML_g-e8f5424d.CY8gRSSn_Z1l8tn9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Photo by Dewang Gupta on Unsplash&lt;/p&gt;</description><pubDate>Mon, 28 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my long career as a code detective, I have seen it all. I have travelled the high Cs, found Rubies and wrestled Pythons, and walked the alleyways of Fortran at night. Of course, as with any job most cases are run-of-the-mill, but some of them are not. Those are the ones you remember. The ones you tell your grandchildren about, if you live to tell the tale.&lt;/p&gt;
&lt;p&gt;This is the story of a programming mistake that caused a C++ program to crash, and how it was fixed using &lt;a href=&quot;https://valgrind.org/&quot;&gt;Valgrind&lt;/a&gt;. It features mysterious artefacts, C++ memory management, and fixing and avoiding mistakes in (scientific) software. I hope it will teach you something about use-after-free issues, and inspire you to try Valgrind for memory debugging next time you have a similar problem. Let’s dive right in, shall we?&lt;/p&gt;
&lt;h2 id=&quot;the-curious-case-of-the-crashing-simulation&quot;&gt;The Curious Case of the Crashing Simulation&lt;/h2&gt;
&lt;p&gt;It was a dark and stormy ni…no wait, it was actually a sunny afternoon in spring, when I received an email from a scientist named Pavel. Pavel is a postdoc at the University of Amsterdam and the Erasmus University Medical Center in Rotterdam, and he was working on porting a rather complicated computer simulation of something called an &lt;a href=&quot;https://en.wikipedia.org/wiki/Restenosis&quot;&gt;In-Stent Restenosis&lt;/a&gt; to &lt;a href=&quot;https://github.com/multiscale/muscle3&quot;&gt;MUSCLE3&lt;/a&gt;. His program was crashing. And he suspected the problem was with MUSCLE3. Which I created and currently maintain. Which would mean… &lt;em&gt;DUH-DUH-DUUUUUH&lt;/em&gt; (organ sound effect) &lt;em&gt;THERE WAS A MISTAKE IN MY CODE&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;By the way, why can’t you include sound effects in blog posts? I think blog posts are much better with sound effects. Someone should fix this. Meanwhile, here’s an image depicting the horror:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An ink drawing of a face with its eyes and mouth wide open in horror. It is flanked by raised arms on both sides.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;982&quot; src=&quot;https://blog.esciencecenter.nl/_astro/0_g4Uw0OcyPSJMyeKP-89e7e8c7.D3nu8NeI_ZgkqUt.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;“The Scream” Undated drawing by Edvard Munch (via Wikipedia )&lt;/p&gt;
&lt;p&gt;Anyway, yes, there was a mistake in MUSCLE3. But to explain the problem, I need to explain what MUSCLE3 does first. MUSCLE3 is a coupling system for multiscale simulations. In a multiscale simulation, a part of the world is simulated in which multiple processes take place, and where some of those processes are much smaller and/or faster than others.&lt;/p&gt;
&lt;p&gt;In this particular simulation, there are some slow-growing cells (simulated using agents), and some fast-moving blood (simulated using computational fluid dynamics). This is not that relevant, but it is fortunate, because what’s a hard-boiled detective story without some fast-moving blood? Anyway, each process is simulated by a separate computer program, and the programs exchange information by sending messages back and forth. This communication is one of the things MUSCLE3 helps with. And now Pavel was saying that whenever he received a large message, his simulation crashed.&lt;/p&gt;
&lt;p&gt;Messages in MUSCLE3 contain data, and that data can be of a range of types, including the standard built-in types such as strings and integers, but also lists, dictionaries, and grids (arrays) of numbers. You don’t need to tell MUSCLE3 what you’re going to send, you just build a &lt;code&gt;Message&lt;/code&gt; object containing whatever kind of data you want to send, and pass it to MUSCLE3, and on the other side the receiver receives a &lt;code&gt;Message&lt;/code&gt; object containing the same data.&lt;/p&gt;
&lt;p&gt;For a dynamic language like Python, this is all simple enough, but, dear reader, this case would prove to be much more complicated. Pavel’s model was not written in Python. It was written in… &lt;em&gt;DUH-DUH-DUUUUUH&lt;/em&gt; C++!&lt;/p&gt;
&lt;p&gt;See? I told you, sound effects. They make things better.&lt;/p&gt;
&lt;p&gt;Anyway, C++ is a statically typed language. C++ programs are &lt;em&gt;compiled&lt;/em&gt; into an executable file, which is then run in a second step. In C++, each variable can only store values of a particular type (e.g. strings, or integers), and that type must be known when the program is compiled. Of course, we don’t know the type of the data in a message until we receive that message, which happens when the program is running, which comes &lt;em&gt;after&lt;/em&gt; it is compiled. So there is a problem.&lt;/p&gt;
&lt;p&gt;To solve this, the C++ API of MUSCLE3 has a &lt;code&gt;Data&lt;/code&gt; class. Variables of type &lt;code&gt;Data&lt;/code&gt; can contain an object of any type that MUSCLE3 can send and receive. In your C++ code, you can ask the &lt;code&gt;Data&lt;/code&gt; object which type of data it contains, and extract an object of that type. If the data is a grid (for instance because the sender is a Python program that sent you a NumPy array), then you can obtain a pointer to the raw array of elements using the &lt;code&gt;elements()&lt;/code&gt; member function of &lt;code&gt;Data&lt;/code&gt; (C++ doesn’t have a standard multi-dimensional array class, so this is the best we can do).&lt;/p&gt;
&lt;p&gt;That is exactly what Pavel did: he called that function, then copied the elements into another data structure. And then his program crashed. At least, it crashed if the grid was large, a test program receiving a small test grid with only a handful of elements worked fine. Which makes no sense, because MUSCLE3 treats large and small grids exactly the same.&lt;/p&gt;
&lt;p&gt;And thus, our mystery. Why did it crash? Why only for large grids? How should it be fixed? How do we keep this from happening again in the future?&lt;/p&gt;
&lt;h2 id=&quot;detective-its-what-you-are-not-what-you-do&quot;&gt;Detective. It’s what you are, not what you do.&lt;/h2&gt;
&lt;p&gt;It was time to get to work. I collected my hat and put on my trench coat, then dialled in the combination on my wall safe. This job would require some tools. My gaze swept across my collection, carefully assembled over the years. On the left, there were two boxes of print statements. One contained a large pile of cheap plastic mass-produced ones, the other was a velvet-lined display case showcasing a set of two exquisite hand-made examples, made in Japan during the Kamakura period and razor-sharp. While the pride of my collection, and the pinnacle of debugging tools in their time, I would need something more modern for this.&lt;/p&gt;
&lt;p&gt;Next were the linters. They would only protect me from Python formatting issues however. Useless, in this case. A debugger then, maybe? My safe contained a perfectly good copy of gdb, but the truth is that it’s kind of uncomfortable to use. Also, it’s more suited to logic problems than to finding the cause of crashes. I put it aside for now.&lt;/p&gt;
&lt;p&gt;I moved on to a shiny white box. AddressSanitizer it said on the top, in colourful letters. That could work. I’d never liked the sterility of it however. It was too neat, too perfect. A tool of the Empire. No. No, for this job, I would need the final box. A steel chest rather, decorated with ancient runic symbols and adorned with the word &lt;em&gt;Valgrind&lt;/em&gt; in large, Gothic script. Gateway to Valhalla, the great hall where brave programmers go after they retire to await Ragnarök, the end of times when hardware issues and compiler bugs arise for one final epic debugging session before the Great Simulation is rebooted. Yes, Valgrind. I took the chest, put it on my desk, opened it. Removed the gleaming artefact, and put it in my pocket. I was ready to go.&lt;/p&gt;
&lt;p&gt;(If the above procedure sounds a bit over-the-top, &lt;code&gt;apt-get install valgrind&lt;/code&gt; will work just fine as well.)&lt;/p&gt;
&lt;p&gt;It was only a short walk to the site of the crime, a &lt;a href=&quot;https://github.com/multiscale/muscle3&quot;&gt;large building&lt;/a&gt; with the word &lt;code&gt;git&lt;/code&gt; on a sign at the entrance. I walked in and asked the receptionist to see MUSCLE3. She gave me a nasty look. Understandable, given the fact that I look ridiculous in a hat, and that no one has worn a beige trench coat since the 1980’s unless they were a dirty old man. But, having explained that I was in fact a detective, I was waved on and soon found myself in a room with a series of filing cabinets. It was time to start my investigation.&lt;/p&gt;
&lt;p&gt;First, I looked at a cabinet labelled &lt;code&gt;libmuscle/cpp/src/libmuscle/tests&lt;/code&gt;. I knew that there had to be a test which tested that grids could be sent and received. In fact there was; a file conveniently named &lt;code&gt;test_data.cpp&lt;/code&gt; contained a large number of tests for &lt;code&gt;Data&lt;/code&gt; objects, including ones for various aspects of using grids. One of those did exactly what Pavel did. I ran the tests to be sure, and they passed just fine.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OK&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;120&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_serialisation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;OK&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid_serialisation (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ms)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, the test only used a small grid. I modified it to use a larger grid. Re-ran the tests. And sure enough…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Segmentation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fault (core dumped)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, I had verified that indeed there had been a crime, erm, that there was a mistake in my code. But where? It was time to deploy Valgrind. I modified the &lt;code&gt;Makefile&lt;/code&gt; that runs the tests to run &lt;code&gt;valgrind &amp;#x3C;test_executable&gt;&lt;/code&gt; instead of just &lt;code&gt;&amp;#x3C;test_executable&gt;&lt;/code&gt;. Having thus installed the Valgrind onto the filing cabinet, I took cover behind another cabinet filled with Fortran code (heavy, voluminous, and in this case auto-generated and therefore expendable) and restarted the test suite.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An arch-shaped angular metal object with a letter V and two viking heads on it sits on top of a wooden cabinet.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;1050&quot; src=&quot;https://blog.esciencecenter.nl/_astro/1_oGKL4SYDYiHd9ggSmp_mpw-7c311286.ChVArLxo_ZqH1yL.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Valgrind in action&lt;/p&gt;
&lt;p&gt;As the first tests ran, a bluish light filled the room and the ancient artefact started vibrating, emitting a faint hum of approval. Then, suddenly, a horrifying screech emanated from it.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hs&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] libmuscle_mcp_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Invalid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; read &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; at &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x13F848&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::CmpHelperEQ&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1444&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1368DF&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::AssertionResult&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; testing&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::EqHelper&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;::Compare&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;int, int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, char const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, int const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (gtest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1472&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; by &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0x1288B1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; libmuscle_mcp_data_grid_Test&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::TestBody&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (test_data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cpp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;526&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;19383&lt;/span&gt;&lt;span style