Friday, March 6, 2026

A Simple Cloth Simulation in Julia — Inspired by My Son’s Blender Experiments

Four years ago, I watched my son Ridit, in class V at that time, experimenting with cloth and soft-body simulations in Blender. At that time he was deeply interested in learning how modern graphics tools simulate physical behaviour such as cloth, smoke, and rigid body dynamics.

One of his experiments is captured in this video:


Watching him explore Blender’s simulation tools sparked a thought in my mind:

Could I reproduce a simplified cloth simulation myself using code?

Years later, while exploring scientific computing with Julia, I decided to attempt exactly that.

The result is a small but interesting Verlet-integration based cloth simulation written entirely in Julia.


Why Verlet Integration?

In physics simulations used in games and graphics engines, Verlet integration is very popular because:

• It is simple
• It is numerically stable
• It does not explicitly require velocity storage

Many cloth simulators in early game engines relied on this technique.

The basic idea is:

$$
x_{new} = x_{current} + (x_{current} - x_{previous}) + a\Delta t^2
$$

Where:

  • (x_{current}) → current position

  • (x_{previous}) → previous position

  • (a) → acceleration (gravity, wind etc.)



Representing Cloth as a Grid

A cloth can be represented as a grid of particles connected by constraints.

Each particle stores:

  • Current position

  • Previous position

Neighbouring particles are connected by distance constraints that maintain the cloth structure.

o---o---o---o
|   |   |   |
o---o---o---o
|   |   |   |
o---o---o---o

Some particles are pinned so the cloth does not fall entirely.


The Julia Implementation

Below is the Julia program that simulates the cloth.

using LinearAlgebra
using Plots

nx = 25
ny = 20
spacing = 0.2
dt = 0.02
steps = 300
gravity = [0.0,-9.8]

# Create grid
pos = [ [i*spacing, j*spacing] for j in 1:ny, i in 1:nx ]
prev = deepcopy(pos)

# Pin top row
pinned = [(i,ny) for i in 1:nx]

constraints = []

for j in 1:ny
for i in 1:nx
if i < nx
push!(constraints, ((i,j),(i+1,j)))
end
if j < ny
push!(constraints, ((i,j),(i,j+1)))
end
end
end

function verlet_step(step)

wind = [2*sin(0.05*step),0.0]

for j in 1:ny
for i in 1:nx

if (i,j) in pinned
continue
end

temp = pos[j,i]

accel = gravity + wind

pos[j,i] = pos[j,i] + (pos[j,i]-prev[j,i]) + accel*dt^2

prev[j,i] = temp
end
end
end

function satisfy_constraints()

for ((i1,j1),(i2,j2)) in constraints

p1 = pos[j1,i1]
p2 = pos[j2,i2]

delta = p2 - p1
dist = norm(delta)

rest = spacing
diff = (dist-rest)/dist

if !((i1,j1) in pinned)
pos[j1,i1] += delta*0.5*diff
end

if !((i2,j2) in pinned)
pos[j2,i2] -= delta*0.5*diff
end
end
end

anim = @animate for step in 1:steps

verlet_step(step)

for k in 1:6
satisfy_constraints()
end

x = [pos[j,i][1] for j in 1:ny, i in 1:nx]
y = [pos[j,i][2] for j in 1:ny, i in 1:nx]

scatter(x,y,legend=false,xlim=(0,6),ylim=(-5,6),markersize=3)
end

gif(anim,"cloth.gif",fps=30)


And here is the video if we run this application.



What the Simulation Does

The simulation includes:

1. Gravity

gravity = [0.0,-9.8]

Every particle experiences downward acceleration.


2. Wind Force

wind = [2*sin(0.05*step),0.0]

A sinusoidal wind creates cloth fluttering.


3. Constraint Relaxation

Multiple iterations enforce distance constraints so the cloth maintains its shape.

for k in 1:6
    satisfy_constraints()
end

This technique is commonly used in Position Based Dynamics.


Visual Result

The script generates an animated GIF showing a cloth hanging from the top row while wind and gravity deform it dynamically.

Even with a few dozen lines of code, we get a convincing physical effect.


What Makes Julia Interesting for Graphics Simulation

Working with Julia gives several advantages:

• Fast numerical computation
• Simple array operations
• Easy prototyping for physics simulations
• Smooth transition from mathematics to implementation

This makes it attractive for engineers exploring scientific computing, graphics, and simulation together.


A Personal Reflection

This small experiment reminded me of the moment I watched my son exploring cloth simulation in Blender years ago.

