Vortex Panel Method

Try it here

Overview

The Vortex Panel Method (VPM) is a simple aerodynamic tool that is rich enough to capture meaningful flow physics, yet fast enough for design iterations. In this project, I used a 2D axisymmetric VPM to model the flow around a diffuser-augmented wind turbine (DAWT), combining classical potential flow theory with a Joukowsky actuator disk representation of the rotor. The result is a lightweight model that can predict induced velocities and wake development without requiring full CFD.

Why Vortex Panel Method and Model Assumptions

The VPM is based on potential flow theory, which assumes:

  • incompressible flow
  • inviscid flow
  • irrotational flow
  • steady conditions

Instead of solving Navier–Stokes, the geometry is represented using a distribution of panels along its surface, with the panels having attributed vortices. Each vortex influences the surrounding flow (Biot-Savart Law), and the combined effect of all the panels reconstructs the velocity field.

This implementation extends a regular vortex method in two ways:

  1. Axisymmetric formulation (r–x plane)
  2. Coupling with a Joukowsky actuator disk model for the turbine

Instead of applying a simple pressure jump (classic actuator disk), the turbine is modeled as a wake-inducing vortex sheet, which interacts directly with the flow field. This allows the model to capture:

  • diffuser-induced acceleration
  • rotor loading effects
  • wake development

For a detailed explanation of this vortex panel method or other vortex methods in general, visit my PhD thesis (starting page 54) or the references Bontempo and Lewis.

How the Code Works

Step 1 — Geometry & Panel Generation

The geometry (airfoil or diffuser) is discretised into panels using cosine clustering, which increases resolution near leading and trailing edge. Each panel stores:

  • center point
  • length
  • slope
  • curvature

Step 2 — Coefficients Matrix and Solving First Iteration

For each panel pair (i,j), compute how panel j affects panel i. The coefficients go into the K-Matrix. Then, the panel vortex strengths are solved using:

K · γ = rhs

Where:

  • K = aerodynamic interaction matrix
  • γ = panel vortex strengths
  • rhs = freestream boundary condition

With γ solved, you can now compute the flow around the diffuser. It will not include the turbine — just an empty diffuser.

Step 3 — Including the Turbine and Wake

When activated:

  • turbine loading extracts axial momentum
  • a wake sheet is introduced downstream of the blade tip
  • wake vortices modify/induce the velocity field
  • diffuser solution is updated iteratively

Now that we are accounting for the wake vortices and turbine influence, we can compute the flow again. The wake sheet will have a different shape, so we must update our wake vortices and re-compute the induction on the velocity field.

After iterating a few times, the solution converges and you have successfully coupled diffuser, turbine and wake, enabling DAWT modelling.

Integration of the Code on the Browser

In this project, the solver runs entirely in the browser. Pyodide allows a dynamic solver loading, where the Python code is compiled to WebAssembly, loading once and caching the solver. Any new edits to the solver can be instantly implemented without rebuilding the app. For the visualization, the Agg backend was used to render Matplotlib figures as PNG, then displayed in JavaScript.

References

  1. Bontempo, F. et al. — Title to be completed.
  2. Lewis, R. I. — Title to be completed.
  3. Pyodide — Python with the scientific stack, compiled to WebAssembly. https://pyodide.org/
  4. Matplotlib Agg backend — Non-interactive backend for rendering to PNG. Matplotlib Backends Documentation

Job Tracker

Try it here

Job hunting is tedious as hell. Companies use different recruitment platforms, listings disappear quickly, and many appear to be ghost listings designed to farm jobseekers’ data. Aggregators like LinkedIn or Indeed show the same thousand positions to the same millions of users, and the rise of “quick apply” features makes every application increasingly more disposable.

I wanted to find my own job listings directly from employers’ websites, track my applications, and generate the documents to support them. I started building Job Tracker as a way to centralize that entire process into a single platform.

The platform continuously collects job listings from employer career pages, stores them in a shared database, and exposes them through a lightweight web application designed around speed and usability.

Finding the Job Listings

Instead of relying on public APIs or third-party aggregators, the platform crawls employer websites directly every weekday, gathering fresh listings from companies and institutions. This way, I am not relying on middlemen, and I can often find new listings two or three days earlier than they appear on larger aggregators. Being among the first applicants is crucial in highly competitive application processes.

Architecture Overview

The project is split into two connected components:

  • A Python-based crawling and data-processing pipeline deployed on Cloudflare infrastructure
  • A frontend application deployed almost entirely on Cloudflare’s free-tier edge infrastructure

Both systems share the same Cloudflare D1 database, allowing the crawler and frontend to stay synchronized on a daily basis.

One of the main reasons for choosing Cloudflare (CF) was the generous free-tier ecosystem. It provides hosting, edge APIs, database services, AI inference, DDoS protection, anti-bot features, making it possible to build and deploy the entire project with little overhead. The configurable rate limiting was also useful during development, both to protect the infrastructure from potential abuse and to help identify unexpected frontend or API behavior before it could scale into larger issues.

