If the matrix blocks are not too large, implementing this using Arrays / Matrix types of Julia would be easiest. A different representation would be to use BlockArrays:
using LinearAlgebra, FillArrays, BlockArrays
AG, AD = rand(6,10), rand(3,10)
TL = mortar((I(3), Fill(0.0,3,6), -AG),(Fill(0.0,6,3),-I(6),-AD))
M = mortar((TL,Fill(0.0,9,19)),(Fill(0.0,9,19),TL))
IGR, IDR, ILR, IG2, ID2, IL2 =
rand(3), rand(6), rand(10), rand(3), rand(6), rand(10)
V = mortar([mortar([IGR, IDR, ILR]), mortar([IG2, ID2, IL2])])
with these defined, the matrix product in the diagram can be calculated as:
julia> M*V
2-blocked 18-element BlockVector{Float64}:
-2.7166482252406086
-0.7411532464031856
-1.4144505807049303
-3.9973523077216147
-4.2554463973398535
-3.9794920828563947
-3.6925883969453324
-3.286901004924977
-1.6640267390765626
───────────────────
-2.899615642942856
-1.873631050122329
-1.477001012721034
-3.3983276831541374
-3.1006965784125096
-4.0077663400711785
-3.2353523978568464
-3.3306260239290744
-1.9377803558173756
It would be necessary to learn the other featuers of BlockedArrays (such as block indexing etc.) to really get the benefits.