Back then he was experimenting visually.
Today I tried to rebuild the physics underneath that visual tool.

Sometimes inspiration in engineering does not come from textbooks — it comes from watching curiosity in the next generation.

And that curiosity often pushes us to explore deeper layers of science and software.

Thursday, February 26, 2026

Why Julia Is Becoming So Popular Among SciML Engineers And How Rebuilding My Old FFT Spectrum Analyzer Opened a New Railway Safety Perspective

 Back in 2012, I wrote a small experimental piece on building a simple FFT-based spectrum analyzer:

Read here...

At that time, it was more about curiosity. FFT fascinated me. The idea that a signal in time could reveal its hidden structure in frequency felt almost magical.

Fast forward to today.

I am revisiting that same idea — but this time using Julia, and not just for visualization, but for building something that could contribute to modern railway track safety systems.

And that’s when I realized why Julia is becoming so popular among the SciML (Scientific Machine Learning) community.


The Shift: From Scripting to Scientific Computing

In 2012, building a spectrum analyzer was largely:

  • A signal processing experiment

  • A learning exercise

  • A visualization tool

But today, with Julia, the same FFT analyzer becomes:

  • A condition monitoring prototype

  • A vibration diagnostics engine

  • A predictive maintenance building block

That shift is profound.


Why SciML Engineers Love Julia

The SciML ecosystem — led by projects like SciML — is not just about machine learning. It’s about merging:

  • Differential equations

  • Physics-based modeling

  • Optimization

  • Machine learning

  • High-performance computing

Julia allows all of this in one language.


1️⃣ Performance Without Leaving the Language

FFT in Julia uses FFTW under the hood.

You write:

fft(signal)

And you get near C-level performance.

No bindings.
No external compilation workflow.
No switching between Python and C++.

For someone who enjoys going deep into engineering mathematics, that matters.


2️⃣ Multiple Dispatch Feels Like Engineering Thinking

As someone who loves system design and patterns, I noticed something interesting.

In C++ or Java, you think in terms of classes and inheritance.

In Julia, you think in terms of:

  • Mathematical structures

  • Generic functions

  • Behavior based on types

It feels closer to how engineers think about systems.

Not "object owns behavior" —
but "system responds based on physical type."

That mental alignment is powerful.


3️⃣ From FFT to Railway Safety

Let’s connect this back to my spectrum analyzer journey.

A railway track under load behaves like a vibrating beam.
When a crack develops, stiffness changes.
That produces high-frequency bursts in vibration signals.

With Julia, I can:

  • Simulate the rail as a mass-spring-damper system

  • Inject a stiffness drop

  • Perform FFT

  • Detect high-frequency anomalies

  • Add ML-based classification

All in one environment.

Modern railway systems, including those used by Indian Railways and Deutsche Bahn, rely heavily on:

  • Vibration analytics

  • Spectral energy monitoring

  • Predictive maintenance

What began as a simple FFT experiment now becomes a prototype for rail crack detection.

That evolution mirrors Julia’s evolution.


SciML Is More Than Machine Learning

SciML is about:

  • Embedding physical laws into ML

  • Solving differential equations efficiently

  • Combining simulation with learning

Using Julia, I can go from:

\[ m \ddot{x} + c \dot{x} + k x = F(t) \]

to spectral fault detection
to anomaly classification

without leaving the language.

That continuity is rare.


Why This Matters for Engineers

Many engineers hesitate to enter machine learning because:

  • Python feels high-level but slow

  • C++ feels powerful but heavy

  • MATLAB feels proprietary

Julia sits in a sweet spot:

  • Scientific syntax

  • High performance

  • Open ecosystem

  • Growing SciML community

And most importantly:

It lets you experiment at system level.


My Personal Realization

Rebuilding my old FFT-based spectrum analyzer in Julia was not nostalgia.

It was a rediscovery.

The same math.
The same Fourier transform.

But now:

  • Faster

  • Cleaner

  • Extensible

  • Connected to real-world safety applications

That is why Julia is becoming popular among SciML engineers.

Because it doesn’t just let you code.

It lets you think in equations and deploy in production.


Final Thought

What started as a simple blog post on FFT years ago has evolved into a small predictive maintenance prototype for railway safety.

Julia didn’t just make it easier.

It made it natural.

And when a language feels natural to scientists and engineers —

That’s when it starts becoming popular.

Here's the source code...

############################################################
# Rail Vibration Monitoring Prototype
# Rail Crack Simulation
############################################################

using FFTW
using DSP
using Plots
using Statistics
using LinearAlgebra

# -------------------------------
# 1️⃣ System Parameters
# -------------------------------

fs = 5000 # Sampling frequency (Hz)
T = 2 # Signal duration (seconds)
t = 0:1/fs:T-1/fs
N = length(t)

println("Sampling Frequency = $fs Hz")
println("Total Samples = $N")

# -------------------------------
# 2️⃣ Normal Rail Vibration
# -------------------------------

f_mode1 = 50
f_mode2 = 120

signal = 0.7*sin.(*f_mode1*t) .+
0.3*sin.(*f_mode2*t)

# -------------------------------
# 3️⃣ Inject Crack Fault (High-Frequency Burst)
# -------------------------------

crack_time = 1.0 # crack at 1 second
crack_index = Int(round(crack_time * fs))

burst_length = 200 # samples (~40 ms)
crack_freq = 800 # high-frequency crack signature

if crack_index + burst_length <= N
signal[crack_index : crack_index + burst_length] .+=
2*sin.(*crack_freq*t[1:burst_length+1])
end

# Add background noise
signal .+= 0.2randn(N)

println("Simulated Crack Frequency = $crack_freq Hz")

# -------------------------------
# 4️⃣ Time Domain Plot
# -------------------------------

p1 = plot(t, signal,
xlabel="Time (s)",
ylabel="Amplitude",
title="Rail Vibration Signal (Crack Simulation)",
legend=false)

# -------------------------------
# 5️⃣ FFT Processing
# -------------------------------

window = hanning(N)
signal_w = signal .* window

fft_result = fft(signal_w)
freq = fs*(0:N-1)/N
magnitude = abs.(fft_result)/N

halfN = div(N,2)

# -------------------------------
# 6️⃣ Spectrum Plot
# -------------------------------

p2 = plot(freq[1:halfN],
magnitude[1:halfN],
xlabel="Frequency (Hz)",
ylabel="Magnitude",
title="Frequency Spectrum",
legend=false,
xlim=(0,1000)) # Extended to show 800 Hz

# -------------------------------
# 7️⃣ Side-by-Side Display
# -------------------------------

p3 = plot(p1, p2, layout=(1,2), size=(1200,400))
display(p3)

# -------------------------------
# 8️⃣ Crack Detection Logic
# -------------------------------

println("\n🔍 Running Crack Detection...\n")

# Detect energy in high-frequency band
high_freq_indices = findall(freq .> 600 .&& freq .< 1000)
high_freq_energy = sum(magnitude[high_freq_indices])

println("High Frequency Energy = ", round(high_freq_energy, digits=4))

if high_freq_energy > 0.02
println("⚠️ Possible Rail Crack Detected (High-Frequency Burst)")
else
println("✅ No crack signature detected")
end

# -------------------------------
# 9️⃣ RMS Indicator
# -------------------------------

rms_value = sqrt(mean(signal.^2))
println("\nRMS Vibration Level = ", round(rms_value, digits=4))

println("\n--- Rail Crack Monitoring Simulation Complete ---")

wait()

And here's when we run the application...


📈 Time Plot

A sharp disturbance around 1 second.

📊 Frequency Plot

A strong peak near:

800 Hz

🖥 Console Output

⚠️ Possible Rail Crack Detected (High-Frequency Burst)

Monday, February 23, 2026

Design patterns gave me a thrust to move beyond programming syntaxes and julia is giving me a chance to mix and visualise engineering skills with software

 CS != Programming...

Initially, learning CS appears to be like learning many seemingly unrelated subjects together. But with maturity and experience, you will be able to understand that these subjects are all connected.

C++, Java, Python - you name any object-oriented language - they seem to be different, but only to those who don't deep dive. Once you master the fundamental object-oriented part of these languages, you will realize that they are all the same.

Design patterns help you get to the core of any object-oriented language. Once you master the Design Pattern, you will never say how to write this program, but how this program should be designed to hold the basic object-oriented principles and how it will interact with the outside world. So you will never say that we will pick up the correct implementation of a system during runtime. Rather, you will exclaim - can't we use Strategy Design Pattern here?

However, we must understand that software or computer science is not that useful unless we apply it to real-life engineering problems. There lies the satisfaction of a scientist and an able engineer. At this juncture, the true maturity of a Computer Science guy is judged. 


Many ecosystems split engineering work across tools:

  • MATLAB for modeling

  • Python for data

  • C++ for performance

  • Simulink for block diagrams

Julia collapses these layers.

You can:

  • Write high-level control logic

  • Drop to numerical linear algebra

  • Move into differential equation solvers

  • Even implement custom integrators

All in one language.

For so many years, the process of engineering computer science was that the scientists modeled an engineering solution, and then software engineers would realize it through code. But what if we want the scientists themselves model and write code to execute that model - all by themselves? For that to happen, we needed to develop a language with a deep binding with the engineering Maths and Physics.

Enter the world of Julia - and you got it - model any scientific problem and then produce the code all alone - the beauty of julia.

As my journey to know WhoAmI continues, my respect for the julia programming language is increasing day by day. So when I can model a PID control or a dipole antenna in Julia, the joy is natural.

I never thought I would be able to delve into hardcore engineering subjects after so many years of engineering graduation.

But this is the reality.

My exploration continues.

Below is the output of a PID control developed using julia.





And here's the far-field radiation pattern of a dipole antenna...



The greatest job satisfaction is always to be at the juncture of software and engineering.

And I am loving it.

Saturday, February 21, 2026

The Engineer in Me is Jubilant — Julia, A Language for System-Level Experimentation for engineers...



There are moments in an engineer’s life when a tool just clicks.

For me, that moment came while implementing a simple PID-controlled DC motor model in Julia.

Not because PID control is revolutionary.
Not because DC motors are exotic.

But because the process felt frictionless.

And that matters.


From Equation to Experiment — Without Friction

In classical control engineering, we begin with mathematics:


G(s) = K / (Js + b)(Ls + R) + K^2

This is not just a formula.
It represents inertia, friction, electrical dynamics — physics captured in Laplace space.

In many languages, translating this into working simulation code involves:

  • Verbose syntax

  • Data structure boilerplate

  • External tools for plotting

  • Type mismatches

  • Build steps

But in Julia, using ControlSystems.jl, the translation from equation to executable model feels almost poetic:

using ControlSystems

s = tf("s")
motor = K / ((J*s + b)*(L*s + R) + K^2)

pid = Kp + Ki/s + Kd*s
closed_loop = feedback(pid * motor, 1)

Look at that.

The code mirrors the mathematics.
No impedance mismatch between theory and implementation.

For an engineer, that is deeply satisfying.


System-Level Thinking — Not Just Coding

Engineering is not about syntax.

It is about:

  • Modeling

  • Interconnection

  • Feedback

  • Stability

  • Response

  • Iteration

Julia allows you to move from:

  • Transfer function

  • → Closed-loop interconnection

  • → Step response

  • → Parameter tuning

in minutes.

With Plots.jl, visualizing behavior is immediate:

y, t = step(closed_loop, 0:0.01:2)
plot(t, vec(y))

Change Kp.
Re-run.
Observe overshoot change.

Change Ki.
Re-run.
Observe steady-state error vanish.

This is experimentation at the speed of thought.


Why This Feels Different

Many ecosystems split engineering work across tools:

  • MATLAB for modeling

  • Python for data

  • C++ for performance

  • Simulink for block diagrams

Julia collapses these layers.

You can:

  • Write high-level control logic

  • Drop to numerical linear algebra

  • Move into differential equation solvers

  • Even implement custom integrators

All in one language.

For someone who enjoys digging into source code, understanding numerical methods, and experimenting at system scale — this coherence is powerful.


Engineers Think in Systems

When I modeled the PID loop, what struck me was not that it worked.

It was how naturally system interconnections are expressed:

feedback(pid * motor, 1)

That single line captures decades of control theory.

This is not scripting.

This is system architecture expressed symbolically.


Performance Without Compromise

Unlike prototyping languages that eventually require rewriting in C/C++, Julia compiles to efficient machine code.

That means:

  • Rapid experimentation

  • No performance guilt

  • No "rewrite later" tax

For control engineers dealing with:

  • High-order systems

  • State-space models

  • Optimization loops

  • Model predictive control

This matters enormously.


The Quiet Joy

There is a quiet joy when:

  • Mathematics maps directly to code

  • Systems behave as predicted

  • Tuning becomes interactive

  • The tool does not get in the way

That is what I felt implementing the PID example.

Not hype.
Not trendiness.

Just alignment between engineering thought and computational expression.


Julia as an Engineering Workbench

Julia is not just a language.

It feels like:

  • A modeling lab

  • A numerical toolbox

  • A systems sandbox

  • A research instrument

For engineers who think in equations, dynamics, and feedback loops — it feels native.


Final Thought

The engineer in me is jubilant.

Because experimentation should be easy.
Modeling should feel direct.
And computation should not stand between idea and insight.

With Julia, system-level experimentation feels natural again.

And that, for an engineer, is everything.

Here's the source code of the PID Control...

Enjoy...

using ControlSystems
using Plots

# ----------------------------
# Motor Parameters
# ----------------------------
J = 0.01 # inertia
b = 0.1 # friction
K = 0.01 # motor constant
R = 1.0 # resistance
L = 0.5 # inductance

# ----------------------------
# Transfer Function of Motor
# G(s) = K / [(Js + b)(Ls + R) + K^2]
# ----------------------------
s = tf("s")

motor = K / ((J*s + b)*(L*s + R) + K^2)

println("Motor Transfer Function:")
display(motor)

# ----------------------------
# PID Controller
# C(s) = Kp + Ki/s + Kd*s
# ----------------------------
Kp = 100
Ki = 200
Kd = 10

pid = Kp + Ki/s + Kd*s

# ----------------------------
# Closed-loop System
# ----------------------------
closed_loop = feedback(pid * motor, 1)

println("Closed Loop Transfer Function:")
display(closed_loop)

# ----------------------------
# Step Response
# ----------------------------
t = 0:0.01:2
y, t = step(closed_loop, t)

p = plot(t, vec(y),
xlabel="Time (s)",
ylabel="Speed",
title="Closed-Loop Step Response",
legend=false)

display(p)
wait()

And here's my PID study - an implementation using Java done many years ago.

One thing you will understand - Julia is a boon for engineers.

Friday, February 20, 2026

Paradigm shift - from behaviours inside object in OOAD to Julia where behaviours emerge from type of function parameters...


OOAD Thought Processing

    Concept → Owner

  • Behavior → Object
  • Polymorphism → Virtual methods
  • Extension → Subclassing
  • Encapsulation → Methods inside class


Julia Thought Processing

    Concept → Owner

  • Behavior → Generic function
  • Polymorphism → Multiple dispatch
  • Extension → Add new methods
  • Encapsulation → Types + modules


OO Design Thinking

  • Identify entities (classes)
  • Attach behavior to them
  • Use inheritance for variation


Julia Design Thinking

  • Identify operations (functions)
  • Define data types
  • Implement methods for combinations of types


Worldview Comparison

OOP worldview

The world is made of interacting objects.

Julia worldview

The world is made of operations applied to data.


The State Pattern in Pure Julia Style

Enjoy the State pattern written in Julia.

Note that this works without the context class of the original State Pattern, which is typically implemented using object-oriented languages like C++, Java, or Python.

abstract type ChickenState end

struct Uncleaned <: ChickenState end
struct Washed <: ChickenState end
struct Marinated <: ChickenState end
struct Cooked <: ChickenState end

function wash(::Uncleaned)
println("Chicken is getting cleaned → Washed")
sleep(2)
return Washed()
end

wash(s::ChickenState) = s # default: no change

function marinate(::Washed)
println("Chicken is being marinated → Marinated")
sleep(2)
return Marinated()
end

marinate(s::ChickenState) = s

function cook(::Marinated)
println("Chicken is being cooked → Cooked")
sleep(4)
return Cooked()
end

cook(s::ChickenState) = s

function serve(::Cooked)
println("Chicken is being served. Final state.")
return Cooked()
end

serve(s::ChickenState) = s

state = Uncleaned()

state = wash(state)
state = marinate(state)
state = cook(state)
state = serve(state)


Here's the Python implementation of the State Design Pattern.

Feel the difference - Pythonian way and the Julian way.

Tuesday, February 17, 2026

Horns of the dilemma - C++ & Python binding or Julia - implementation of strategy design pattern in Julia...

 


Aah… I am at the crossroads - tried-and-true marriage (C++/Python) or solo act (Julia).

For the past few months, I delved into many tools that act as a glue between C++ and Python, like nanobind, pybind11, SWIG, Boost.Python, etc. All of these looked good. This is the industry-wise power couple for performance and ease of use.

Yesterday, while trying to understand why so many top-level AI scientists are leaving bigtech, I got a clue about scientific AI and Julia, the programming language especially made for this field.

Yes, I am not talking about LLM - because I am sure AI ≠ the next word suggestion. There is a vast field in AI to cover vis-à-vis Scientific AI and simulation. In fields like climate modeling, drug discovery, or fluid dynamics, we aren't just predicting tokens; we are constrained by the laws of physics.

This is where Julia has carved out a unique, dominant niche through a movement called SciML.

While Python and C++ can do this, Julia has structural advantages that make it the "lab equipment" of choice for this decade.

To train an AI, you need gradients (derivatives). In Python, you can only differentiate through code written in specific frameworks like PyTorch or JAX. In Julia, the entire language is essentially differentiable. You can take the derivative of a complex simulation, a CAD model, or a custom physics engine without rewriting it in a "tensor" format.

Remember, scientific models are often written by scientists, not software engineers.

  • The Old Way: A scientist writes a model in Python; it’s too slow for the Supercomputer, so a software engineer rewrites it in C++.

  • The Julia Way: The scientist writes high-level code that is automatically compiled to LLVM (machine code). The prototype is the production code.

Some important use cases for Julia…

  • Climate Modeling: The CliMA project (MIT/Caltech) is rebuilding global climate models in Julia to better integrate satellite data with fluid dynamics.

  • Pharmaceuticals: Pumas is a Julia-based tool used for "quantitative pharmacology" to predict how drugs move through the body.

  • Aerospace: Organizations like NASA use Julia for trajectory optimization because it handles the massive matrix math of orbital mechanics at C++ speeds

Julia isn't a "Python killer" for building a website or a simple chatbot. But for Scientific AI—where you need to solve a partial differential equation while training a transformer—it is currently the only language that doesn't make you choose between your sanity (Python) and your performance (C++).

So… here we go… my exploration of Julia has begun today. The way I learn new software languages is by doing the same thing for Julia - using Julia to implement some of the GoF Design Patterns, here the Strategy Pattern.

Here is the source code of the Strategy Pattern developed using Julia.

abstract type JourneyToTheAirport end

struct Bus <: JourneyToTheAirport end
struct Metro <: JourneyToTheAirport end
struct Auto <: JourneyToTheAirport end

gotoairport(::Bus)   = println("🚌 Journey by bus... hope there's no traffic!")
gotoairport(::Metro) = println("🚇 Journey by metro... fast and efficient.")
gotoairport(::Auto)  = println("🛺 Journey by auto... hold on tight!")

# 1. Create a mapping of strings to Type Constructors
choices = Dict(
    "bus"   => Bus(),
    "metro" => Metro(),
    "auto"  => Auto()
)

function run_app()
    println("How do you want to get to the airport? (bus, metro, auto):")

    # 2. Get user input and clean it up (lowercase and strip whitespace)
    user_input = lowercase(strip(readline()))

    # 3. Look up the strategy in our dictionary
    if haskey(choices, user_input)
        strategy = choices[user_input]
        gotoairport(strategy)
    else
        println("❌ Sorry, '$user_input' is not a valid transport option.")
    end
end

run_app()

Enjoy…

Saturday, February 7, 2026

Many private engineering colleges in India who made a lot of money by just printing out CS degrees for gullible students have closed their shops...

It’s a classic case of the "education bubble" finally popping. For nearly two decades, opening a private engineering college in India was seen as a guaranteed gold mine—often dubbed the "CS Degree Mill."

​The trend we are noticing is backed by some pretty stark data. Since the mid-2010s, the All India Council for Technical Education (AICTE) has overseen a massive "market correction."

​Why the "Shops" are Closing

​The decline wasn't just due to a lack of students, but a systemic failure in the business model of these institutions:

  • The 30% Rule: The AICTE enacted a strict policy where colleges with less than 30% enrollment for five consecutive years face forced closure. This effectively weeded out the "ghost colleges" that existed only on paper.
  • The Employability Gap: Industry reports (like those from Aspiring Minds) consistently pointed out that nearly 80% of Indian engineering graduates were unemployable in core technical roles. When companies stopped showing up for "Day 0" placements at Tier-3 colleges, the "gullible students" (and their parents) stopped signing up.
  • Pivot to "Premium": High-quality private players and "Deemed Universities" (like BITS, VIT, or newer ones like Shiv Nadar and Bennett) consolidated the market. Smaller colleges that couldn't compete with their labs or placement cells simply couldn't survive.
  • Phased Mergers: Many colleges aren't just "shutting down" but are being absorbed into larger private universities or converting their campuses into international schools or management institutes.

​While the "degree mills" are closing, it has left a generation of graduates with "paper degrees" that hold little market value. The industry has moved toward skills-based hiring, where a GitHub portfolio often carries more weight than a certificate from a defunct college.