<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://gibsonic.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gibsonic.org/" rel="alternate" type="text/html" /><updated>2026-03-12T17:05:42+00:00</updated><id>https://gibsonic.org/feed.xml</id><title type="html">Perry Gibson 🍐</title><subtitle>Personal blog of Perry Gibson © 2026.</subtitle><author><name>Perry Gibson 🍐</name></author><entry><title type="html">Token Cyborgs</title><link href="https://gibsonic.org/blog/2026/03/10/token_cyborgs/" rel="alternate" type="text/html" title="Token Cyborgs" /><published>2026-03-10T08:00:08+00:00</published><updated>2026-03-10T08:00:08+00:00</updated><id>https://gibsonic.org/blog/2026/03/10/token_cyborgs</id><content type="html" xml:base="https://gibsonic.org/blog/2026/03/10/token_cyborgs/"><![CDATA[<p>The token cyborg mediates some or all of their everyday experience through AI
models.</p>

<!--more-->

<p>The legible artefacts of notes and software tools accrue in their home
directories, most of which has not been fully read by their eyes. But they trust
that it sufficiently represents their will, and it may have its use down the
line.</p>

<p>They may pass the audio of their meetings or conversations through models, for
summarisation or analysis. The motivated will have live interaction, consulting
their models for potential insights or questions to ask. With practice, the
pauses and darting eyes are difficult to spot.</p>

<p>The personal agency of the token cyborg will vary. Some wear their models like
exo-skeletons, strengthening their own resolve, and amplifying their will.
Others are worn by the models, productive half hours passing with nary a
conscious thought.</p>

<p>The token cyborg hungers for larger context windows, longer reasoning chains,
higher throughput, lower latency. In an hour they may crunch through more
floating-point ops than the whole human race did until around the time of the
Chernobyl disaster.</p>

<p>Self-hosted, or heavily subsidised TaaS, the token cyborg shifts their
infrastructure often. How much of themselves exists in a data lake to be picked
over? As their trust in their tools grow, they expose more of themselves. An
email API key here, a family group chat there. Context is power.</p>

<p>Desires and goals now form as prompts, quick references for the context to fetch
— trust that the intent is evident. An implicit knowledge of models’ pitfalls,
caveats and requirements sprinkled in at the end of requests. Make it efficient,
don’t make mistakes, don’t hallucinate. Make it sound charming.</p>

<p>A WiFi-less flight is to have one’s arms bound.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="ai" /><category term="tokens" /><category term="llms" /><summary type="html"><![CDATA[The token cyborg mediates some or all of their everyday experience through AI models.]]></summary></entry><entry><title type="html">Women in Policing: Health, Justice, and Organisational Culture — A Wee Chat with Dr Dr Mahnoz Illias</title><link href="https://gibsonic.org/blog/2026/02/14/mahnoz_police/" rel="alternate" type="text/html" title="Women in Policing: Health, Justice, and Organisational Culture — A Wee Chat with Dr Dr Mahnoz Illias" /><published>2026-02-14T10:20:08+00:00</published><updated>2026-02-14T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/14/mahnoz_police</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/14/mahnoz_police/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-01-mahnoz.png" width="1024" /></p>

<p>Dr Dr Mahnoz Illias completed her PhD at the University of Glasgow in 2025. Aye,
she really is a double doctor 😎, originally earning a medical degree in
Bangladesh, before completing an MSc in Global Mental Health at the University
of Glasgow, supported by the Commonwealth Scholarship Commission. Her PhD
research examined policing as a gendered organisation and the impact on the
health and well-being of female police staff and officers in the UK. Here, I had
a wee chat with her about her research and perspectives.</p>

<!--more-->

<hr />

<p><strong>Awright Dr Dr Mahnoz?</strong></p>

<p>Hello there Dr Perry Josef Gee Gibson.</p>

<p><strong>What was your research topic about?</strong></p>

<p>I looked at the gendered toll of policing on the health and well-being of female
police officers in the UK.</p>

<p><strong>Who were you working with for that?</strong></p>

<p>I was working with my supervisors and the wider team that I engaged with. My
primary supervisor was based at the School of Health and Wellbeing at the
University of Glasgow, and my second supervisor was at the Adam Smith Business
School.</p>

<p>It was quite an interdisciplinary project. I was based within these two schools,
but a lot of the work I did was actually closer to the field of criminology
rather than either public health or business/organisation studies.</p>

<p>Outside of the school, I worked closely with the
<a href="https://www.scottishwdf.com/">Scottish Women’s Development Forum</a> of Police
Scotland. They’re a group who represent women within Police Scotland — all the
women staff and officers. It’s a voluntary organisation because, although police
forces keep saying they’re “trying their best to accommodate the welfare of
their employees”, but claim they “do not have the funds” for formal support. So
volunteers step forward to fill the gap. I also worked with broader groups like
the <a href="https://www.sipr.ac.uk/">Scottish Institute for Policing Research</a> and the
Academic Team of Police Scotland.</p>

<p><strong>What was the connection with the Adam Smith Business School; I don’t
immediately see the connection to the research area?</strong></p>

<p>It was mainly about the organisation — the culture, structure, and norms, and
how they impact health and well-being. Although in public health we do study
this (and public health itself is very interdisciplinary), it’s mainly the
people in “organisation studies” who study how organisations are functioning.
They’re located at the business school, so that’s where the Adam Smith Business
School comes into my research journey.</p>

<figure style="max-width: 40%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Adam_Smith_The_Muir_portrait.jpg/1280px-Adam_Smith_The_Muir_portrait.jpg" alt="Portrait of Adam Smith" style="width: 100%;" />
  <figcaption>Adam Smith, Scottish "father of economics", for whom the school is named. His book <a href="https://en.wikipedia.org/wiki/The_Wealth_of_Nations">The Wealth of Nations</a> is worth a read if you want to learn about the price of socks made in the Highlands. Via <a href="https://commons.wikimedia.org/wiki/File:Adam_Smith_The_Muir_portrait.jpg">Wikimedia Commons</a></figcaption>
</figure>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Social support, especially workplace social support, plays a huge role in our lives, which we often overlook."
</blockquote>

<p><strong>You were originally a medical doctor, then you did a
<a href="https://www.gla.ac.uk/postgraduate/taught/globalmentalhealth/">Master’s in Global Mental Health</a>.
How was that perspective shift—looking at mental health not just as an
individual matter, but as a large-scale policy question?</strong></p>

<p>It was different. When we talk about health or mental health, what I’ve found is
that people often think it has to be related to institutional medicine, or
hospitals, or doctors dealing with it. But in our day-to-day life, we can see
how each individual has a health experience that is much less formal. Our eating
choices, our social interactions, our work environment—all of these impact our
health.</p>

<p>We also share a lot of experience from the people around us, which impacts us
both mentally and physically. Acknowledging this in the workplace is important —
in the past, these issues were often presented as individual problems. But I
believe we’re coming to recognise it as a shared responsibility. Every
interaction—including this conversation—happens in a shared space. Both of us
bring our accumulated knowledge and experiences to it.</p>

<p>I also feel that when we talk about health, we normally try to narrow it down to
medical reports or such things, but there is something way beyond that. Health
is not just a medical issue—it’s a social issue, it’s a <em>justice</em> issue. These
things came up again and again in my research.</p>

<p><strong>Taking the perspective that not everything can and should be medicalised?</strong></p>

<p>Yes, when I finished medical school in Bangladesh, my idea about mental health
was quite narrow. When I talked about mental health, I used to think it had to
be something major—schizophrenia, bipolar disorder, or something that needs
regular medication and to be dealt with on a regular basis.</p>

<p>Outside of that, our understanding from our education was that “depression is
there”, and people just have to deal with it until they need medication. What
I’ve come to understand is that mental health isn’t separate from physical
health—they’re intertwined, happening at the same time. It’s not a separate
entity; it’s part of who we are. That means we should be aware of it in our
everyday lives, rather than just in crisis.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://i.pinimg.com/736x/71/44/cc/7144cc2524816581585902eef30eb345.jpg" alt="Depression meme" style="width: 100%;" />
  <figcaption>Depression: sometimes it's like that.</figcaption>
</figure>

<p><strong>Was your research focused on Scotland, or did it explore the wider UK?</strong></p>

<p>It was actually throughout the UK. However, as the project received half of its
funding from the
<a href="https://www.sipr.ac.uk/">Scottish Institute for Policing Research</a>—and I’m
grateful to them and <a href="https://www.ukri.org/councils/mrc/">MRC UK</a> for their
support—I had more connection with organisations based in Scotland. But I did a
mixed-method study. I had to analyse two large national cohorts of police
officers, which covered information from all police officers and staff across
the UK—it wasn’t confined to Scotland, and I did not confine my results to
Scotland either.</p>

<p>When I did my primary data collection, most of the participants were from
Scotland—probably two-thirds—and the rest were from across the UK.</p>

<p><strong>In brief, what were the main findings of your thesis?</strong></p>

<p>I would say the main findings were that the health and well-being of female
police officers cannot be understood as a single piece of work. Rather, I would
describe it as a puzzle. By doing research on all these different parts, I got a
closer picture of the entire puzzle, but it’s still not solved. It was more like
a mosaic, with pieces fitting into each other rather than isolated factors—the
social aspect of health working one way, the mental health aspect another way,
the physical aspect there. They’re all intertwined.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Gaudi_lizard_%286031486006%29.jpg/1920px-Gaudi_lizard_%286031486006%29.jpg" alt="Gaudí mosaic lizard" style="width: 100%;" />
  <figcaption>The mosaic of problems that women face. Via <a href="https://commons.wikimedia.org/wiki/File:Gaudi_lizard_(6031486006).jpg">Wikimedia Commons</a></figcaption>
</figure>

<p>All of these health and wellbeing issues—stemming from the cultural and
structural issues—often, as I said earlier, we try to describe them as medical
problems. But health is not just a medical problem. It is a justice issue as
well. What facilities you’re getting within your organisation, what you’re given
or not given, can be seen from a justice point of view. At the root of
everything, there is actually organisational injustice, which is controlling how
it impacts overall health.</p>

<p>Lastly, I found that social support, especially workplace social support, plays
a huge role in our lives, which we often overlook.</p>

<p><strong>These seem like interconnected problems. How much can be attributed to being a
woman, versus just “being a polis<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> is stressful”?</strong></p>

<p>Every organisation or institution within a society, including families, is a
reflection of the existing society itself. When I was talking to those police
officers, one of my inclusion criteria was they would need to have at least ten
years of experience working as a police officer—to reflect back on how the
culture changed over time, how policies changed, how that impacted them.</p>

<p>All of them came into policing knowing there would be a certain level of
operational stress. They knew what policing was—definitely there were some
surprises like every other job, but gradually in day-to-day life, the relational
aspects became more prominent.</p>

<p>There’s a scholar with a famous theory called “Gendered Organisations”—her name
is <a href="https://en.wikipedia.org/wiki/Joan_Acker">Joan Acker</a>. She explains it very
nicely. She says that a “job” itself is an abstract idea; for its embodiment,
you need a <em>person</em> to be there.</p>

<p>And that person, when they enter the role, they bring all of their gendered
ideas about women with them—what they learned throughout their life about the
limitations of women, what they can do, what they cannot do. They came with
their perceptions and kept spreading those ideas. As society has changed, those
ideas have also changed. But still, though we keep saying that men and women are
equal in our society, that’s not quite the case. Policing remains a gendered
organisation, and this has real impacts on the health and well-being of female
police staff and officers.</p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Health is not just a medical issue—it's a social issue, it's a justice issue."
</blockquote>

<p><strong>Is it your impression that police in the UK have more of a “boys’ club”
problem than other places? Or is it more in-line with the issues in wider
society?</strong></p>

<p>They definitely had their own boys’ club issues. They had cultures where women
wouldn’t be invited to the informal parties or after-work gatherings, or they’d
always assume that if you have children, you must need childcare.</p>

<p><strong>Are there any articles folk could check out if they were interested?</strong></p>

<p>I have two articles out so far, and two others are under review.</p>

<p>My meta-ethnographic review, which looked at the interplay between
organisational injustice and the health and well-being of female police officers
and staff across the globe, was published in BMC Public Health [1].</p>

<p>Another piece of work compared the impact of workplace social support on the
mental health of parents, both men and women, published in the journal
“Policing” [2].</p>

<p><em>[1] M. Illias, K. Riach, and E. Demou, ‘Understanding the interplay between
organisational injustice and the health and wellbeing of female police officers:
a meta-ethnography’, BMC Public Health, vol. 24, Sep. 2024, doi:
<a href="https://pubmed.ncbi.nlm.nih.gov/39342226/">10.1186/s12889-024-20152-1</a>.</em></p>

<p><em>[2] M. Illias et al., ‘Exploring gender differences in policing: the role of
workplace social support on the mental health and wellbeing of parents in
policing’, Policing, vol. 19, Jan. 2025, doi:
<a href="https://academic.oup.com/policing/article/doi/10.1093/police/paaf037/8316114?login=false">10.1093/police/paaf037</a>.</em></p>

<p><strong>Were there any technical tools in your work that you were using, and any
frustrations with them?</strong></p>

<p>Definitely. One of the datasets I was using was the
“<a href="https://police-health.org.uk/">Airwave Health Monitoring Study</a>”. Since it was
quite sensitive, to access that data, I had to get access to a “safe haven”, or
what they formally call a <em>Trusted Research Environment</em>. The operators had
maintenance windows (thus, I couldn’t always access it when I needed to), and
sometimes because it’s a big dataset hosted somewhere else, there were technical
issues. Many days I was frustrated because you’re in the mood to analyse and
then you cannot access the data.</p>