Crawling & Data Pipeline

The crawler was built using Python, Playwright and lightweight rule-based data-processing. Playwright handles browser automation across multiple platforms, while the processing layer parses, cleans, removes duplicates, and improves the collected listings before synchronizing them to the CF D1 database.

Each listing is parsed into a structured scheme containing metadata such as title, company, location, employment type, language, and seniority level. The system uses rule-based classification and keyword analysis to process hundreds of jobs extremely quickly without relying on AI.

Besides the classification itself, this allows the detection of additional required skills and technologies, later used to match listings against the user’s profile and to identify relevant experiences during the application process.

The process is not fully automated, as I still define the list of employers and manually point toward their career pages. This is not necessarily a disadvantage, since it gives me full control over the data sources and guarantees that the collected listings remain relevant.

At a later stage, this feature could potentially evolve into a personalized system where users maintain their own employer lists. At that point, however, the amount of collected listings would increase exponentially, requiring a much larger crawling and processing infrastructure.

Frontend & User Features

The frontend is built as a static React + Next.js application running on CF Pages, with server-side functionality handled through CF Pages Functions.

The focus of the UI was to keep the experience lightweight and responsive while continuously handling data flowing in from the APIs. At the same time, the platform still offers features commonly found in larger recruitment platforms, including search, filtering, job and application tracking, and AI-assisted cover letter generation.

Besides job discovery, the platform evolved into a broader job-search workflow tool. Users can organize relevant opportunities through a Kanban-style board, tracking applications from saved positions to interviews, offers, or rejections. This transformed the project from a simple crawler into a centralized application-management platform.

The AI generation system (used for the cover letters) uses CF Workers AI running Llama 3.1 8B. It is a very lightweight model compared to state-of-the-art, but correctly prompted it is capable of handling these not so difficult tasks.

User authentication is handled through Clerk, allowing users to connect using email, GitHub, Google, or Apple accounts.

The platform also includes an automated email notification powered by the Resend API, used to periodically send users curated job listings and relevant new positions matching their profile and tracked interests.

Scalability & Future Improvements

One of the most interesting aspects of the project is balancing scalability with simplicity.

The current architecture remains intentionally lightweight, relying on deterministic processing pipelines and edge deployment rather than heavy infrastructure or large-scale AI inference. This keeps operational costs low while still supporting daily crawling, enrichment, synchronization, and frontend delivery.

Future improvements could include:

  • Personalized employer lists per user
  • Distributed crawling infrastructure (crawling on client side… is that even doable?)
  • Better matching between user profiles and job requirements
  • Monetization through Premium tier to cover AI inference costs

Complete Stack

AreaTechnology
FrontendReact + Next.js
HostingCloudflare Pages + Workers
DatabaseSQLite + Cloudflare D1
AuthenticationClerk
AI InferenceCloudflare Workers AI
CrawlerPython + Playwright
EmailResend API

References

PhD Thesis — Diffuser-Augmented Wind Turbines

Overview

Wind energy is naturally associated with offshore farms or large rural landscapes with giant turbines, but as cities continue searching for sustainable energy solutions, wind energy can be integrated directly into urban environments. This challenge is more complicated than simply placing smaller wind turbines on rooftops or between buildings. Urban environments create highly turbulent and unpredictable wind conditions, which strongly affect both the aerodynamic performance of turbines and the noise they produce.

My PhD research focused on understanding the aerodynamics and aeroacoustics of diffuser-augmented wind turbines operating in urban environments. My thesis, “Aerodynamics and Aeroacoustics of Diffuser-Augmented Wind Turbines”, was developed in the context of the European project zEPHYR, which brought together researchers working on wind energy, aerodynamics, aeroacoustics, and sustainable urban integration.

As one of the PhD researchers in the project, my role focused on the aerodynamic and acoustic behavior of urban wind turbine systems, with a particular emphasis on predicting and understanding aerodynamic noise generation.

Understanding Wind Turbine Noise

Although wind turbines are often seen as clean and quiet systems, they still generate sound during operation. Understanding where this noise comes from is an important part of designing turbines, especially in urban environments.

Wind turbine noise can be divided into two categories:

  • Mechanical noise
  • Aerodynamic noise

Mechanical noise originates from internal components such as gearboxes, generators, and mechanical vibrations. The aerodynamic noise is generated directly by the interaction between airflow and the turbine blades. As the blades rotate, turbulent air structures interact with the blade surfaces and edges, creating fluctuating pressure fields that radiate as sound waves.

Several physical mechanisms contribute to aerodynamic noise generation, including:

  • Turbulent boundary-layer trailing-edge noise
  • Inflow turbulence noise
  • Flow separation
  • Tip vortex interactions

Different mechanisms dominate at different frequencies and operating conditions. For example, inflow turbulence noise is often associated with lower-frequency sound because it is generated by large turbulent structures interacting with the leading edge of the blade. Trailing-edge noise is generally regarded as the dominant source of noise in a wind turbine, and it operates at high frequency.