<p>When I began my PhD, I didn’t know how to code in
<a href="https://en.wikipedia.org/wiki/R_(programming_language)">R</a> (a programming
language for statistical analysis), but I needed to for its flexibility and the
amount of data analysis I had to perform. Learning that was also a challenge. I
used to freeze at the thought of having to engage in coding work—the word
“coding” was very frightening. But after my analysis of the first database, I
got quite confident, and it didn’t take me much time to do my second analysis.</p>

<figure style="max-width: 80%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/RStudio_IDE_screenshot.png/1920px-RStudio_IDE_screenshot.png" alt="RStudio IDE screenshot" style="width: 100%;" />
  <figcaption>The RStudio IDE — a good system, but I cannae get behind 1-based indices. Via <a href="https://commons.wikimedia.org/wiki/File:RStudio_IDE_screenshot.png">Wikimedia Commons</a></figcaption>
</figure>

<p><strong>Do you think you would have benefited from having access to more technical
support?</strong></p>

<p>I had people in my unit who I could reach out to, but in a PhD you can’t control
which part of work you’re going to do at what time of day. If it was a friend, I
could reach out anytime. But if it’s a colleague, it’s a formal relationship. As
a new person within the unit, I was also hesitant to reach out to them. Whenever
I had issues, I could reach out to people, but these were colleagues who had
volunteered to help me—there weren’t any designated people you could always go
to. Having someone like that would have definitely benefited me or people like
me who have just started coding.</p>

<p><strong>What was your experience navigating the research space in the UK as a
Bangladeshi woman?</strong></p>

<p>I didn’t face any issues particularly from a gender perspective. But compared to
my MSc, I felt a bit isolated. I don’t know whether that was the nature of the
PhD, or something was wrong with me, or I wasn’t ready—it was just after COVID
as well, so people were quite isolated at that time. Maybe all those factors
worked together.</p>

<p>I was still hanging out with my old friends outside that space, but compared to
that, I did not have that many close friends within my own department. They were
very lovely people, very cooperative, but somehow I didn’t have that connection
with them.</p>

<p>But there was another space—the Scottish Institute for Policing Research—where I
met a lot of people from different fields: criminology, cybersecurity, forensic
backgrounds. I made good friends with them. I don’t know what the reason was
behind this, but that’s how it was.</p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Coming from Bangladesh, I expected the UK to be a 'utopia'... But when I looked beyond the surface, it was very shocking."
</blockquote>

<p><strong>For any organisation in general—you’ve looked a lot into organisational
structures. Is there any general advice you’d give to leaders or individuals
about how to help manage the issues you’ve seen in your work?</strong></p>

<p>One of the things was that Police Scotland is a single force, but in England
they have around 43 forces. Across different stations or forces, they each were
tackling different issues well, and others less well. But those were ad hoc
initiatives, with success stories not being shared with each other.</p>

<p>I know there’s decentralisation of policing and those ideas in criminology, and
there are certain reasons for that. But I felt they should have a common
platform where they can share positive initiatives that are actually helping
people deal with the issues they face in their day-to-day life.</p>

<p>If they can find a way to share those and adopt the effective programmes that
are working for people, that would be really beneficial for the entire
organisation or the entire police force across the UK.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/United_Kingdom_police_areas_map.svg/960px-United_Kingdom_police_areas_map.svg.png" alt="Map of UK police areas" style="width: 100%;" />
  <figcaption>Police areas of the United Kingdom. <a href="https://commons.wikimedia.org/wiki/File:United_Kingdom_police_areas_map.svg">CC BY-SA 3.0</a></figcaption>
</figure>

<p><strong>You mentioned the PhD ended up being more about criminology. Could you briefly
explain what you meant by that?</strong></p>

<p>I would say it’s criminology because every time I was going to conferences and
knowledge exchange programmes, I was mostly interacting with people from
criminology or forensic psychology backgrounds. They’re the ones coming to work
on what’s happening with policing, how policing can be better, rather than
someone from a health background.</p>

<p>In that sense, I didn’t have much in common with other people in terms of
background. But they were very welcoming, so it wasn’t an issue.</p>

<p>Also, a major portion of writing up my final thesis involved understanding the
policing structure within the UK—what policies are out there, under what law
police organisations in the UK came into being. Those are things more from
criminology rather than my health perspective. They were new ideas for me.</p>

<p><strong>Anything else you want to highlight?</strong></p>

<p>Another interesting finding: when I started my project, I was initially
expecting the focus to be about physical health. Many police officers are
exposed to more danger than a typical office job, and if we’re talking about
women—our physiology is generally different from men, and this has some impact
on our musculoskeletal health. Perhaps my research would take me into questions
around musculoskeletal problems they’re facing, and how the workplace could
change to support that.</p>

<p>However, when I started to look into it, what came up more consistently was
<em>mental health</em> issues. I was very surprised that no matter which part of the
world the articles I was researching were coming from, they had similar issues:
regardless of the culture—whether it was from the Global South or Global North.
It was surprising for me because, coming from Bangladesh, I expected the UK to
be a “utopia” where everything was perfect, or at least significantly better,
women would be getting their rights properly, they didn’t have to fight for it,
they were living their lives very comfortably.</p>

<p>But when I looked beyond the surface, it was very shocking and frustrating for
me to deal with those accounts on a daily basis, and that these issues exist in
the UK as much as they do in other parts of the world. It also helped me realise
how seemingly gender-neutral policies are not as neutral as they seem.</p>

<p><strong>Thank you Dr Dr Mahnoz</strong></p>

<p>Thank you Dr Perry Josef Gee Gibson.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>“Polis” is a Scots term for police. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="police" /><category term="interviews" /><category term="mental-health" /><summary type="html"><![CDATA[Dr Dr Mahnoz Illias completed her PhD at the University of Glasgow in 2025. Aye, she really is a double doctor 😎, originally earning a medical degree in Bangladesh, before completing an MSc in Global Mental Health at the University of Glasgow, supported by the Commonwealth Scholarship Commission. Her PhD research examined policing as a gendered organisation and the impact on the health and well-being of female police staff and officers in the UK. Here, I had a wee chat with her about her research and perspectives.]]></summary></entry><entry><title type="html">Invited talk at CODAI, HiPEAC 2026</title><link href="https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk/" rel="alternate" type="text/html" title="Invited talk at CODAI, HiPEAC 2026" /><published>2026-02-08T10:20:08+00:00</published><updated>2026-02-08T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-02-hipeac.png" width="1024" /></p>

<p>I was delighted to be invited to both give a talk, and participate in the panel
discussion at the <a href="https://www.codai-workshop.com/home">CODAI workshop</a>
(Workshop on Compilers, Deployment, and Tooling for AI) at HiPEAC 2026 (Kraków,
Poland).</p>

<p>My talk, titled “The Compiler Before the Horse: Design Space Exploration at
Fractile,” focused on how investing in compiler development early in our
hardware design process has been essential for effective design space
exploration and for making well-informed architectural decisions.</p>

<!--more-->

<p>The stream was recorded, and is available from the
<a href="https://www.codai-workshop.com/2026-recording">CODAI website</a>.</p>

<p>I tried to keep the tone light, and may have overdone it with my extended
metaphor. Beating a dead horse, if you will.</p>

<p>In an age of easy, high-quality generative images, I had some fun old-school
editing together my own images.</p>

<figure style="width:66%; margin: 1em auto; text-align: center;">
  <img src="https://gibsonic.org/assets/pics/2026-01-one_trick_pony.png" alt="Not a one trick pony" style="width:100%; height:auto;" />
  <figcaption>not a one trick pony!</figcaption>
</figure>

<p>The first part of the talk mirrored a lot of the themes in my <a href="/blog/2025/03/03/c4ml_vegas/">C4ML talk in
Vegas</a> in 2025, namely that we found a lot
of success developing quick and dirty prototypes of the compiler using the MLIR
Python bindings. We even got an end-to-end compilation and functional simulation
of Llama2-7B, which was a great validation of our team, our design, and our
high-level architecture.</p>

<p>I then discussed how the organisation has changed, and how as we approach
tape-out, we have been nailing down the minutiae of our programming model, and
how that interacts with our architecture.</p>

<p>The message I was trying to sell was that the compiler team, and staff at
Fractile in general, have been empowered to make functional software early, to
better understand the shape of our design space, and use that to inform our
conversations with architects.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="talks" /><category term="compilers" /><category term="hipeac" /><summary type="html"><![CDATA[I was delighted to be invited to both give a talk, and participate in the panel discussion at the CODAI workshop (Workshop on Compilers, Deployment, and Tooling for AI) at HiPEAC 2026 (Kraków, Poland). My talk, titled “The Compiler Before the Horse: Design Space Exploration at Fractile,” focused on how investing in compiler development early in our hardware design process has been essential for effective design space exploration and for making well-informed architectural decisions.]]></summary></entry><entry><title type="html">You Can Do It Too: Inside Scotland’s Post-Punk Press with Glenn Gibson</title><link href="https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson/" rel="alternate" type="text/html" title="You Can Do It Too: Inside Scotland’s Post-Punk Press with Glenn Gibson" /><published>2026-02-03T10:20:08+00:00</published><updated>2026-02-03T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-02-glenn.png" width="1024" /></p>

<p>In this post, I chat with a former New Musical Express (NME) writer Glenn Gibson
(aka, my da) about his experiences breaking into music journalism in the
1970s-80s, the evolution of music publications, the development of Scotland’s
music scene during the punk and post-punk era, and various other bits and
pieces.</p>

<!--more-->

<hr />

<p><strong>You’ve got interesting stories about the music industry—I thought it’d be good
to capture some of them. How did you get into music writing?</strong></p>

<p><em>It was the New Musical Express, which was well-established when I started.</em>
<em>It’s a music paper dating back to the 50s, and they were credited with
originating the UK pop charts. But it was very much tied</em> <em>into the music
business. They just had pop stuff and so forth. And at some</em> <em>point, during the
early 1970s, they got a new editor who totally</em> <em>revamped it.</em></p>

<p><em>Starting in the 60s there was the underground press which was usually
independent. And the NME started employing people who wrote for those
publications.</em></p>

<p><strong>So rather than just being a mouthpiece for what was coming out from the big
labels, it was able to give space for some more up-and-coming and challenging
artists?</strong></p>

<p><em>Yes, rather than just covering what was in the charts. With the counterculture
and all of the post-war developments, music was developing fast.</em></p>

<p><em>It went from rock and roll, to the Beatles, and the beat boom, and moved on to
prog rock, glam rock, and punk. Around 1976/77 they wanted music publications
that would reflect that — written by people who were close to the movement, who
were really part of that.</em></p>

<p><em>They were probably copying what was happening in America because in the 60s,
Rolling Stone magazine started. Rolling Stone is now well-established, I believe
it’s quite a corporate thing now. But it started as a counterculture underground
thing.</em></p>

<p><strong>They employed the likes of Hunter S. Thompson for articles?</strong></p>

<p><em>Yes, some real mavericks. One person they employed was Cameron Crowe, who went
on to become a film director. A film he wrote, ‘Almost Famous,’ was
semi-autobiographical.</em></p>

<p><strong>Auch aye, I think we watched that together a few years back.</strong></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/en/d/dd/Almost_famous_poster1.jpg" alt="Almost Famous film poster" style="width: 100%;" />
  <figcaption>Almost Famous (2000), written/directed by Cameron Crowe. Via <a href="https://en.wikipedia.org/wiki/File:Almost_famous_poster1.jpg">Wikipedia</a></figcaption>
</figure>

<p><em>He was just somebody who was a big music fan. He sent them articles he’d
written, and they liked them. I don’t think they found out until later that he
was 15. They were sending him off to interview big-time stars and he became
really successful. “Almost Famous” is arguably one of the best music business
films ever made. I would say that and
“<a href="https://en.wikipedia.org/wiki/24_Hour_Party_People">24 Hour Party People</a>”
(2002).</em></p>

<p><em>And Cameron Crowe has actually just published his autobiography,
<a href="https://www.goodreads.com/book/show/224004354-the-uncool">“The Uncool” (2025)</a>,
because part of “Almost Famous” was that he was never cool.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"That's when I started getting published—and paid."
</blockquote>

<p><em>Anyway, that’s the kind of thing that the NME were trying to copy, and it
worked. They got a big audience and it became very cool, internationally as
well. It was very well liked in America too. They seemed open to taking on
people from around the country, so I went to see Ivor Cutler, the Scottish
humorist, singer, songwriter, and poet, and I wrote something about it and sent
it to them. They published it.</em></p>

<p><strong>Oh, crackin’</strong></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <div style="overflow: hidden;">
    <img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/Ivor_Cutler_1973.jpg" alt="Ivor Cutler in 1973" style="width: 100%; margin-top: -25%;" />
  </div>
  <figcaption>Ivor Cutler in 1973, photo by Alan Messer. <a href="https://commons.wikimedia.org/wiki/File:Ivor_Cutler_1973.jpg">CC BY-SA 3.0</a></figcaption>
</figure>

<p><em>They came back and said “would you like to do more?” I sent them quite a few
things, and they didn’t publish any of them. But then the person in charge of
the live review section changed and a new guy came in and he said, “Don’t do
that anymore. What you should do is phone me every week and say what’s coming up
and we will then commission you to write things.” That’s when I started getting
published — and paid.</em></p>

<p><em>That being said, I still had a day job as well. Looking back, I don’t know how
I managed it.</em></p>

<p><strong>I guess not having weans helps.</strong></p>

<p><em>I think the extreme would be working all day and then going to Edinburgh and
not getting back home from Edinburgh until five in the morning. And then getting
up to go to work. Out constantly at gigs and interviews, and also needing the
time to write up.</em></p>

<p><strong>Aye, I can imagine that took a good chunk of time. Did the acts you were sent
to cover align with your tastes, or were you seeing a load of pish? Once they
started commissioning, were they picking what you covered, or did you still have
a say?</strong></p>

<p><em>Well, a mixture, because I wasn’t doing exclusively what was happening in
Scotland. I was being sent to review other bands who were touring who could be
American, but as well as covering what was happening in Scotland because what
was happening in Scotland was developing, and gaining national attention.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"One thing punk did was give people the message: 'you can do it too.'"
</blockquote>

<p><strong>Starting to develop its own scene?</strong></p>

<p><em>Yes. Simple Minds were one of the first ones. I went to see them playing in
bars. I think they had already signed a contract with a record company at this
point, so they were starting to move beyond that, but there were a lot of other
ones coming up behind them.</em></p>

<p><strong>There are probably quite a lot of bands that folk would be surprised to hear
came out of the Scottish scene because the accent or dialect doesn’t necessarily
come across.</strong></p>

<p><em>Well, the music business was always very centred in London. This was after
punk. One thing punk did was give people the message: “you can do it too.” And
what they were playing was relatively simple. That simplicity had origins in
early rock and roll. The British beat groups of the 1960s were actually quite
‘punk’ in their way—like The Who, The Animals, and Them. With “Them”, the singer
was Van Morrison who is still very successful.</em></p>

<p><em>It was fairly simple, thus it’s something that people who were just teaching
themselves how to play guitar or bass or drums could play. It was a reaction to
progressive rock, which can be very complicated and long and was all about
musicianship. That was a backlash against that. The impact of it was quite
startling.</em></p>

<p><strong>I guess there was starting to be more access to recording and distribution
equipment during that time?</strong></p>

<p><em>There were local recording studios, but access to recording didn’t change much
during that period. With computers and software it became much easier to record
from home, but you couldn’t do that then really, unless you bought quite
expensive tape recorders, which could still be quite primitive. So bands would
go to record in small Scottish studios. But it could still cost a lot of money.
Some of them would be around £600 a day.</em></p>

<p><strong>Auch, geezo, and I guess that’s £600 then as well.</strong></p>

<p><em>For people without much money, that was a lot. And the Scottish bands who were
playing in bars would be paid very little. I think in some cases they’d get like
£10 and there might be four or five people in the band, and they had to hire a
van to get there which might cost them about £70 — so they were making a loss.</em>
<em>But they were just trying to get their own music out there.</em></p>

<p><em>It was an interesting dynamic but that message about “you can do it too” was
quite widespread. And more than just music. For instance, my friend Martin
Millar was very influenced by that ethos to become a writer. Actors, writers,
people across the creative arts—a lot of people were influenced by that, and
still are today.</em></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <img src="https://covers.openlibrary.org/b/id/8779561-L.jpg" alt="Lonely Werewolf Girl book cover" style="width: 100%;" />
  <figcaption>Lonely Werewolf Girl by Martin Millar. Via <a href="https://openlibrary.org/works/OL20126859W/Lonely_Werewolf_Girl">Open Library</a></figcaption>
</figure>

<p><em>I got to do [the writing] for a number of years and earned a reasonable
amount of money and got to travel around and meet a lot of people. And with
various different publications, I probably did it for about 11 years. Although
you got some money, it was difficult to actually make a living.</em></p>

<p><strong>Because it was quite sporadic?</strong></p>

<p><em>Yeah, it was unreliable, I was just a freelance person who was also working a
day job. There were some people who did the writing exclusively. However, they
were probably getting unemployment benefits and things like that, or there might
have been some other small local things that they did. There were a couple of
people who went on to write for the local newspapers, doing the pop column.</em></p>

<p><strong>Which is a bit more of a reliable income.</strong></p>

<p><em>Yes, <a href="https://www.thetimes.com/profile/john-dingwall">John Dingwall</a>, for
instance, he started off with a fanzine and then wrote for Record Mirror.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="/assets/pics/2026-02-stand_and_deliver.jpg" alt="Stand and Deliver fanzine cover" style="width: 100%;" />
  <figcaption>Stand and Deliver, John Dingwall's fanzine</figcaption>
</figure>

<p><em>When he was just doing Record Mirror he probably wasn’t getting that much, but
he went on to work for the Evening Times and Daily Record and he did that for a
long time, and has been a core part of Scottish journalism since.</em></p>

<p><em>Making money from journalism at that time, even if you were employed by a
Scottish newspaper which was predominantly sold in Scotland, you were paid quite
well. The circulation of newspapers today has plummeted since then.</em></p>

<p><strong>Aye, the issues that face the entire journalism industry today is a whole
fraught topic unto itself.</strong></p>

<p><em>I do know some people who moved to London and maybe had a bit of success. But
they weren’t getting paid that much just working for music papers, or smaller
music magazines, they were very often living in cheap accommodation: squats,
somebody’s spare room, or flats with only cold water and broken windows.</em></p>

<p><strong>I guess in a sense that’s quite punk. You’re getting an appreciation of your
source material.</strong></p>

<p><em>Right, the other side of that, is that the several people I can think of that
did that, they all died quite young. In their early 60s and some even younger.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"They'd get like £10 and there might be four or five people in the band, and they had to hire a van which might cost them about £70—so they were making a loss."
</blockquote>

<p><strong>Is that what a lifetime of substandard heating will do to ye?</strong></p>

<p><em>Yeah, and maybe not being able to feed themselves properly as well. It might be
a coincidence.</em></p>

<p><strong>People say the body keeps score.</strong></p>

<p><em>Yes, I obviously have nothing definite about it but you know, it happened to
one photographer I worked with. He moved to London and got a job working for
“Sounds” which was quite a good magazine. Quite well regarded. And I think after
that, he even got a job working for Marvel.</em></p>

<p><em>I used to go and stay with him sometimes in London, but I kind of lost track
after a while. Anyway, he got a brain aneurysm. He came back to Scotland a
number of years ago and I think he’s in a care home.</em></p>

<p><em>The singer from the Bluebells, Ken McCluskey, who we knew, discovered that this
guy Harry Papadopoulos was back in Scotland. And the reason Ken found out about
it, was because Harry’s brother was an electrician or a tradesman of some kind
and went and did a job in his house. The subject must have come up. Ken went to
visit him, and they managed to get a hold of his old negatives. They’ve been on
display in several art galleries and so forth. And there was a book published.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://covers.openlibrary.org/b/id/14693456-L.jpg" alt="What Presence! book cover" style="width: 100%;" />
  <figcaption>What Presence!: The Rock Photography of Harry Papadopoulos. Via <a href="https://openlibrary.org/works/OL35700027W/What_Presence!">Open Library</a></figcaption>
</figure>

<p><strong>There was the
“<a href="https://www.nms.ac.uk/past-exhibitions/rip-it-up-the-story-of-scottish-pop">Rip It Up: The Story of Scottish Pop</a>”
exhibition at the National Museum of Scotland in 2018, where there were a couple
of things you contributed.</strong></p>

<p><em>I never really collected a lot of memorabilia, but there were some things I
had. Part of the reason for it is that a lot of people in the past have been
asked to lend things of that type and never got them back. So a lot of people
who were asked to lend things would say “nah, not doing that”. But with the
National Museum of Scotland they were known for being quite reliable, and you
did get everything back. So it ended up being quite extensive, and showing off a
lot of items never seen before.</em></p>

<p><strong>Speaking of Scottish pop history being museum-worthy, what place do you think
this sort of thing should have in our collective consciousness?</strong></p>

<p><em>Occasionally in YouGov questionnaires they’ll ask things like “What does
Britain do best?” I’m not saying things like industrial products—I’d say music,
comedy, acting, writing, and the arts in general. And it’s hard to think of
things that Britain does better than those kinds of things.</em></p>

<p><strong>Aye, a lump of steel is more-or-less the same wherever it’s from. But music,
comedy—that’s a product of the people and the culture. You can’t get that
anywhere else.</strong></p>

<p><em>For a very long time pop and rock music that was listened to internationally
was almost exclusively from Britain and America. And that has been changing.
There were certain countries, like Germany, that became quite successful, or at
least critically recognised for what they were doing.</em></p>

<p><strong>Aye, they weren’t playing Kraftwerk on Clyde One initially.</strong></p>

<p><em>No. But there were a lot of other things coming out of Germany at that time,
but it probably remained quite underground, or a niche interest. That’s
continued—music from other countries gaining recognition in the UK. And now that
you have K-pop and J-pop, these are massively successful.</em></p>

<p><strong>Aye, it’s good to see that things are getting a bit more nuanced than just the
catch-all term of “World Music”.</strong></p>

<p><em>Yes, there were phases—African music was a thing for a while, and reggae
especially — Jamaica was close to America which may have helped with discovery
and distribution. It very much had its own sound, developing over the years from
ska to blue beat to reggae, and they had their own version of rap quite early
on.</em></p>

<p><strong>Aye, and you see how dub influenced music worldwide. I’ve been noticing
Afro-house having a similar reach lately.</strong></p>

<p><em>Africa has so many different countries with their own traditions and own
styles, but certainly around that time they would have had a lot of influence
from what was coming out of Britain and America.</em></p>

<p><strong>I suppose folk in Britain and America had a lot more access to the mass
production and distribution required to get their music heard internationally.</strong></p>

<p><em>A lot of these things are very popular in their own country and only certain
ones break through internationally. There are certainly people that can help
give it a boost. Paul Simon recorded an album with African musicians in the
“Graceland” album a number of years ago. And he got a lot of criticism because
South Africa had apartheid going on and there were supposed to be cultural
boycotts.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Graceland_cover_-_Paul_Simon.jpg" alt="Graceland album cover by Paul Simon" style="width: 100%;" />
  <figcaption>Graceland by Paul Simon. Via <a href="https://commons.wikimedia.org/wiki/File:Graceland_cover_-_Paul_Simon.jpg">Wikimedia Commons</a></figcaption>
</figure>

<p><em>However, I think his point was more that “this is the cultural bit and we’re
actually paying people quite a lot more than the going rate”; and some of them
got successful careers out of it internationally.</em></p>

<p><strong>I wonder how many of those musicians were hitting oot with ‘I love apartheid,
now here’s Wonderwall.’ Probably not fans of the regime themselves.</strong></p>

<p><em>Most of the South African musicians involved were Black artists who had lived
under apartheid and whose careers were constrained by it — but I think the
boycott of South Africa was for the whole country. Therefore, even if you were
working with people who were victims of it, it was still frowned upon in many
ways. That being said, I think Paul Simon was quite a tough guy with a lot of
self-belief, so he just did it anyway.</em></p>

<p><strong>This was all well before my time, did it seem like the boycott was a
significant part of how the apartheid came to an end?</strong></p>

<p><em>Probably yes, but there are lots of factors beyond that.</em></p>

<p><strong>Well, thanks for this chat—there are plenty of other threads we could pull on.
The Virgin Megastores opening, people you’ve met over the years. Whenever a
random track comes up you seem to have an anecdote ready.</strong></p>

<p><em>I think for certain things I have quite a good memory. There’s this common
thing that for some people, there’s certain types of music that they liked when
they were in their late teens and that’s what they like forever. Whereas I’ve
always wanted to find new things; and there are some people like that, but I
think that’s the minority because you have to put some effort into it, and you
do have to be interested. And if you’re interested enough you will remember
these things.</em></p>

<p><strong>I think to this day you’re my main source of interesting new music. I find
stuff on my own, but it’s more through happenstance than actively seeking it
out.</strong></p>

<p><em>I think if you’re interested in music quite a lot, it ties in with so many
other things. That would lead you into particular types of books or films or
art. It’s all tied together.</em></p>

<p><strong>Cheers da!</strong></p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="music" /><category term="interviews" /><summary type="html"><![CDATA[In this post, I chat with a former New Musical Express (NME) writer Glenn Gibson (aka, my da) about his experiences breaking into music journalism in the 1970s-80s, the evolution of music publications, the development of Scotland’s music scene during the punk and post-punk era, and various other bits and pieces.]]></summary></entry><entry><title type="html">Invited talk at Alces Flight 2025</title><link href="https://gibsonic.org/blog/2025/10/31/alces_flight/" rel="alternate" type="text/html" title="Invited talk at Alces Flight 2025" /><published>2025-10-31T10:20:08+00:00</published><updated>2025-10-31T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/31/alces_flight</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/31/alces_flight/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-alces-flight.png" width="1024" /></p>

<p>I was honoured to be invited to give a talk at the
<a href="https://alces.network/flight-2025/">Alces Flight 2025</a> conference, which took
place in London, UK, in October 2025.</p>

<p>My talk discussed how interdisciplinary collaboration and playfulness can be
powerful tools, especially for early-career researchers and engineers.</p>

<p>I shared some of my experiences from my PhD and industry work.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="talks" /><category term="compilers" /><category term="dse" /><summary type="html"><![CDATA[I was honoured to be invited to give a talk at the Alces Flight 2025 conference, which took place in London, UK, in October 2025. My talk discussed how interdisciplinary collaboration and playfulness can be powerful tools, especially for early-career researchers and engineers. I shared some of my experiences from my PhD and industry work.]]></summary></entry><entry><title type="html">How We Survived Mac and Even Laughed</title><link href="https://gibsonic.org/blog/2025/10/12/macbook_setup/" rel="alternate" type="text/html" title="How We Survived Mac and Even Laughed" /><published>2025-10-12T10:20:08+00:00</published><updated>2025-10-12T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/12/macbook_setup</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/12/macbook_setup/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-mac.png" width="1024" /></p>

<p>At work, we recently transitioned everyone to MacBooks. I’ve never used one
before, and had spent the past decade on Linux laptops which I’ve gradually
refined to my liking.</p>

<p>Here’s an inconvenient truth — these machines are not designed to meet my
needs. Being able to modify them to meet those needs has been a challenge. In an
attempt to not alienate my readers, this doesn’t mean that folk with other needs
are wrong. Apple clearly has a particular set of users in mind; I’m just not one
of them.</p>

<p>My philosophy is that the tools I use should behave the way I tell them to. This
post describes some of the issues I’ve encountered trying to achieve that, and
how I’ve worked around them. Overall, I’ve been able to get a workable setup.</p>

<!--more-->

<h1 id="windows-and-workspace-management">Windows and Workspace Management</h1>

<p>One of the most important aspects of my workflow is the ability to manage
windows and workspaces efficiently.</p>

<p>I typically have 10 workspaces, with a relatively strict purpose for each one,
and map each to a keyboard shortcut, usually <code class="language-plaintext highlighter-rouge">super+[0-9]</code>. That way I can
quickly switch between different tasks and contexts (e.g., text editor is in
<code class="language-plaintext highlighter-rouge">super+1</code>, email in <code class="language-plaintext highlighter-rouge">super+9</code>, etc). I can also move windows between workspaces
using <code class="language-plaintext highlighter-rouge">super+shift+[0-9]</code>.</p>

<p>macOS has a concept of ‘Spaces’, which are virtual desktops, but the behaviour I
required of sending windows to specific spaces and switching between them with
keyboard shortcuts wasn’t available out of the box. I had to install a
third-party window manager called <a href="https://github.com/koekeishiya/yabai">yabai</a>.</p>

<p>Yabai is a tiling window manager, which means that it automatically arranges
windows in a grid-like layout. This isn’t something I’ve bothered with before,
but I’ve gotten used to it, and I’ve ended up liking it. I’ve even enabled
tiling windows on my Debian laptop, through KDE Plasma. It also helps to deal
with the limited memory of the MacBook, since it pushes me to not have too many
windows open at once.</p>

<p>Alas, Yabai and some other tools had some issues when the macOS Tahoe update
came out in September 2025. This initially broke my setup, and made me feel like
there was a small-calibre bullet in my skull, as it made everything much harder
to use. Some patches have been released since then, and things are mostly
working now.</p>

<p>Example Yabai configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Re-inject scripting addition if Dock restarts</span>
yabai <span class="nt">-m</span> signal <span class="nt">--add</span> <span class="nv">event</span><span class="o">=</span>dock_did_restart <span class="nv">action</span><span class="o">=</span><span class="s2">"sudo yabai --load-sa"</span>
<span class="nb">sudo </span>yabai <span class="nt">--load-sa</span>

<span class="c"># Update workspace number in SketchyBar</span>
yabai <span class="nt">-m</span> signal <span class="nt">--add</span> <span class="nv">event</span><span class="o">=</span>space_changed <span class="nv">action</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.config/sketchybar/plugins/space_display.sh"</span>

<span class="c"># Set default layout to tiling (bsp)</span>
yabai <span class="nt">-m</span> config layout bsp

<span class="c"># Window padding and gap between tiles</span>
yabai <span class="nt">-m</span> config top_padding         0
yabai <span class="nt">-m</span> config bottom_padding      0
yabai <span class="nt">-m</span> config left_padding        0
yabai <span class="nt">-m</span> config right_padding       0
yabai <span class="nt">-m</span> config window_gap          0

<span class="c"># Focus behavior</span>
yabai <span class="nt">-m</span> config mouse_follows_focus on
yabai <span class="nt">-m</span> config focus_follows_mouse autofocus

<span class="c"># Automatically rebalance split tree when windows are closed</span>
yabai <span class="nt">-m</span> config auto_balance on

<span class="c"># Warp new windows into the tree (default tiling behavior)</span>
yabai <span class="nt">-m</span> config window_placement second_child

<span class="c"># Enable window shadows and blur for floating windows (optional)</span>
yabai <span class="nt">-m</span> config window_shadow on

<span class="c"># Make full-screen toggle (green button) act like regular zoom</span>
yabai <span class="nt">-m</span> config window_opacity off

<span class="c"># Optional: float certain system apps (you can add more)</span>
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"System Preferences"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"System Settings"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"Software Update"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"App Store"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">title</span><span class="o">=</span><span class="s2">"Preferences"</span> <span class="nv">manage</span><span class="o">=</span>off

<span class="c"># Optional: make the Dock not steal space if it's visible</span>
yabai <span class="nt">-m</span> config window_shadow               off
yabai <span class="nt">-m</span> config window_opacity              off
</code></pre></div></div>

<p>You may wish to add spacing between windows, but I prefer to have none.</p>

<h2 id="keyboard-shortcuts">Keyboard shortcuts</h2>

<p>I used <a href="https://github.com/koekeishiya/skhd">skhd</a> to manage the keyboard
shortcuts for Yabai.</p>

<p>For example,</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ctrl - 1 : yabai <span class="nt">-m</span> space <span class="nt">--focus</span> 1

ctrl - m : yabai <span class="nt">-m</span> window <span class="nt">--toggle</span> zoom-parent
ctrl + <span class="nb">shift</span> - c : yabai <span class="nt">-m</span> window <span class="nt">--close</span>

ctrl + <span class="nb">shift</span> - 1 : yabai <span class="nt">-m</span> window <span class="nt">--space</span> 1
</code></pre></div></div>

<p>I became frustrated with additional Mac keyboard issues and made further
changes.</p>

<h1 id="the-keyboard">The Keyboard</h1>

<p>The Mac keyboard is a bit different from a standard PC keyboard. And the keycaps
are labelled differently. That layout doesn’t fit my needs, so I’ve had to make
some changes.</p>

<p>First thing I did was remap the modifier keys in System Settings -&gt; Keyboard -&gt;
Modifier Keys. I set <code class="language-plaintext highlighter-rouge">Caps Lock</code> to <code class="language-plaintext highlighter-rouge">Command</code> (to avoid
<a href="https://news.ycombinator.com/item?id=14370017">Emacs pinky</a>), and <code class="language-plaintext highlighter-rouge">Command</code> to
<code class="language-plaintext highlighter-rouge">Option</code> (aka <code class="language-plaintext highlighter-rouge">Alt</code>). And the <code class="language-plaintext highlighter-rouge">Option</code> to <code class="language-plaintext highlighter-rouge">Control</code> (aka the <code class="language-plaintext highlighter-rouge">Super</code> key). You
may want to swap the <code class="language-plaintext highlighter-rouge">Command</code> and <code class="language-plaintext highlighter-rouge">Control</code> keys instead, if you’re used to the
classic <code class="language-plaintext highlighter-rouge">Ctrl-c</code> and <code class="language-plaintext highlighter-rouge">Ctrl-v</code> shortcuts for copy and paste.</p>

<p>The Mac keyboard is also missing a delete key, so I used an app called
<a href="https://karabiner-elements.pqrs.org/">Karabiner-Elements</a> to map
<code class="language-plaintext highlighter-rouge">Shift+Backspace</code> to <code class="language-plaintext highlighter-rouge">Delete</code>. It has a GUI for remapping, and also has a JSON
config file.</p>

<p>So for that example we can have:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"profiles"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"complex_modifications"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"rules"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                    </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Shift + Delete = Forward Delete"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"manipulators"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                            </span><span class="p">{</span><span class="w">
                                </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                                    </span><span class="nl">"key_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"delete_or_backspace"</span><span class="p">,</span><span class="w">
                                    </span><span class="nl">"modifiers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"mandatory"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"shift"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w">
                                </span><span class="p">},</span><span class="w">
                                </span><span class="nl">"to"</span><span class="p">:</span><span class="w"> </span><span class="p">[{</span><span class="w"> </span><span class="nl">"key_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"delete_forward"</span><span class="w"> </span><span class="p">}],</span><span class="w">
                                </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"basic"</span><span class="w">
                            </span><span class="p">}</span><span class="w">
                        </span><span class="p">]</span><span class="w">
                    </span><span class="p">},</span><span class="w">
</span></code></pre></div></div>

<p>Other remaps worth considering include tilde (<code class="language-plaintext highlighter-rouge">~</code>), quote (<code class="language-plaintext highlighter-rouge">"</code>), at (<code class="language-plaintext highlighter-rouge">@</code>), and
backslash (<code class="language-plaintext highlighter-rouge">\</code>).</p>

<h1 id="external-monitor-issues">External Monitor Issues</h1>

<p>One of the most surprising issues was connecting to an external monitor. I like
to connect the laptop to an external monitor, and I want the external monitor to
be my <em>only</em> display (i.e., turn off the laptop screen). One monitor is
sufficient for my workflow. It turns out, for some reason, this isn’t possible
in Mac out of the box.</p>

<p>One <em>can</em> use “clamshell mode”, where if you close the laptop lid, the external
monitor will become the only display. However, this means that you cannot use
the laptop keyboard, and I prefer to use the laptop keyboard for consistency.</p>

<p>I had to install third-party software to achieve this, called
<a href="https://github.com/waydabber/BetterDisplay">BetterDisplay</a>. In its settings, I
then navigated to Displays-&gt;Overview-&gt;Connection Management Settings-&gt;Disconnect
built-in display when an external display is connected. This capability should
be built into the OS; it exists in most other systems.</p>

<h1 id="sketchybar">SketchyBar</h1>

<p>As part of using Yabai, I wanted a status bar that could show me the current
workspace I’m using. However, out of the box, I couldn’t find a way to do this.</p>

<p>Therefore I used a third-party status bar called
<a href="https://github.com/FelixKratz/SketchyBar">SketchyBar</a>, which is highly
customizable.</p>

<p>I opted to keep it simple, with the current workspace number, to the right of
the battery level.</p>

<p><img src="https://gibsonic.org/assets/pics/2025-10-screenshot.png" alt="Screenshot of desktop" width="1024" /></p>

<p>The default macOS status bar remains accessible with this configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sketchybar <span class="nt">--add</span> item hide left <span class="se">\</span>
           <span class="nt">--set</span> hide <span class="nv">script</span><span class="o">=</span><span class="s2">"sketchybar --bar hidden=on; sleep 5; sketchybar --bar hidden=off"</span> <span class="se">\</span>
           <span class="nt">--subscribe</span> hide mouse.entered.global
</code></pre></div></div>

<p>But I’m grateful that SketchyBar exists, since there’s a lot of unnecessary
menus and icons in the default Mac status bar.</p>

<h1 id="hiding-the-mouse-pointer">Hiding the Mouse Pointer</h1>

<p>I haven’t fully reached the point of never using the mouse, especially when much
of the web is still designed for mouse interaction. However, I tend to use the
mouse a lot less than most people. Therefore, I want the mouse pointer to
disappear when I’m not using it. To achieve this, I used a third-party app
called
<a href="https://doomlaser.com/cursorcerer-hide-your-cursor-at-will/">cursorcerer</a>.</p>

<h1 id="emacs">Emacs</h1>

<p>The <a href="https://github.com/d12frosted/homebrew-emacs-plus">Emacs Plus formula</a> from
Homebrew is pretty good, but it doesn’t install a <code class="language-plaintext highlighter-rouge">.app</code> file into
<code class="language-plaintext highlighter-rouge">/Applications</code> by default.</p>

<p>I had to copy the <code class="language-plaintext highlighter-rouge">.app</code> file into <code class="language-plaintext highlighter-rouge">/Applications</code> for the shortcuts to work.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo cp</span> <span class="nt">-R</span> /opt/homebrew/opt/emacs-plus/Emacs.app /Applications
</code></pre></div></div>

<p>I also had to add <code class="language-plaintext highlighter-rouge">(add-to-list 'default-frame-alist '(undecorated . t))</code> to my
<code class="language-plaintext highlighter-rouge">~/.config/emacs/early-init.el</code> file to remove the title bar, and rounded
corners, which I consider unnecessary.</p>

<h1 id="terminal">Terminal</h1>

<p>Alas, I’m not so deep in the Emacs bucket that I use it as my terminal emulator.
I prefer to use a separate terminal emulator, with tabs, and an extra level of
nesting with tmux.</p>

<p>The default terminal on Mac had strange keybindings, and the app <code class="language-plaintext highlighter-rouge">iTerm2</code> had
similar issues.</p>

<p>I ended up using <code class="language-plaintext highlighter-rouge">kitty</code>, which allowed me to configure the keybindings to match
my needs with a simple config file.</p>

<h1 id="conclusion">Conclusion</h1>

<p>There are many more issues I’ve encountered, but these are the main ones that
have got in the way of my workflow. There is a large community of third-party
tools that may be better suited to meet the needs of your workflow, and I’m sure
folk out there have even better setups. For me, this was the minimum viable
setup to get my work done.</p>

<p>On the bright side, the experience of setting up a new environment has allowed
me to feed back some improvements into my normal workflow on Linux as well. For
example, Shift+Backspace to Delete, and tiling window management. Also, missing
the Trackpoint on the Mac keyboard has pushed me to use the keyboard more, which
feels like a win (in the most meaningless sense).</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="linux" /><category term="mac" /><category term="emacs" /><category term="dev" /><category term="workflow" /><summary type="html"><![CDATA[At work, we recently transitioned everyone to MacBooks. I’ve never used one before, and had spent the past decade on Linux laptops which I’ve gradually refined to my liking. Here’s an inconvenient truth — these machines are not designed to meet my needs. Being able to modify them to meet those needs has been a challenge. In an attempt to not alienate my readers, this doesn’t mean that folk with other needs are wrong. Apple clearly has a particular set of users in mind; I’m just not one of them. My philosophy is that the tools I use should behave the way I tell them to. This post describes some of the issues I’ve encountered trying to achieve that, and how I’ve worked around them. Overall, I’ve been able to get a workable setup.]]></summary></entry><entry><title type="html">Show Me Your Code: Binary White Dwarfs &amp;amp; Melize Ferrus</title><link href="https://gibsonic.org/blog/2025/10/11/bwd/" rel="alternate" type="text/html" title="Show Me Your Code: Binary White Dwarfs &amp;amp; Melize Ferrus" /><published>2025-10-11T10:20:08+00:00</published><updated>2025-10-11T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/11/bwd</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/11/bwd/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-bwd.png" width="1024" /></p>

<p>I’ve been chatting recently with
<a href="https://orcid.org/0000-0002-2842-2067">Melize Ferrus</a>, currently working on
<span class="pronoun" data-type="possessive"></span> PhD in physics and studying
various aspects of gravitational waves.</p>

<p>It’s not an area I have much expertise in, but through a series of chats and
playing around with some of <span class="pronoun" data-type="possessive"></span>
code (and making some fun demos), I thought I’d discuss what I’ve learned. This
is not a deep dive into the physics, but rather an exercise in cross-discipline
communication, and a chance to play with some Python code. I wrap up with a Q&amp;A
to hear <span class="pronoun" data-type="possessive"></span> take on physics and collaboration.</p>

<!--more-->

<p>I’ve asked Melize to write some clarifications and commentary, which will appear
in block quotes like this:</p>

<blockquote>
  <p>What it do, what it does 🥘</p>
</blockquote>

<p>The rest of the text is my understanding, and may contain errors. Anything you
see that is wrong is my fault, not Melize’s (including quote transcription).
Everything should be prefixed with “I reckon”. You can read more about Melize’s
work on gravitational waves in
<a href="https://nautil.us/a-supermassive-test-for-einsteins-famous-theory-312691/">this article</a>.</p>

<p>Melize’s code is closed source for now while <span class="pronoun" data-type="subject"></span> works on some active areas of research, but I was
given access to it for this exercise. The <a href="https://www.astropy.org/"><code class="language-plaintext highlighter-rouge">astropy</code></a>
and <a href="https://numpy.org/"><code class="language-plaintext highlighter-rouge">numpy</code></a> libraries are used extensively.</p>

<h1 id="the-problem-area">The Problem Area</h1>

<p>The code that Melize shared with me was looking at binary white dwarf (BWD)
systems. These are pairs of white dwarf stars (which are the cores of dead
stars) orbiting each other.</p>

<p>There are a few reasons why these systems are interesting to study. From what I
gather though, of particular interest is that when these stars get close to each
other, they can produce very small gravitational waves.</p>

<blockquote>
  <p>When the white dwarfs get close enough that they become bound and start
orbiting each other, they emit gravitational waves. We’re mostly looking at
ones inside our own galaxy, because anything further out would be way too
faint to detect.</p>
</blockquote>

<p>It is difficult to detect gravitational waves from such small systems, but the
reason why we care is that they contribute noise, or “background radiation”, to
the gravitational wave signals we do care about, such as those from black hole
mergers.</p>

<p>Therefore, understanding these white dwarf systems helps us to better interpret
the gravitational wave data we receive from detectors like
<a href="https://en.wikipedia.org/wiki/LIGO">LIGO</a> and
<a href="https://www.virgo-gw.eu/science/gw-universe/the-first-detections/">Virgo</a>.</p>

<blockquote>
  <p>In my case the work’s for LISA — the space-based gravitational wave detector.
It’ll be much more sensitive and looks at a totally different frequency range
than the ground ones like LIGO or Virgo. You need it in space, because the
arms have to be effectively millions of kilometers long. Ground detectors
catch signals lasting less than a second; LISA will see them for weeks or even
months. That means we can detect black holes long before they merge and
coordinate with telescopes to watch the same event. It’s going to open up a
lot for cosmology and multi-messenger studies.</p>
</blockquote>

<p>So how does Melize’s code tackle this problem?</p>

<h1 id="the-code">The Code</h1>

<p>I saw that Melize’s code had two main parts, both of which use <em>Gibbs Sampling</em>.
Gibbs sampling is a statistical technique used to generate samples from a
probability distribution. We don’t need to use “real” data points from
astronomical observations, especially with the number of data points we need.
Instead, we can use our models of the Galaxy and the binary white dwarf systems
to generate synthetic data points that are statistically similar to what we
might observe.</p>

<blockquote>
  <p>I’d maybe mention it’s a Monte Carlo method — Gibbs sampling is just one type
of that. There are a bunch of approaches; this is the one I happened to use.</p>
</blockquote>

<p>The two main uses of Gibbs sampling in <span class="pronoun" data-type="possessive"></span> code were:</p>

<ul>
  <li>Drawing samples of what the binary white dwarf systems might look like (e.g.,
their masses, distances, and orbital periods).</li>
  <li>Generating <em>where</em> in the galaxy these systems might be located.</li>
</ul>

<p>Boffins have modelled what we think the distribution of these systems looks
like, and this code is drawing samples from this distribution. The specifics of
the distributions are not important for this discussion, and not something I’ve
taken the time to understand.</p>

<blockquote>
  <p>It’s only separated into two parts because I’m lazy. Theoretically they could
all live in the same Gibbs sampler. It’s on my to-do list to merge them into a
proper joint distribution.</p>
</blockquote>

<h1 id="binary-white-dwarf-systems">Binary White Dwarf Systems</h1>

<p>When we generate a sample of a binary white dwarf system, we are generating:</p>

<ul>
  <li>The mass of the first white dwarf (in solar masses).</li>
  <li>The mass of the second white dwarf (in solar masses).</li>
  <li>Their semi-major axis (in solar radii) — essentially the orbital radius, but
these orbits aren’t circular.</li>
  <li>Their orbital eccentricity (what shape their orbit is).</li>
</ul>

<blockquote>
  <p>Semi-major axis is the halfway point of the furthest distance between the two
bodies in their orbit.</p>
</blockquote>

<p>For example, a sample I generated from Melize’s code was:</p>

<p><strong>Example Binary White Dwarf System</strong></p>

<!-- prettier-ignore-start -->
<p>\(\begin{aligned}
m_1 &amp;= 1.33\,M_\odot \\
m_2 &amp;= 0.64\,M_\odot \\
e   &amp;= 0.38 \\
a   &amp;= 7.26 \times 10^5\,R_\odot
\end{aligned}\)
<!-- prettier-ignore-end --></p>

<p>To help with my own exploration, I also gave each system a random name using 2
words from the <a href="https://www.eff.org/dice">EFF Long Wordlist</a>.</p>

<p>E.g.,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>overrun-nicotine
stack-thursday
goldmine-undesired
strained-hurried
ecologist-undead
cherisher-degree
supermom-unsigned
rescuer-sternum
zebra-crepe
</code></pre></div></div>

<p>From this code, we can generate as many samples as we want, and our set of
binary white dwarf systems will be distributed according to our model.</p>

<p><strong>Melize, what can we do with these samples?</strong></p>

<blockquote>
  <p>What I’m actually computing is the gravitational-wave power contributed by all
the white dwarfs at each discrete frequency. E.g., using some nonsense numbers
and units, it might give one million watts at 1 mHz and something else at 10
mHz. Let’s say those are the bands LISA’s interferometer is looking at, and
that helps us correct our observations. That’s my focus, though you could use
the samples for other analyses too.</p>
</blockquote>

<h1 id="galactic-coordinates">Galactic Coordinates</h1>

<p>We expect the white dwarf systems to be distributed around the Milky Way galaxy,
with a higher density towards the center of the galaxy, and a lower density as
we move away from the center.</p>

<p>The galaxy is modelled as a disk, with a bulge in the center. Melize’s model
generates “2D cylindrical galactic coordinates”, which are:</p>

<ul>
  <li>(R): radial distance: the distance from the center of the galaxy.</li>
  <li>(Z): the vertical distance above or below the galactic midplane.</li>
</ul>

<blockquote>
  <p>The coordinates are cylindrical — the center of the galaxy’s at (0, 0).
They’re distributed to match how main-sequence stars are spread throughout the
Milky Way. From a logical standpoint they’re just dead stars, so BWDs will be
wherever stars are. I can’t think of a strong reason for their distribution to
be very different.</p>
</blockquote>

<p>This is in contrast to the more familiar Cartesian coordinates <code class="language-plaintext highlighter-rouge">(x, y, z)</code>.
However, to convert from galactic coordinates to Cartesian coordinates, we also
need the “azimuthal” angle (φ), which is the angle around the center of the
galaxy. This requires an assumption about how the systems are distributed
<em>around</em> the galaxy. This isn’t necessary for Melize’s work, but I wanted to
visualise the results in a format I was more familiar with.</p>

<p>Therefore I added a third step to the code, which was to draw a random angle
between <code class="language-plaintext highlighter-rouge">[0, τ]</code>, and then convert from galactic coordinates to Cartesian ones.
We already have the <code class="language-plaintext highlighter-rouge">Z</code> coordinate, and we can convert from <code class="language-plaintext highlighter-rouge">(R, φ)</code> to <code class="language-plaintext highlighter-rouge">(x, y)</code>
using:</p>

<!-- prettier-ignore-start -->
<p>\(\begin{aligned}
x &amp;= R \cos(\phi) \\
y &amp;= R \sin(\phi)
\end{aligned}\)
<!-- prettier-ignore-end --></p>

<blockquote>
  <p>For what I’m doing, you do eventually need the azimuthal angle because you
need to know where the binary is located relative to the gravitational wave.
But it’s uniform, so there’s no need to sample it — it’s just drawn uniformly,
sometimes conditional on other factors.</p>
</blockquote>

<h1 id="visualisation">Visualisation</h1>

<p>With Melize’s code, and some minor data transformation, we can now generate
5,000 BWD systems, and also generate their positions in the galaxy. The code is
capable of generating as many samples as we want, but for my purposes I kept the
number small.</p>

<p>This plot is interactive, using the <code class="language-plaintext highlighter-rouge">plotly</code> library, and its <code class="language-plaintext highlighter-rouge">go.Scatter3d</code>
tool. I initially made this in a Jupyter notebook, and then exported it to a
format that can run in the browser using Plotly’s JavaScript library, using
<code class="language-plaintext highlighter-rouge">fig.write_json("2025-10-binaries.json")</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Create an interactive 3D scatter plot of the sampled systems
</span><span class="kn">import</span> <span class="n">plotly.graph_objects</span> <span class="k">as</span> <span class="n">go</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">go</span><span class="p">.</span><span class="nc">Figure</span><span class="p">(</span>
    <span class="n">go</span><span class="p">.</span><span class="nc">Scatter3d</span><span class="p">(</span>
        <span class="n">x</span><span class="o">=</span><span class="n">x</span><span class="p">,</span>
        <span class="n">y</span><span class="o">=</span><span class="n">y</span><span class="p">,</span>
        <span class="n">z</span><span class="o">=</span><span class="n">z_vals</span><span class="p">,</span>
        <span class="n">mode</span><span class="o">=</span><span class="sh">"</span><span class="s">markers</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">text</span><span class="o">=</span><span class="n">hover_text</span><span class="p">,</span>
        <span class="n">hoverinfo</span><span class="o">=</span><span class="sh">"</span><span class="s">text</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">marker</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span>
            <span class="n">size</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
            <span class="n">color</span><span class="o">=</span><span class="n">m1_vals</span><span class="p">,</span>
            <span class="n">colorscale</span><span class="o">=</span><span class="sh">"</span><span class="s">Turbo</span><span class="sh">"</span><span class="p">,</span>
            <span class="n">colorbar</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="sh">"</span><span class="s">Primary Mass [M☉]</span><span class="sh">"</span><span class="p">,</span> <span class="n">tickcolor</span><span class="o">=</span><span class="sh">"</span><span class="s">white</span><span class="sh">"</span><span class="p">),</span>
            <span class="n">opacity</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span>
        <span class="p">),</span>
    <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<p>You can see it below, if your browser supports it.</p>

<div id="binaries_plot" style="width:100%;height:600px;"></div>

<p>If you hover over a point, it will show you the details of that binary white
dwarf system, including the randomly generated name I added.</p>

<h1 id="audio-shenanigans">Audio Shenanigans</h1>

<p>Next, I wanted to do something more playful. Using the generated BWD systems, I
tried out a few techniques to turn them into musical notes. I spent some time
tuning how different parameters influenced the audio.</p>

<p>I’ve not done much audio programming before, so I kept it simple, using 4 basic
waveform types: sine, square, snare, and kick.</p>

<p><img src="/assets/pics/2025-10-waves.png" alt="Waveforms" style="width:100%;max-width:800px;margin-bottom:1rem;" /></p>
<div id="waves_audio_controls" style="display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;
            margin-bottom:2rem;position:relative;z-index:1;">
  <button onclick="playArray(window.data_sine)">▶ Sine</button>
  <button onclick="playArray(window.data_square)">▶ Square</button>
  <button onclick="playArray(window.data_snare)">▶ Snare</button>
  <button onclick="playArray(window.data_kick)">▶ Kick</button>
</div>

<p>I generated a bunch of BWD samples, and checked the parameter ranges so I could
normalise them.</p>

<p>My code ended up being quite hacky:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">bwd_to_voice</span><span class="p">(</span><span class="n">m1</span><span class="p">,</span> <span class="n">m2</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">norm_ranges</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Map BWD parameters to sound features and instrument type.</span><span class="sh">"""</span>
    <span class="n">nm1</span><span class="p">,</span> <span class="n">nm2</span><span class="p">,</span> <span class="n">ne</span><span class="p">,</span> <span class="n">na</span> <span class="o">=</span> <span class="n">norm_ranges</span>
    <span class="n">mass_avg</span> <span class="o">=</span> <span class="p">(</span><span class="n">m1</span> <span class="o">-</span> <span class="n">nm1</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">nm1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">nm1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">ecc</span> <span class="o">=</span> <span class="p">(</span><span class="n">e</span> <span class="o">-</span> <span class="n">ne</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">ne</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">ne</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">sep</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">na</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">na</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">na</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">q</span> <span class="o">=</span> <span class="n">m2</span> <span class="o">/</span> <span class="n">m1</span>
    <span class="n">asym</span> <span class="o">=</span> <span class="nf">abs</span><span class="p">(</span><span class="n">m1</span> <span class="o">-</span> <span class="n">m2</span><span class="p">)</span> <span class="o">/</span> <span class="n">m1</span>

    <span class="c1"># instrument choice
</span>    <span class="k">if</span> <span class="n">mass_avg</span> <span class="o">&gt;</span> <span class="mf">0.8</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">kick</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">ecc</span> <span class="o">&gt;</span> <span class="mf">0.7</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">snare</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">asym</span> <span class="o">&gt;</span> <span class="mf">0.3</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">square</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">sine</span><span class="sh">"</span>

    <span class="n">freq</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">+</span> <span class="mi">800</span> <span class="o">*</span> <span class="n">mass_avg</span>
    <span class="n">dur</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="o">+</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">sep</span><span class="p">)</span>
    <span class="n">vol</span> <span class="o">=</span> <span class="mf">0.3</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">ecc</span>
    <span class="k">return</span> <span class="n">freq</span><span class="p">,</span> <span class="n">dur</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="n">voice</span>
</code></pre></div></div>

<p>With a constant BPM, I passed binary white dwarf systems through this code,
making one note each, and generated the following track:</p>

<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:1.5rem 0;">
  <iframe src="https://www.youtube.com/embed/xEgBRG2BrM0" title="YouTube video player" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="">
  </iframe>
</div>

<p>A tad atonal, which makes sense since we’re mapping astronomical parameters to
musical ones without any harmonic constraints. Maybe I need to read more music
theory. However, it grows on me the more I generate and listen to it.</p>

<p>Perhaps it’s hubris to think that randomly generated white dwarf systems would
immediately make good music, but it’s fun to try.</p>

<blockquote>
  <p>I can’t wait to somehow contribute to a future post where we come at music
from the mathematical angle — figuring out what makes music sound good without
actually knowing what the notes mean.</p>
</blockquote>

<h1 id="qa">Q&amp;A</h1>

<p>Now that I’ve shown some of my hacking around with Melize’s code, here I take
the opportunity to ask <span class="pronoun" data-type="object"></span> some
general questions.</p>

<p><strong>What got you interested in this area of research?</strong></p>

<blockquote>
  <p>Honestly, nothing in particular. I always wanted to be an astronomer as a kid.
At some point I realized I liked physics, so I thought astrophysics would be
cool.</p>

  <p>But I didn’t really know how to read my college website properly, so I didn’t
realize they didn’t even have astronomy. I knew they had physics, but I didn’t
check the course list well enough. Once I was there, I realized—oh, there’s
nothing astronomy-related here.</p>

  <p>I got involved in aerospace engineering stuff for a bit, then kind of gave up
and moved on. Later, I heard about an internship at the Flatiron Institute for
people in the National Society for Black Physicists. I applied, got sent a
list of different research topics, and picked my top three. The one I ended up
doing was literally my lowest-ranked choice.</p>

  <p>I think my top pick was something about solar oscillations, and the second one
I forget. But yeah, I ended up getting the third one, and over the course of
the internship I realized I really liked it. So there was no grand plan like,
“I’ve always wanted to work on black holes.” It just kind of happened.</p>
</blockquote>

<p><strong>What are some big open questions in this area of research that you’re
interested in?</strong></p>

<blockquote>
  <p>I work across a pretty wide range of things in gravitational waves. What I’m
doing now is different from what I did with at Flatiron, and different again
from what I did at King’s.</p>

  <p>On the numerical relativity side, one big question is whether we can come up
with a model or theorem that works for the merger phase of black hole
collisions. We already have post-Newtonian approximations for the inspiral,
and quasi-normal modes for the ringdown. Those let you predict what the
gravitational wave looks like if you know the parameters of the system.</p>

  <p>But for that last bit, right before the black holes coalesce, there’s no
theorem—just heavy computation. It would be great if we had a simpler equation
or model instead of running six-hour-long simulations for that one stage.</p>

  <p>Then there’s eccentricity. Black hole mergers can have different
eccentricities, and that changes the whole signal. But those effects can look
like other things—spin, non-vacuum conditions, whatever. So it’s hard to tell
what’s what. We usually assume circular orbits, but they’re often not.
Understanding the typical black hole orbit better would help a lot—both for
improving models and for things like star formation studies.</p>

  <p>For the LISA mission, a huge open question is what we’ll learn about
cosmology. LIGO only catches the last second or so of a merger. LISA will
detect black holes a month in advance. That means you can get detailed
parameters early, subtract out the known signals, and study what’s
left—possibly signs of inflation, cosmic strings, or first-order phase
transitions. The future looks really exciting for cosmology.</p>
</blockquote>

<p><strong>You deal with some pretty large simulations and computations. Would you say
that programming is a big part of your work? Is there enough collaboration
between physicists and computer experts?</strong></p>

<blockquote>
  <p>Yeah, programming’s a big part of it. But I’d say most physicists are computer
experts only in the sense that they know enough to make their own stuff work.
We’re not computer experts broadly.</p>

  <p>Like, you [ed: Perry] know enough physics to help me out with something, but
not enough physics overall to anticipate what I might need. Same for me—I know
enough computational stuff to get results, but I don’t always follow the best
practices. Someone else could look at my code and think, “Sure, it works, but
this could be done way better.”</p>

  <p>There could definitely be more collaboration. Everyone’s under pressure to
produce results quickly, so code often ends up written in brute-force, opaque
ways. Later, when new people join, they spend weeks just figuring out what the
code even does. Half of it could’ve been explained in a docstring or wiki.</p>

  <p>A lot of scientific code isn’t open source. That really limits reproducibility
and collaboration. Sometimes groups hoard code to keep control—people have to
email them to run a simulation instead of doing it themselves. Then those
teams rack up citations for just pressing run. Nothing’s truly replicable
because others can’t see the underlying code.</p>

  <p>I’ve even been on papers where the authors said they were using the “highly
precise [system] code.” But how do you know it’s precise? You’ve never seen
the infrastructure. Everyone assumes it’s right because a big name’s attached.
It’s very anti-scientific—this blind trust that something’s correct just
because of who made it.</p>
</blockquote>

<p><strong>Amongst other things, you’re black, and present pretty femme, which is still
relatively rare in physics. Have you had any interesting or noteworthy
experiences through this lens?</strong></p>

<blockquote>
  <p>I’ve got a few specific examples, but I don’t want to call anyone out.</p>

  <p>I get mistaken for other people a lot, even at conferences. It happens so
often it’s almost funny, except it’s not.</p>

  <p>Like, once at a conference, I asked in the group chat if anyone had
painkillers because I had cramps. A guy brought me one, fine. The next day, he
said he’d seen “me” while biking and shouted, “Do you still need the
drugs?”—but it was just some random woman with similar hair. He figured that
must be me.</p>

  <p>I’ve also been to plenty of conferences where no one sits with me. Literally,
people will fill every seat around me but not next to me. It feels isolating.</p>

  <p>It’s not that anyone’s openly rude. It’s just that constant, quiet exclusion.
Seeing your peers welcomed while you’re sidelined makes you ask why. It’s
tiring.</p>
</blockquote>

<p><strong>What are the biggest uncertainties in the models you work with?</strong></p>

<blockquote>
  <p>Oh, huge ones. One of the biggest is the merger rate—how many mergers happen
per year. The uncertainty can be as large as the value itself.</p>

  <p>Let me bring up one of my favorite ones. It’s very entertaining to me</p>
</blockquote>

<!-- prettier-ignore-start -->
<p><em>(<span class="pronoun" data-type="subject"></span> types on <span class="pronoun" data-type="possessive"></span> laptop for a moment, then starts laughing.)</em>
<!-- prettier-ignore-end --></p>

<blockquote>
  <p><a href="https://journals.aps.org/prx/pdf/10.1103/PhysRevX.9.031040">Here we go: neutron star mergers [page 26]</a>.
The estimated rate is 920 per gigaparsec cubed per year, with a +2,220 / –790
margin!</p>

  <p>Hands down, that’s my favourite. I roll around in my non-existent grave to
this shit. It’s a couple of years old, so newer estimates are probably tighter
now. This is for the first two observations of LIGO with the neutron star
detection for the collision rate.</p>

  <p>Yeah, I have a lot of confidence in all of the different things I generate
using those kinds of things…</p>
</blockquote>

<p><strong>Anything else you want to say?</strong></p>

<blockquote>
  <p>I really like the kind of work I do. I’ve been lucky to move between
institutions and completely change up what I’m working on each time.</p>

  <p>After my year at Flatiron I felt cocky about starting my PhD, “I run this
bitch,” but when I got to King’s it was like starting from scratch again due
to the alternative perspectives on the topic. It’s cool seeing how much
undergrad material—stuff I once thought was useless—actually shows up all the
time.</p>

  <p>In undergrad, you’re rushing to master something in 13 weeks, then it leaks
out of your head. Doing a PhD gives you the time to actually learn it
properly. None of my physics education was a waste. Even the quantum mechanics
I thought I’d never need has ended up being useful.</p>
</blockquote>

<blockquote>
  <p>It gives you time to learn the thing properly, as opposed to learn the thing
in order to pass the test. Yeah, so like if you didn’t do everything perfectly
in your undergrad, it’s fine. I think it’s just that doing a PhD gives you
more appreciation of it.</p>
</blockquote>

<p><strong>Thank you Melize.</strong></p>

<blockquote>
  <p>Thank you Dr Gibson, I’ll see you on GitHub 🙂‍↕️.</p>
</blockquote>

<h1 id="conclusions">Conclusions</h1>

<p>When I talk to specialists in other fields who are articulate and passionate
about their work, I find it infectious. I usually come away with the feeling of
“ah, so it <em>isn’t magic</em>, but <em>it is</em> hard”. I haven’t eaten my intellectual
vegetables by working through general-relativity textbook exercises. However, by
inhabiting Melize’s code for a while, and picking
<span class="pronoun" data-type="possessive"></span> brain, I feel like I’ve
gained a little more appreciation of the field, and the cool people that work in
it.</p>

<script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>

<div id="binaries_plot" style="width:100%;height:600px;"></div>
<script>
fetch('/assets/plotly/2025-10-binaries.json')
  .then(r => r.json())
  .then(fig => Plotly.newPlot('binaries_plot', fig.data, fig.layout, {responsive:true}));
</script>

<script>
fetch('/assets/plotly/2025-10-waves-audio.json')
  .then(r => r.json())
  .then(data => {
    window.data_sine = data.sine;
    window.data_square = data.square;
    window.data_snare = data.snare;
    window.data_kick = data.kick;
  });

function playArray(arr, sampleRate=8000) {
  if (!arr) return;
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const buf = ctx.createBuffer(1, arr.length, sampleRate);
  buf.copyToChannel(Float32Array.from(arr), 0);
  const src = ctx.createBufferSource();
  src.buffer = buf;
  src.connect(ctx.destination);
  src.start();
}
</script>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="python" /><category term="science" /><category term="physics" /><summary type="html"><![CDATA[I’ve been chatting recently with Melize Ferrus, currently working on PhD in physics and studying various aspects of gravitational waves. It’s not an area I have much expertise in, but through a series of chats and playing around with some of code (and making some fun demos), I thought I’d discuss what I’ve learned. This is not a deep dive into the physics, but rather an exercise in cross-discipline communication, and a chance to play with some Python code. I wrap up with a Q&amp;A to hear take on physics and collaboration.]]></summary></entry><entry><title type="html">Simple Workflow Tweaks for Scientific Python Projects</title><link href="https://gibsonic.org/blog/2025/10/05/python_science/" rel="alternate" type="text/html" title="Simple Workflow Tweaks for Scientific Python Projects" /><published>2025-10-05T14:20:08+00:00</published><updated>2025-10-05T14:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/05/python_science</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/05/python_science/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-python_tools.png" width="1024" /></p>

<p>I’ve recently been chatting with a couple of mates who are doing scientific
research using Python. Answering specific code questions is a lot of fun, as I
try to figure out enough of their domain to see if/how I can help.</p>

<p>However, there are some general workflow improvements that I think both they and
other scientific Python programmers could benefit from. In this post, I’ll share
some lightweight workflow improvements that can help make your code better.</p>

<!--more-->

<p>Research code is often different from production software: it doesn’t need to be
as robust or strictly engineered. However, a few simple practices can make it
far more reproducible and maintainable.</p>

<p>In this post, we’ll explore steps to improve reproducibility, collaboration, and
confidence in your results — without overcomplicating your code.</p>

<p>This post assumes you’re using GitHub (or a similar platform like GitLab or
Gitea) for version control. If you’re not yet using a VCS, I highly recommend
starting there.</p>

<p>If you are working on more software-engineering-oriented projects, this post is
probably not for you, as there are many more things you should be doing.</p>

<p>We’ll go through a few simple steps:</p>

<ul>
  <li>Creating a Python package with a reproducible environment.</li>
  <li>Writing tests with <code class="language-plaintext highlighter-rouge">pytest</code> to catch bugs early.</li>
  <li>Using pre-commit hooks to maintain code quality automatically.</li>
  <li>Setting up GitHub Actions to run tests on every push.</li>
</ul>

<h2 id="the-project">The Project</h2>

<p>Let’s say we’re using <a href="https://www.astropy.org/">Astropy</a> to do some cosmology
calculations. This isn’t my area of expertise, I’ve just made some bullshit code
that shows the development practices: apologies if it offends your
sensibilities!</p>

<p>Initially, we explored these calculations in a Jupyter notebook. While notebooks
are great for experimentation, they aren’t ideal for <strong>sharing, testing, or
reusing code</strong>. I’ve seen people with functions they copy between every
notebook, making slight changes each time, and then lose track of which version
is “the good one”.</p>

<p>Our first goal is to take some commonly used functions from the notebook and
turn them into a <strong>small, reusable Python package</strong> that we can import into any
notebook or script.</p>

<h2 id="common-package">Common Package</h2>

<p>The outcome of this section can be seen on commit <code class="language-plaintext highlighter-rouge">ed941a</code> of
<a href="https://github.com/Wheest/cosmole-example/tree/ed941aee1683f3be44d3a497437f221986b86acd">this GitHub repository</a>.
I’ll walk through the steps below.</p>

<p>When you have functions that you want to reuse across multiple notebooks or
scripts, it’s best to put them in a <strong>common package</strong> rather than copying and
pasting. Copying code can quickly lead to inconsistencies and bugs as your code
evolves.</p>

<p>For this project, we’ll create a small package called <code class="language-plaintext highlighter-rouge">cosmole</code> containing three
scripts:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── cosmole
│   ├── __init__.py
│   ├── angular_separation.py
│   ├── convert_equatorial_to_galactic.py
│   └── redshift_to_distance.py
└── notebooks
    └── 2025-10-07-exploration.ipynb
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">__init__.py</code> file defines what is accessible when someone imports the
package:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># cosmole/__init__.py
</span><span class="kn">from</span> <span class="n">.redshift_to_distance</span> <span class="kn">import</span> <span class="n">redshift_to_distance</span>
<span class="kn">from</span> <span class="n">.angular_separation</span> <span class="kn">import</span> <span class="n">angular_separation</span>
<span class="kn">from</span> <span class="n">.convert_equatorial_to_galactic</span> <span class="kn">import</span> <span class="n">convert_equatorial_to_galactic</span>
</code></pre></div></div>

<p>Now (once we’ve finished the following sections), from any notebook or script in
the project, you can import your functions:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">cosmole</span> <span class="kn">import</span> <span class="p">(</span>
    <span class="n">redshift_to_distance</span><span class="p">,</span>
    <span class="n">angular_separation</span><span class="p">,</span>
    <span class="n">convert_equatorial_to_galactic</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div></div>

<h3 id="dependency-management">Dependency Management</h3>

<p>In scientific projects, it’s easy for code to stop working later if software
packages you depend on change. When I was writing up my PhD, I had to regenerate
some plots from my first year and ran into issues because <code class="language-plaintext highlighter-rouge">matplotlib</code> had
changed; I wasn’t sure which version I had originally used — it was a pain.</p>

<p>To avoid “it worked on my machine” problems, we can specify exact package
versions using a <code class="language-plaintext highlighter-rouge">requirements.txt</code> file.</p>

<p>This is a simple text file listing all the Python packages your project depends
on, along with their versions. For our project, you can see it
<a href="https://github.com/Wheest/cosmole-example/blob/main/requirements.txt">here</a>.</p>

<p>You can install these dependencies with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
</code></pre></div></div>

<p>Or with conda:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conda <span class="nb">install</span> <span class="nt">--file</span> requirements.txt
</code></pre></div></div>

<p>This ensures anyone cloning the repository can reproduce your environment and
run your code without surprises.</p>

<h3 id="setting-up-the-package">Setting up the package</h3>

<p>To make Python aware of your <code class="language-plaintext highlighter-rouge">cosmole</code> package, we need a <strong><code class="language-plaintext highlighter-rouge">setup.py</code></strong> file at
the root of the project. This file tells Python how to install your package and
its dependencies. In our example project,
<a href="https://github.com/Wheest/cosmole-example/blob/ed941aee1683f3be44d3a497437f221986b86acd/setup.py">you can see it here</a>.</p>

<p>We can now install our package with:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">-e</span> <span class="nb">.</span>
</code></pre></div></div>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">-e</code> flag means editable — any changes you make to the source code are
reflected immediately when you import the package.</li>
  <li>This is especially handy when working interactively in notebooks.</li>
</ul>

<p>Additionally, adding and executing these lines at the top of your notebooks will
also mean you automatically reload your package whenever you edit any of your
<code class="language-plaintext highlighter-rouge">.py</code> files:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Enable autoreload so that changes in imported modules are reflected automatically
</span><span class="o">%</span><span class="n">load_ext</span> <span class="n">autoreload</span>
<span class="o">%</span><span class="n">autoreload</span> <span class="mi">2</span>
</code></pre></div></div>

<h4 id="note-to-conda-users">Note to Conda users</h4>

<p>If you use Conda, you <em>might</em> need an additional file <code class="language-plaintext highlighter-rouge">pyproject.toml</code> in your
project to ensure that the package installs correctly.</p>

<p>E.g.,</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">[</span><span class="n">build-system</span><span class="k">]</span>
<span class="n">requires</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"setuptools"</span><span class="p">,</span> <span class="s">"wheel"</span><span class="p">]</span>
<span class="n">build-backend</span> <span class="o">=</span><span class="w"> </span><span class="s">"setuptools.build_meta"</span>
</code></pre></div></div>

<p>This is because modern versions of <code class="language-plaintext highlighter-rouge">pip</code> build packages in <strong>isolated
environments</strong>. So you need to specify that <code class="language-plaintext highlighter-rouge">setuptools</code> and <code class="language-plaintext highlighter-rouge">wheel</code> are
required to build the package (which then installs the dependencies from
<code class="language-plaintext highlighter-rouge">requirements.txt</code>).</p>

<h2 id="testing-your-code">Testing Your Code</h2>

<p>The outcome of this section can be seen on commit
<a href="https://github.com/Wheest/cosmole-example/tree/99050481d5165109625f5c3f18eef9442d1ea4ab"><code class="language-plaintext highlighter-rouge">9905048</code></a>.</p>

<p>Once you have refactored your functions into your package, it’s a good idea to
write tests.</p>

<blockquote>
  <p>Actually, one approach is to write the tests <em>first</em> as we’re developing our
initial implementation of our functions (a practice known as test-driven
development). However, in research, this might not always be the most
practical approach.</p>
</blockquote>

<p>Tests help ensure that your code behaves as expected, which is especially useful
when making changes or refactoring. Good test design is an art, thinking about
edge cases and failure modes.</p>

<p>Even if your research code is exploratory, having a few <strong>basic automated
tests</strong> can catch obvious bugs early and give you confidence that updates don’t
break existing functionality.</p>

<p>During development, you might find that a test itself was wrong, or you changed
the intended purpose of a function. In which case, just update the test — make
them work for you!</p>

<p>We can use the <code class="language-plaintext highlighter-rouge">pytest</code> package to write and run tests. For example, let’s test
one of our functions by adding a file
<code class="language-plaintext highlighter-rouge">tests/test_convert_equatorial_to_galactic.py</code> to the project:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">pytest</span>
<span class="kn">from</span> <span class="n">astropy.coordinates</span> <span class="kn">import</span> <span class="n">SkyCoord</span>
<span class="kn">import</span> <span class="n">astropy.units</span> <span class="k">as</span> <span class="n">u</span>
<span class="kn">from</span> <span class="n">cosmole</span> <span class="kn">import</span> <span class="n">convert_equatorial_to_galactic</span>

<span class="k">def</span> <span class="nf">test_convert_equatorial_to_galactic</span><span class="p">():</span>
    <span class="n">ra</span><span class="p">,</span> <span class="n">dec</span> <span class="o">=</span> <span class="mf">83.82208</span><span class="p">,</span> <span class="o">-</span><span class="mf">5.39111</span>  <span class="c1"># Approx location of Orion Nebula
</span>    <span class="n">l</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">convert_equatorial_to_galactic</span><span class="p">(</span><span class="n">ra</span><span class="p">,</span> <span class="n">dec</span><span class="p">)</span>
    <span class="n">coord</span> <span class="o">=</span> <span class="nc">SkyCoord</span><span class="p">(</span><span class="n">ra</span><span class="o">=</span><span class="n">ra</span><span class="o">*</span><span class="n">u</span><span class="p">.</span><span class="n">deg</span><span class="p">,</span> <span class="n">dec</span><span class="o">=</span><span class="n">dec</span><span class="o">*</span><span class="n">u</span><span class="p">.</span><span class="n">deg</span><span class="p">,</span> <span class="n">frame</span><span class="o">=</span><span class="sh">'</span><span class="s">icrs</span><span class="sh">'</span><span class="p">).</span><span class="n">galactic</span>
    <span class="k">assert</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">approx</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span> <span class="o">==</span> <span class="n">coord</span><span class="p">.</span><span class="n">l</span><span class="p">.</span><span class="n">degree</span>
    <span class="k">assert</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">approx</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span> <span class="o">==</span> <span class="n">coord</span><span class="p">.</span><span class="n">b</span><span class="p">.</span><span class="n">degree</span>
</code></pre></div></div>

<p>The assert <code class="language-plaintext highlighter-rouge">pytest.approx</code> lines verify that the function returns the expected
results, raising an error if it doesn’t.</p>

<p>To run the tests, from your project root, run:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pytest
</code></pre></div></div>

<p>You should see output like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_angular_separation.py <span class="nb">.</span>                                                               <span class="o">[</span> 33%]
tests/test_convert_equatorial_to_galactic.py <span class="nb">.</span>                                                   <span class="o">[</span> 66%]
tests/test_redshift_to_distance.py <span class="nb">.</span>
<span class="o">[</span>100%]
</code></pre></div></div>

<p>Which shows that all our tests passed. If we’d introduced a bug (e.g., I
accidentally added 10 to one of my results), the test would catch this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_convert_equatorial_to_galactic.py F                                                   <span class="o">[</span> 66%]
tests/test_redshift_to_distance.py <span class="nb">.</span>                                                             <span class="o">[</span>100%]

<span class="o">===============================================</span> FAILURES <span class="o">===============================================</span>
_________________________________ test_convert_equatorial_to_galactic __________________________________

    def test_convert_equatorial_to_galactic<span class="o">()</span>:
        ra, dec <span class="o">=</span> 83.82208, <span class="nt">-5</span>.39111  <span class="c"># Approx location of Orion Nebula</span>
        l, b <span class="o">=</span> convert_equatorial_to_galactic<span class="o">(</span>ra, dec<span class="o">)</span>
        coord <span class="o">=</span> SkyCoord<span class="o">(</span><span class="nv">ra</span><span class="o">=</span>ra <span class="k">*</span> u.deg, <span class="nv">dec</span><span class="o">=</span>dec <span class="k">*</span> u.deg, <span class="nv">frame</span><span class="o">=</span><span class="s2">"icrs"</span><span class="o">)</span>.galactic
<span class="o">&gt;</span>       assert pytest.approx<span class="o">(</span>l, <span class="nv">rel</span><span class="o">=</span>1e-6<span class="o">)</span> <span class="o">==</span> coord.l.degree
E       assert 219.01374318285238 ± 2.2e-04 <span class="o">==</span> np.float64<span class="o">(</span>209.01374318285238<span class="o">)</span>
E
E         comparison failed
E         Obtained: 209.01374318285238
E         Expected: 219.01374318285238 ± 2.2e-04

tests/test_convert_equatorial_to_galactic.py:11: AssertionError
</code></pre></div></div>

<h3 id="pre-commit-hooks">Pre-commit Hooks</h3>

<p>To help maintain consistent code quality, we can use <strong>pre-commit hooks</strong>. These
are scripts that automatically run <strong>before each commit</strong> to check for common
issues like code formatting, linting, or missing documentation.</p>

<p>The key benefits of pre-commit hooks are:</p>

<ul>
  <li><strong>Catch issues early</strong> — errors or style violations are flagged before they
enter your repository.</li>
  <li><strong>Automatic fixes</strong> — many hooks, like code formatters, can fix problems
automatically, saving time.</li>
  <li><strong>Consistency across contributors</strong> — ensures everyone on the project follows
the same style and quality rules.</li>
</ul>

<h4 id="configuration">Configuration</h4>

<p>Pre-commit hooks are configured in a <code class="language-plaintext highlighter-rouge">.pre-commit-config.yaml</code> file at the root
of your project. For example, a simple configuration might include:</p>

<ul>
  <li><strong>Ruff</strong> — a fast Python linter and code formatter.</li>
  <li><strong>Prettier</strong> — for formatting YAML, Markdown, and JSON.</li>
</ul>

<p>In our example project, you can see the configuration file
<a href="https://github.com/Wheest/cosmole-example/blob/main/.pre-commit-config.yaml">here</a>.</p>

<p>You can install pre-commit and set it up with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>pre-commit
pre-commit <span class="nb">install</span>
</code></pre></div></div>

<p>Now, every time you make a commit, the hooks defined in your configuration file
will run automatically on any files that have changed. You can also run them
manually on <strong>all files</strong> with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pre-commit run <span class="nt">--all-files</span>
</code></pre></div></div>

<p>In our code, several automatic reformatting steps were applied: none of which
should change our functionality, only the neatness of our code. For example,
removing unused <code class="language-plaintext highlighter-rouge">import</code>s, making sure lines don’t get too long, being
consistent with the use of whitespace, etc.</p>

<p>However, there are also some issues that need manual review. For example, Ruff
complained that we had an ambiguous variable name <code class="language-plaintext highlighter-rouge">l</code> (lowercase L - which looks
like a <code class="language-plaintext highlighter-rouge">1</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_convert_equatorial_to_galactic.py:8:5: E741 Ambiguous variable name: `l`
   |
 6 | def test_convert_equatorial_to_galactic():
 7 |     ra, dec = 83.82208, -5.39111  # Approx location of Orion Nebula
 8 |     l, b = convert_equatorial_to_galactic(ra, dec)
   |     ^ E741
 9 |     coord = SkyCoord(ra=ra*u.deg, dec=dec*u.deg, frame='icrs').galactic
10 |     assert pytest.approx(l, rel=1e-6) == coord.l.degree
   |
</code></pre></div></div>

<p>Normally, I’d recommend following the rules — they’re opinionated but usually
sensible.</p>

<p>However, we can tell Ruff to ignore this specific warning by adding a comment to
the end of the line.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">l</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">convert_equatorial_to_galactic</span><span class="p">(</span><span class="n">ra</span><span class="p">,</span> <span class="n">dec</span><span class="p">)</span>  <span class="c1"># noqa: E741
</span></code></pre></div></div>

<p>You <em>can</em> skip pre-commit using <code class="language-plaintext highlighter-rouge">--no-verify</code>, but only do so if you have a good
reason (like it’s 10pm and you just want to get your changes saved before bed
😴).</p>

<p>In my example, you can see all the pre-commit changes in
<a href="https://github.com/Wheest/cosmole-example/commit/d23d21a9a4343d64522cd9ad15745c95c6e45be1"><code class="language-plaintext highlighter-rouge">d23d21a</code></a>.
In practice, these changes would be applied at the time of writing the code in
the first place, but I wanted to show the before-and-after.</p>

<h3 id="github-actions">GitHub Actions</h3>

<p>Now, we have tests and pre-commit hooks, which are great for local development.
However, we also want to make sure that our code is tested when we push changes,
especially if we’re collaborating with others.</p>

<p>GitHub Actions allows you to run workflows on GitHub-hosted machines. While
these have limited compute power, they can easily handle running basic tests and
automation tasks.</p>

<p>For our example, we can create a workflow that runs our tests and pre-commit
hooks on every push to the repository. If your code can run and pass on a
different machine, that is a great indicator that it is reproducible and not
dependent on your local setup.</p>

<p>Let’s do this by creating a file <code class="language-plaintext highlighter-rouge">.github/workflows/ci.yml</code> as shown
<a href="https://github.com/Wheest/cosmole-example/blob/main/.github/workflows/ci.yml">here</a>.</p>

<p>Now, every time you push changes or create a pull request, GitHub Actions will
automatically run your tests and hooks. This adds an extra layer of confidence
and helps maintain a reliable, reproducible scientific codebase.</p>

<p>You can see on the repo’s GitHub page, a yellow circle after we’ve pushed,
meaning the checks are running</p>

<p><img src="/assets/pics/2025-10-05-gh_actions_yellow.png" width="1024" alt="GitHub Actions workflow running" /></p>

<p>You can see initially, this run fails, and we can click on the red ❌ to see the
<a href="https://github.com/Wheest/cosmole-example/actions/runs/18319638023/job/52169145433">terminal logging what went wrong</a>.</p>

<p>In this case, we didn’t actually install our package on the GitHub runner.
Therefore, we need to add <code class="language-plaintext highlighter-rouge">pip install .</code> to the workflow:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install the package</span>
  <span class="na">run</span><span class="pi">:</span> <span class="s">pip install .</span>
</code></pre></div></div>

<p>Now, our code passes!</p>

<p><img src="/assets/pics/2025-10-05-gh_actions_passed.png" width="1024" alt="GitHub Actions workflow passed" /></p>

<p>In future, we’ll be able to see which commits introduced bugs in our code. If
you use a <code class="language-plaintext highlighter-rouge">git</code>
<a href="https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow">feature branch workflow</a>
(using branches for features and PRs), then you can enforce that any commits to
<code class="language-plaintext highlighter-rouge">main</code> <strong>must</strong> pass these checks. However, this may be overkill for a small
research project.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Ultimately, the goal of research code is to help us explore and answer our
research questions. However, small software engineering standards can pay
dividends if applied in a sensible way.</p>

<p>There are more things you may want to explore, for example, you can add more
rules to Ruff
(<a href="https://github.com/Wheest/cosmole-example/pull/1">like enforcing documentation</a>).
Similar workflows can also be applied to projects in other programming
languages. You may also want to standardise your git commit message format,
e.g., using
<a href="https://www.conventionalcommits.org/en/v1.0.0/#summary">Conventional Commits</a>.</p>

<p>P.S. props to my black-hole buddy
<a href="https://orcid.org/0000-0002-2842-2067">Melize</a> for providing the header image,
which is his reproduction of
<a href="https://academic.oup.com/mnras/article/483/4/5518/5251998">Korol et al. 2018</a>.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="python" /><category term="science" /><category term="reproducibility" /><category term="testing" /><category term="github-actions" /><category term="pre-commit" /><summary type="html"><![CDATA[I’ve recently been chatting with a couple of mates who are doing scientific research using Python. Answering specific code questions is a lot of fun, as I try to figure out enough of their domain to see if/how I can help. However, there are some general workflow improvements that I think both they and other scientific Python programmers could benefit from. In this post, I’ll share some lightweight workflow improvements that can help make your code better.]]></summary></entry><entry><title type="html">Calling Clang’s Assembler from C++</title><link href="https://gibsonic.org/blog/2025/06/30/clang_assembler/" rel="alternate" type="text/html" title="Calling Clang’s Assembler from C++" /><published>2025-06-30T10:00:00+00:00</published><updated>2025-06-30T10:00:00+00:00</updated><id>https://gibsonic.org/blog/2025/06/30/clang_assembler</id><content type="html" xml:base="https://gibsonic.org/blog/2025/06/30/clang_assembler/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-06-asm.png" width="1024" /></p>

<p>LLVM is a collection of modular and reusable compiler and toolchain
technologies. It provides a set of libraries and tools for building compilers,
assemblers, linkers, and other related tools.</p>

<p>In a project I was working on, we were using the <code class="language-plaintext highlighter-rouge">clang</code> part of this project to
compile C and LLVM IR code. The code path for these two sources was similar
enough that we could have a single <code class="language-plaintext highlighter-rouge">compile</code> function that passed all the
configuration flags for our usecase.</p>

<p>However, for a new feature, I was generating assembly files directly and wanted
to assemble them into an object file. This post briefly explains how I got this
working and how you can use the <code class="language-plaintext highlighter-rouge">clang</code> libraries to assemble assembly files in
C++.</p>

<!--more-->

<p>As a normal user of the <code class="language-plaintext highlighter-rouge">clang</code> CLI tool, the workflow is the same:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clang <span class="nt">-c</span> my_asm.s <span class="nt">-o</span> my_obj.o  <span class="c"># same interface for C and assembly (.s)</span>
clang <span class="nt">-c</span> main.c <span class="nt">-o</span> my_obj.o
</code></pre></div></div>

<p>However, this approach didn’t work when trying to use the <code class="language-plaintext highlighter-rouge">clang</code> libraries in
C++. I encountered several errors, with unrecognised flags. Some were easy to
fix as they were just flags that were specific to C or LLVM IR that I didn’t
need for assembly. However, one recurring one I got was
<code class="language-plaintext highlighter-rouge">Error: unknown argument: '-filetype'</code>. This seemed to be inserted automatically
when setting up the job, and wasn’t something I could easily remove.</p>

<p>I thought I’d go back to basics, and think about how the <code class="language-plaintext highlighter-rouge">clang</code> toolchain works
under the hood. I was curious about what flags were being inserted under the
hood, so I ran:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clang -### <span class="nt">-c</span> my_asm.s 2&gt; cc1_dump.txt
</code></pre></div></div>

<p>This command printed all the flags passed to the underlying program:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clang version [redacted]
Target: [redacted]-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
 (in-process)
 "/usr/lib/llvm-[redacted]/bin/clang" "-cc1as" "-triple" "[redacted]-linux-gnu" "-filetype" "obj" "-main-file-name" "test_tensor.s" "-target-cpu" "[redacted]" "-fdebug-compilation-dir=/tmp/[redacted]" "-dwarf-debug-producer" "clang version [redacted]" "-dwarf-version=[redacted]" "-mrelocation-model" "pic" "-o" "my_obj.o" "my_asm.s"

</code></pre></div></div>

<p>You’ll note that <code class="language-plaintext highlighter-rouge">clang</code> infers from the file extension that it is an assembly
file, and so passes the <code class="language-plaintext highlighter-rouge">-cc1as</code> flag.</p>

<p>It’s worth noting that the <code class="language-plaintext highlighter-rouge">clang</code> executable isn’t really a compiler, it’s a
compiler <em>driver</em>. <code class="language-plaintext highlighter-rouge">clang -cc1</code> is the compiler, and <code class="language-plaintext highlighter-rouge">clang -cc1as</code> is the
assembler, and these are flags that are passed to the <code class="language-plaintext highlighter-rouge">clang</code> driver to invoke
the appropriate tool. It can also infer the type of file being compiled based on
the file extension, and will pass the appropriate flags to the underlying tools.
However, when we’re using the <code class="language-plaintext highlighter-rouge">clang</code> libraries directly in C++, we’re
responsible for calling the <code class="language-plaintext highlighter-rouge">cc1as</code> program directly to assemble assembly files.</p>

<p>The main program that <code class="language-plaintext highlighter-rouge">cc1as</code> uses is defined under
<a href="https://github.com/llvm/llvm-project/blob/2e7aa7ead6808047df2b7b56bfc725ffc3685e43/clang/tools/driver/cc1as_main.cpp"><code class="language-plaintext highlighter-rouge">clang/tools/driver/cc1as_main.cpp</code></a>,
and adapting this was enough to get this feature working.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="c++" /><category term="compilers" /><category term="llvm" /><category term="clang" /><category term="assembler" /><summary type="html"><![CDATA[LLVM is a collection of modular and reusable compiler and toolchain technologies. It provides a set of libraries and tools for building compilers, assemblers, linkers, and other related tools. In a project I was working on, we were using the clang part of this project to compile C and LLVM IR code. The code path for these two sources was similar enough that we could have a single compile function that passed all the configuration flags for our usecase. However, for a new feature, I was generating assembly files directly and wanted to assemble them into an object file. This post briefly explains how I got this working and how you can use the clang libraries to assemble assembly files in C++.]]></summary></entry><entry><title type="html">Open Source: Petit Pois, a Podcast Archiver and Feed Generator</title><link href="https://gibsonic.org/blog/2025/04/18/petit-pois/" rel="alternate" type="text/html" title="Open Source: Petit Pois, a Podcast Archiver and Feed Generator" /><published>2025-04-18T10:00:00+00:00</published><updated>2025-04-18T10:00:00+00:00</updated><id>https://gibsonic.org/blog/2025/04/18/petit-pois</id><content type="html" xml:base="https://gibsonic.org/blog/2025/04/18/petit-pois/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-04-petit-pois.png" width="1024" /></p>

<p>I’ve just released a new open-source project called <strong>Petit Pois</strong>,
<a href="https://github.com/Wheest/petit-pois">available on my GitHub</a>, written in
Python.</p>

<p>It’s a podcast archive tool and feed generator that allows you to archive
podcast episodes and generate custom feeds for them. The project is designed to
be simple and easy to use, with a focus on flexibility and customisation. I have
a sketch of a workflow for how we can generate private token URLs, and integrate
it with a web server such as Nginx to serve the files.</p>

<p>Most podcasts are shite, but it’s still important that we have archival tools
available, since <em>some</em> of them may be important to preserve for future
generations.</p>

<p>The main goal is for personal archival, preservation, and research use only, as
redistributing or republishing podcast episodes without permission may be
illegal. Big ol’ disclaimer: I encourage users to respect the rights of content
creators and follow copyright laws.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="oss" /><category term="python" /><summary type="html"><![CDATA[I’ve just released a new open-source project called Petit Pois, available on my GitHub, written in Python. It’s a podcast archive tool and feed generator that allows you to archive podcast episodes and generate custom feeds for them. The project is designed to be simple and easy to use, with a focus on flexibility and customisation. I have a sketch of a workflow for how we can generate private token URLs, and integrate it with a web server such as Nginx to serve the files. Most podcasts are shite, but it’s still important that we have archival tools available, since some of them may be important to preserve for future generations. The main goal is for personal archival, preservation, and research use only, as redistributing or republishing podcast episodes without permission may be illegal. Big ol’ disclaimer: I encourage users to respect the rights of content creators and follow copyright laws.]]></summary></entry></feed>