Aeroacoustic prediction is an important research topic, because it allows to predict noise intensity and direction, and to create designs that reduce noise.

The DAWT

Unlike conventional wind turbines, DAWTs use a diffuser or duct-like structure surrounding the rotor. This geometry is used to accelerate the airflow crossing through the turbine to improve the aerodynamic performance. It’s ideal for urban environments to overcompensate for the lower wind velocity, and the diffuser shape helps with the potential flow misalignment.

DAWT diffuser schematic

On the flip side, the diffuser significantly increases the cost of the turbines, and is not scalable for larger turbine radius. An additional downside is that the diffuser is an additional source of noise and, specifically the diffuser trailing-edge noise is a source dominant over the wind turbine noise. Thus it needs to be studied.

Building the Computational Workflow

A major part of my research involved developing numerical workflows capable of transforming aerodynamic flow information into acoustic predictions. The key idea is simple: first analyze the turbine aerodynamics, like how the flow moves around the blades and loads it causes, then use all that information to create an informed prediction of how much noise this will produce.

Overview of the Workflow

1. Aerodynamic Simulations

The first step was modeling the airflow around wind turbine using Computational Fluid Dynamics (CFD). Different numerical approaches were explored, providing varying levels of fidelity:

  • Full 3D simulations
  • 2D strip-theory
  • Low-order methods

These simulations allowed the extraction of important aerodynamic quantities such as:

  • Velocity fluctuations
  • Turbulent boundary layer properties
  • Aerodynamics loads
  • Pressure distributions and gradients
  • Flow separation regions

2. Aeroacoustic Modeling

Once the aerodynamic data is obtained, the sound generated by the turbine blades can be predicted. Much of my research focused on analytical aeroacoustic models, combining Amiet-based formulations for broadband noise with fan tonal noise models to model the turbine acoustic components.

Broadband Noise Prediction with Amiet Theory

One of the main frameworks used throughout this work was the aeroacoustic theory developed by Amiet. It was originally formulated to study helicopter rotor noise, Amiet’s theory predicts the broadband noise generated when turbulent flow interacts with a flat plate, particularly at the trailing edge.

The model describes how turbulent pressure fluctuations convected over an airfoil surface are scattered into acoustic waves. Although originally derived for simple flat plates, the methodology can be extended to realistic wind turbine blades using a strip-theory approach.

In this approximation, a three-dimensional blade is divided into a series of smaller blade sections, each treated locally as a flat plate with its own flow conditions. This makes it possible to estimate the broadband aerodynamic noise generated by rotating wind turbine blades using aerodynamic quantities extracted from CFD simulations, such as wall-pressure fluctuations, and boundary layer properties.

Tonal Noise and Scattering

In addition, rotating blades generate tonal noise components associated with periodic aerodynamic loading and blade rotation. These tonal components typically occur at harmonics of the blade-passing frequency and are often more noticeable by human listeners.

To model these effects, a fan tonal noise model was used together with FEM for the acoustic scattering. The scattering is particularly important in this case because the turbine is surrounded by a diffuser, which reflects its sound, changing its direction. As a result, the diffuser does not only affect the aerodynamics of the turbine, but also changes how sound propagates toward an observer.

Tonal noise duct schematic

Predicting the Noise Generated by the Diffuser

While aerodynamic noise generated by turbine blades has been extensively studied, the noise generated by the diffuser itself remained largely unexplored. At the time of this work, there were no low-order analytical models available for predicting broadband noise generated by cylindrical ducts or diffusers. Previous studies relied almost exclusively on high-fidelity CFD, which are computationally very expensive and difficult to use during design and optimization.

To address this problem, I adapted the Amiet model (for flat plates) to extend it for cylindrical geometries, with two different approaches. The adapted model showed very good agreement for cylindrical ducts and was then applied to diffuser geometry, demonstrating acceptable predictive capability at a significantly lower computational cost than full high-fidelity simulations.

This development became one of the main contributions of the PhD, providing a new low-order method for predicting aerodynamic noise from ducts, ducted propellers, and diffuser-augmented wind turbines.

References

  1. Gonçalves, R. (2025). Aerodynamics and aeroacoustics of diffuser-augmented wind turbines (Doctoral dissertation, University of Twente). https://doi.org/10.3990/1.9789036567800
  2. Gonçalves, R. P., Bresciani, A. P. C., & Schram, C. (2025). Extension of Amiet’s theory to circular geometry. The Journal of the Acoustical Society of America, 158(4), 3133–3151. https://doi.org/10.1121/10.0039542
  3. Gonçalves, R. P., Ahmed, F., & Schram, C. (2026). Prediction of diffuser noise footprint of a ducted wind turbine. Applied Acoustics, 242, 111079. https://doi.org/10.1016/j.apacoust.2025.111079

Videos: