git: e3db418d4794 - main - cad/gmsh: chase CGNS 4.5.0

From: Thierry Thomas <thierry_at_FreeBSD.org>
Date: Tue, 06 May 2025 16:07:54 UTC
The branch main has been updated by thierry:

URL: https://cgit.FreeBSD.org/ports/commit/?id=e3db418d47948a7106eab82bd09dacce06606d89

commit e3db418d47948a7106eab82bd09dacce06606d89
Author:     Thierry Thomas <thierry@FreeBSD.org>
AuthorDate: 2025-01-29 19:57:11 +0000
Commit:     Thierry Thomas <thierry@FreeBSD.org>
CommitDate: 2025-05-06 16:07:47 +0000

    cad/gmsh: chase CGNS 4.5.0
    
    Patch 20c318a4 from upstream.
    
    Obtained from:  https://gitlab.onelab.info/gmsh/gmsh/-/commit/20c318a4b945a3c7086a3a95b7bb4b56f2a5029e
---
 cad/gmsh/Makefile                                  |   2 +-
 ...erMeshOptimizer_HighOrderMeshElasticAnalogy.cpp |  41 +++
 .../patch-contrib_MeshOptimizer_VertexCoord.cpp    |  42 ++++
 .../patch-contrib_domhex_BackgroundMesh2D.cpp      | 110 +++++++++
 .../files/patch-contrib_domhex_BackgroundMesh2D.h  |  23 ++
 .../files/patch-contrib_domhex_surfaceFiller.cpp   |  48 ++++
 cad/gmsh/files/patch-src_common_gmsh.cpp           |  32 +++
 cad/gmsh/files/patch-src_geo_GFace.cpp             | 121 +++++++++
 cad/gmsh/files/patch-src_geo_GFace.h               |  26 ++
 cad/gmsh/files/patch-src_geo_GeomMeshMatcher.cpp   | 274 +++++++++++++++++++++
 cad/gmsh/files/patch-src_geo_GeomMeshMatcher.h     |  32 +++
 cad/gmsh/files/patch-src_geo_OCCFace.cpp           |  19 ++
 cad/gmsh/files/patch-src_geo_OCCFace.h             |  11 +
 cad/gmsh/files/patch-src_geo_Pair.h                |  29 +++
 cad/gmsh/files/patch-src_geo_discreteFace.cpp      |  33 +++
 cad/gmsh/files/patch-src_geo_discreteFace.h        |  11 +
 cad/gmsh/files/patch-src_geo_gmshFace.cpp          |  27 ++
 cad/gmsh/files/patch-src_geo_gmshFace.h            |  11 +
 cad/gmsh/files/patch-src_geo_gmshSurface.cpp       |  15 ++
 cad/gmsh/files/patch-src_geo_gmshSurface.h         |  19 ++
 cad/gmsh/files/patch-src_geo_xyFace.h              |  16 ++
 cad/gmsh/files/patch-src_mesh_BackgroundMesh.cpp   |  26 ++
 cad/gmsh/files/patch-src_mesh_meshGFace.cpp        |  22 ++
 cad/gmsh/files/patch-src_mesh_meshGFaceBamg.cpp    |  24 ++
 .../patch-src_mesh_meshGFaceDelaunayInsertion.cpp  |  18 ++
 25 files changed, 1031 insertions(+), 1 deletion(-)

diff --git a/cad/gmsh/Makefile b/cad/gmsh/Makefile
index 05b472488041..7f1a92dd87f0 100644
--- a/cad/gmsh/Makefile
+++ b/cad/gmsh/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=	gmsh
 DISTVERSION=	4.13.1
-PORTREVISION=	4
+PORTREVISION=	5
 CATEGORIES=	cad
 MASTER_SITES=	http://gmsh.info/src/
 DISTNAME=	${PORTNAME}-${PORTVERSION}-source
diff --git a/cad/gmsh/files/patch-contrib_HighOrderMeshOptimizer_HighOrderMeshElasticAnalogy.cpp b/cad/gmsh/files/patch-contrib_HighOrderMeshOptimizer_HighOrderMeshElasticAnalogy.cpp
new file mode 100644
index 000000000000..2ecac4e87b02
--- /dev/null
+++ b/cad/gmsh/files/patch-contrib_HighOrderMeshOptimizer_HighOrderMeshElasticAnalogy.cpp
@@ -0,0 +1,41 @@
+--- contrib/HighOrderMeshOptimizer/HighOrderMeshElasticAnalogy.cpp.orig	2024-03-29 22:06:53 UTC
++++ contrib/HighOrderMeshOptimizer/HighOrderMeshElasticAnalogy.cpp
+@@ -242,25 +242,25 @@ void highOrderTools::_computeMetricInfo(GFace *gf, MEl
+   for(int j = 0; j < nbNodes; j++) {
+     SPoint2 param;
+     reparamMeshVertexOnFace(e->getVertex(j), gf, param);
+-    Pair<SVector3, SVector3> der = gf->firstDer(param);
++    std::pair<SVector3, SVector3> der = gf->firstDer(param);
+     int XJ = j;
+     int YJ = j + nbNodes;
+     int ZJ = j + 2 * nbNodes;
+     int UJ = j;
+     int VJ = j + nbNodes;
+-    J(XJ, UJ) = der.first().x();
+-    J(YJ, UJ) = der.first().y();
+-    J(ZJ, UJ) = der.first().z();
+-    J(XJ, VJ) = der.second().x();
+-    J(YJ, VJ) = der.second().y();
+-    J(ZJ, VJ) = der.second().z();
++    J(XJ, UJ) = der.first.x();
++    J(YJ, UJ) = der.first.y();
++    J(ZJ, UJ) = der.first.z();
++    J(XJ, VJ) = der.second.x();
++    J(YJ, VJ) = der.second.y();
++    J(ZJ, VJ) = der.second.z();
+ 
+-    JT(UJ, XJ) = der.first().x();
+-    JT(UJ, YJ) = der.first().y();
+-    JT(UJ, ZJ) = der.first().z();
+-    JT(VJ, XJ) = der.second().x();
+-    JT(VJ, YJ) = der.second().y();
+-    JT(VJ, ZJ) = der.second().z();
++    JT(UJ, XJ) = der.first.x();
++    JT(UJ, YJ) = der.first.y();
++    JT(UJ, ZJ) = der.first.z();
++    JT(VJ, XJ) = der.second.x();
++    JT(VJ, YJ) = der.second.y();
++    JT(VJ, ZJ) = der.second.z();
+ 
+     SVector3 ss = getSSL(e->getVertex(j));
+     GPoint gp = gf->point(param);
diff --git a/cad/gmsh/files/patch-contrib_MeshOptimizer_VertexCoord.cpp b/cad/gmsh/files/patch-contrib_MeshOptimizer_VertexCoord.cpp
new file mode 100644
index 000000000000..4cb21e79ce54
--- /dev/null
+++ b/cad/gmsh/files/patch-contrib_MeshOptimizer_VertexCoord.cpp
@@ -0,0 +1,42 @@
+--- contrib/MeshOptimizer/VertexCoord.cpp.orig	2024-03-29 22:06:54 UTC
++++ contrib/MeshOptimizer/VertexCoord.cpp
+@@ -76,12 +76,12 @@ void VertexCoordParent::gXyz2gUvw(const SPoint3 &uvw, 
+     gUvw[0] = gXyz.x() * der.x() + gXyz.y() * der.y() + gXyz.z() * der.z();
+   }
+   else {
+-    Pair<SVector3, SVector3> der =
++    std::pair<SVector3, SVector3> der =
+       static_cast<GFace *>(ge)->firstDer(SPoint2(uvw[0], uvw[1]));
+-    gUvw[0] = gXyz.x() * der.first().x() + gXyz.y() * der.first().y() +
+-              gXyz.z() * der.first().z();
+-    gUvw[1] = gXyz.x() * der.second().x() + gXyz.y() * der.second().y() +
+-              gXyz.z() * der.second().z();
++    gUvw[0] = gXyz.x() * der.first.x() + gXyz.y() * der.first.y() +
++              gXyz.z() * der.first.z();
++    gUvw[1] = gXyz.x() * der.second.x() + gXyz.y() * der.second.y() +
++              gXyz.z() * der.second.z();
+   }
+ }
+ 
+@@ -101,15 +101,15 @@ void VertexCoordParent::gXyz2gUvw(const SPoint3 &uvw,
+     }
+   }
+   else {
+-    Pair<SVector3, SVector3> der =
++    std::pair<SVector3, SVector3> der =
+       static_cast<GFace *>(ge)->firstDer(SPoint2(uvw[0], uvw[1]));
+     auto itUvw = gUvw.begin();
+     for(auto itXyz = gXyz.begin(); itXyz != gXyz.end(); itXyz++) {
+-      (*itUvw)[0] = itXyz->x() * der.first().x() +
+-                    itXyz->y() * der.first().y() + itXyz->z() * der.first().z();
+-      (*itUvw)[1] = itXyz->x() * der.second().x() +
+-                    itXyz->y() * der.second().y() +
+-                    itXyz->z() * der.second().z();
++      (*itUvw)[0] = itXyz->x() * der.first.x() +
++                    itXyz->y() * der.first.y() + itXyz->z() * der.first.z();
++      (*itUvw)[1] = itXyz->x() * der.second.x() +
++                    itXyz->y() * der.second.y() +
++                    itXyz->z() * der.second.z();
+       itUvw++;
+     }
+   }
diff --git a/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.cpp b/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.cpp
new file mode 100644
index 000000000000..2863634a8f85
--- /dev/null
+++ b/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.cpp
@@ -0,0 +1,110 @@
+--- contrib/domhex/BackgroundMesh2D.cpp.orig	2024-03-29 22:06:54 UTC
++++ contrib/domhex/BackgroundMesh2D.cpp
+@@ -490,9 +490,9 @@ void frameFieldBackgroundMesh2D::computeCrossField(
+         v[1] = (*it)->lines[i]->getVertex(1);
+         SPoint2 p1, p2;
+         reparamMeshEdgeOnFace(v[0], v[1], face, p1, p2);
+-        Pair<SVector3, SVector3> der = face->firstDer((p1 + p2) * .5);
+-        SVector3 t1 = der.first();
+-        SVector3 t2 = der.second();
++        std::pair<SVector3, SVector3> der = face->firstDer((p1 + p2) * .5);
++        SVector3 t1 = der.first;
++        SVector3 t2 = der.second;
+         SVector3 n = crossprod(t1, t2);
+         n.normalize();
+         SVector3 d1(v[1]->x() - v[0]->x(), v[1]->y() - v[0]->y(),
+@@ -534,21 +534,21 @@ void frameFieldBackgroundMesh2D::eval_crossfield(doubl
+                                                  STensor3 &cf)
+ {
+   double quadAngle = angle(u, v);
+-  Pair<SVector3, SVector3> dirs =
++  std::pair<SVector3, SVector3> dirs =
+     compute_crossfield_directions(u, v, quadAngle);
+-  SVector3 n = crossprod(dirs.first(), dirs.second());
++  SVector3 n = crossprod(dirs.first, dirs.second);
+ 
+   for(int i = 0; i < 3; i++) {
+-    cf(i, 0) = dirs.first()[i];
+-    cf(i, 1) = dirs.second()[i];
++    cf(i, 0) = dirs.first[i];
++    cf(i, 1) = dirs.second[i];
+     cf(i, 2) = n[i];
+   }
+ 
+   //  SVector3 t1,t2,n;
+   //  GFace *face = dynamic_cast<GFace*>(gf);
+-  //  Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v));
+-  //  SVector3 s1 = der.first();
+-  //  SVector3 s2 = der.second();
++  //  std::pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v));
++  //  SVector3 s1 = der.first;
++  //  SVector3 s2 = der.second;
+   //  n = crossprod(s1,s2);
+   //  n.normalize();
+   //  s1.normalize();
+@@ -642,12 +642,12 @@ void frameFieldBackgroundMesh2D::exportCrossField(cons
+     double angle_current = angle(v);
+     GPoint p = get_GPoint_from_MVertex(v);
+     for(int i = 0; i < 2; i++) {
+-      Pair<SVector3, SVector3> dirs = compute_crossfield_directions(
++      std::pair<SVector3, SVector3> dirs = compute_crossfield_directions(
+         v->x(), v->y(), angle_current + deltas[i]);
+       fprintf(f, "VP(%g,%g,%g) {%g,%g,%g};\n", p.x(), p.y(), p.z(),
+-              dirs.first()[0], dirs.first()[1], dirs.first()[2]);
++              dirs.first[0], dirs.first[1], dirs.first[2]);
+       fprintf(f, "VP(%g,%g,%g) {%g,%g,%g};\n", p.x(), p.y(), p.z(),
+-              dirs.second()[0], dirs.second()[1], dirs.second()[2]);
++              dirs.second[0], dirs.second[1], dirs.second[2]);
+     }
+   }
+   fprintf(f, "};\n");
+@@ -656,7 +656,7 @@ void frameFieldBackgroundMesh2D::exportCrossField(cons
+ 
+ // returns the cross field as a pair of othogonal vectors (NOT in parametric
+ // coordinates, but real 3D coordinates)
+-Pair<SVector3, SVector3>
++std::pair<SVector3, SVector3>
+ frameFieldBackgroundMesh2D::compute_crossfield_directions(double u, double v,
+                                                           double angle_current)
+ {
+@@ -664,12 +664,12 @@ frameFieldBackgroundMesh2D::compute_crossfield_directi
+   GFace *face = dynamic_cast<GFace *>(gf);
+   if(!face) {
+     Msg::Error("Entity is not a face in background mesh");
+-    return Pair<SVector3, SVector3>(SVector3(), SVector3());
++    return std::pair<SVector3, SVector3>(SVector3(), SVector3());
+   }
+ 
+-  Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u, v));
+-  SVector3 s1 = der.first();
+-  SVector3 s2 = der.second();
++  std::pair<SVector3, SVector3> der = face->firstDer(SPoint2(u, v));
++  SVector3 s1 = der.first;
++  SVector3 s2 = der.second;
+   SVector3 n = crossprod(s1, s2);
+   n.normalize();
+ 
+@@ -687,8 +687,8 @@ frameFieldBackgroundMesh2D::compute_crossfield_directi
+   SVector3 t2 = crossprod(n, t1);
+   t2.normalize();
+ 
+-  return Pair<SVector3, SVector3>(SVector3(t1[0], t1[1], t1[2]),
+-                                  SVector3(t2[0], t2[1], t2[2]));
++  return std::pair<SVector3, SVector3>(SVector3(t1[0], t1[1], t1[2]),
++                                       SVector3(t2[0], t2[1], t2[2]));
+ }
+ 
+ bool frameFieldBackgroundMesh2D::compute_RK_infos(double u, double v, double x,
+@@ -711,9 +711,9 @@ bool frameFieldBackgroundMesh2D::compute_RK_infos(doub
+     return false;
+   }
+ 
+-  Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u, v));
+-  SVector3 s1 = der.first();
+-  SVector3 s2 = der.second();
++  std::pair<SVector3, SVector3> der = face->firstDer(SPoint2(u, v));
++  SVector3 s1 = der.first;
++  SVector3 s2 = der.second;
+   SVector3 n = crossprod(s1, s2);
+   n.normalize();
+   SVector3 basis_u = s1;
diff --git a/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.h b/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.h
new file mode 100644
index 000000000000..9e6ad3a20153
--- /dev/null
+++ b/cad/gmsh/files/patch-contrib_domhex_BackgroundMesh2D.h
@@ -0,0 +1,23 @@
+--- contrib/domhex/BackgroundMesh2D.h.orig	2024-03-29 22:06:54 UTC
++++ contrib/domhex/BackgroundMesh2D.h
+@@ -9,9 +9,7 @@
+ #include <string>
+ #include <map>
+ #include <vector>
+-#include "Pair.h"
+ #include "STensor3.h"
+-
+ #include "BGMBase.h"
+ 
+ class MTriangle;
+@@ -133,8 +131,8 @@ class frameFieldBackgroundMesh2D : public backgroundMe
+   void eval_crossfield(MVertex *vert, STensor3 &cf);
+ 
+   void exportCrossField(const std::string &filename);
+-  Pair<SVector3, SVector3> compute_crossfield_directions(double u, double v,
+-                                                         double angle_current);
++  std::pair<SVector3, SVector3> compute_crossfield_directions(double u, double v,
++                                                              double angle_current);
+   bool compute_RK_infos(double u, double v, double x, double y, double z,
+                         RK_form &infos);
+ 
diff --git a/cad/gmsh/files/patch-contrib_domhex_surfaceFiller.cpp b/cad/gmsh/files/patch-contrib_domhex_surfaceFiller.cpp
new file mode 100644
index 000000000000..2985db17481f
--- /dev/null
+++ b/cad/gmsh/files/patch-contrib_domhex_surfaceFiller.cpp
@@ -0,0 +1,48 @@
+--- contrib/domhex/surfaceFiller.cpp.orig	2024-03-29 22:06:54 UTC
++++ contrib/domhex/surfaceFiller.cpp
+@@ -85,10 +85,10 @@ bool compute4neighbors(
+   metricField = SMetric3(1. / (L * L));
+ 
+   // get the unit normal at that point
+-  Pair<SVector3, SVector3> der =
++  std::pair<SVector3, SVector3> der =
+     gf->firstDer(SPoint2(midpoint[0], midpoint[1]));
+-  SVector3 s1 = der.first();
+-  SVector3 s2 = der.second();
++  SVector3 s1 = der.first;
++  SVector3 s2 = der.second;
+   SVector3 n = crossprod(s1, s2);
+   n.normalize();
+   t1 -= n*dot(t1,n);
+@@ -259,10 +259,10 @@ bool compute4neighbors(
+ //     //                 0
+ 
+ //     // get the unit normal at that point
+-//     Pair<SVector3, SVector3> der =
++//     std::pair<SVector3, SVector3> der =
+ //       gf->firstDer(SPoint2(midpoint[0], midpoint[1]));
+-//     SVector3 s1 = der.first();
+-//     SVector3 s2 = der.second();
++//     SVector3 s1 = der.first;
++//     SVector3 s2 = der.second;
+ //     SVector3 n = crossprod(s1, s2);
+ //     n.normalize();
+ 
+@@ -490,7 +490,7 @@ void packingOfParallelograms(GFace *gf, std::vector<MV
+     double du[4] = {0,0,0,0}, dv[4]= {0,0,0,0};
+ 
+     //    printf("cop %d\n",(*it)->getNum());
+-    
++
+     for (int i=0;i<2;i++){
+       if (gf->periodic(i)){
+ 	reparamMeshVertexOnFace(*it, gf, midpoint);
+@@ -513,7 +513,7 @@ void packingOfParallelograms(GFace *gf, std::vector<MV
+     }
+ 
+     if (NP == 0)NP=1;
+-    
++
+     for (int i=0;i<NP;i++){
+       bool singular = !compute4neighbors(gf, *it, midpoint, newp, metricField, cross_field, du[i],dv[i],globalMult );
+       //      printf("there %d %g %g\n",singular,du[i],dv[i]);
diff --git a/cad/gmsh/files/patch-src_common_gmsh.cpp b/cad/gmsh/files/patch-src_common_gmsh.cpp
new file mode 100644
index 000000000000..df550b32000f
--- /dev/null
+++ b/cad/gmsh/files/patch-src_common_gmsh.cpp
@@ -0,0 +1,32 @@
+--- src/common/gmsh.cpp.orig	2024-05-05 07:36:23 UTC
++++ src/common/gmsh.cpp
+@@ -443,7 +443,7 @@ GMSH_API void gmsh::model::getEntitiesForPhysicalName(
+   GModel::current()->getEntitiesForPhysicalName(name, entities);
+   if(entities.size() != 0) {
+     for(auto ge : entities) {
+-      dimTags.push_back(std::pair<int, int >(ge->dim(), ge->tag()));
++      dimTags.push_back(std::make_pair(ge->dim(), ge->tag()));
+     }
+   }
+   else {
+@@ -847,13 +847,13 @@ gmsh::model::getDerivative(const int dim, const int ta
+     GFace *gf = static_cast<GFace *>(entity);
+     for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
+       SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
+-      Pair<SVector3, SVector3> d = gf->firstDer(param);
+-      deriv.push_back(d.left().x());
+-      deriv.push_back(d.left().y());
+-      deriv.push_back(d.left().z());
+-      deriv.push_back(d.right().x());
+-      deriv.push_back(d.right().y());
+-      deriv.push_back(d.right().z());
++      std::pair<SVector3, SVector3> d = gf->firstDer(param);
++      deriv.push_back(d.first.x());
++      deriv.push_back(d.first.y());
++      deriv.push_back(d.first.z());
++      deriv.push_back(d.second.x());
++      deriv.push_back(d.second.y());
++      deriv.push_back(d.second.z());
+     }
+   }
+ }
diff --git a/cad/gmsh/files/patch-src_geo_GFace.cpp b/cad/gmsh/files/patch-src_geo_GFace.cpp
new file mode 100644
index 000000000000..241d63352f0e
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_GFace.cpp
@@ -0,0 +1,121 @@
+--- src/geo/GFace.cpp.orig	2024-03-29 22:07:00 UTC
++++ src/geo/GFace.cpp
+@@ -880,10 +880,10 @@ double GFace::curvatureDiv(const SPoint2 &param) const
+ 
+   const double eps = 1.e-5;
+ 
+-  Pair<SVector3, SVector3> der = firstDer(param);
++  std::pair<SVector3, SVector3> der = firstDer(param);
+ 
+-  SVector3 du = der.first();
+-  SVector3 dv = der.second();
++  SVector3 du = der.first;
++  SVector3 dv = der.second;
+   SVector3 nml = crossprod(du, dv);
+ 
+   double detJ = norm(nml);
+@@ -937,19 +937,19 @@ double GFace::curvatures(const SPoint2 &param, SVector
+                          SVector3 &dirMin, double &curvMax,
+                          double &curvMin) const
+ {
+-  Pair<SVector3, SVector3> D1 = firstDer(param);
++  std::pair<SVector3, SVector3> D1 = firstDer(param);
+ 
+   if(geomType() == Plane || geomType() == BoundaryLayerSurface) {
+-    dirMax = D1.first();
+-    dirMin = D1.second();
++    dirMax = D1.first;
++    dirMin = D1.second;
+     curvMax = 0.;
+     curvMin = 0.;
+     return 0.;
+   }
+ 
+   if(geomType() == Sphere) {
+-    dirMax = D1.first();
+-    dirMin = D1.second();
++    dirMax = D1.first;
++    dirMin = D1.second;
+     curvMax = curvatureDiv(param);
+     curvMin = curvMax;
+     return curvMax;
+@@ -961,8 +961,8 @@ double GFace::curvatures(const SPoint2 &param, SVector
+   // curvatures and main directions
+   curvMax = fabs(eigVal[1]);
+   curvMin = fabs(eigVal[0]);
+-  dirMax = eigVec[1] * D1.first() + eigVec[3] * D1.second();
+-  dirMin = eigVec[0] * D1.first() + eigVec[2] * D1.second();
++  dirMax = eigVec[1] * D1.first + eigVec[3] * D1.second;
++  dirMin = eigVec[0] * D1.first + eigVec[2] * D1.second;
+ 
+   return curvMax;
+ }
+@@ -979,9 +979,9 @@ void GFace::getMetricEigenVectors(const SPoint2 &param
+                                   double eigVec[4]) const
+ {
+   // first derivatives
+-  Pair<SVector3, SVector3> D1 = firstDer(param);
+-  SVector3 du = D1.first();
+-  SVector3 dv = D1.second();
++  std::pair<SVector3, SVector3> D1 = firstDer(param);
++  SVector3 du = D1.first;
++  SVector3 dv = D1.second;
+   SVector3 nor = crossprod(du, dv);
+   nor.normalize();
+ 
+@@ -1088,13 +1088,13 @@ void GFace::XYZtoUV(double X, double Y, double Z, doub
+ 
+       while(err > tol && iter < MaxIter) {
+         P = point(U, V);
+-        Pair<SVector3, SVector3> der = firstDer(SPoint2(U, V));
+-        mat[0][0] = der.left().x();
+-        mat[0][1] = der.left().y();
+-        mat[0][2] = der.left().z();
+-        mat[1][0] = der.right().x();
+-        mat[1][1] = der.right().y();
+-        mat[1][2] = der.right().z();
++        std::pair<SVector3, SVector3> der = firstDer(SPoint2(U, V));
++        mat[0][0] = der.first.x();
++        mat[0][1] = der.first.y();
++        mat[0][2] = der.first.z();
++        mat[1][0] = der.second.x();
++        mat[1][1] = der.second.y();
++        mat[1][2] = der.second.z();
+         mat[2][0] = 0.;
+         mat[2][1] = 0.;
+         mat[2][2] = 0.;
+@@ -1193,15 +1193,15 @@ void bfgs_callback(const alglib::real_1d_array &x, dou
+   // printf("func : %f\n", func);
+ 
+   // Value of the gradient
+-  Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(x[0], x[1]));
+-  grad[0] = -(p.x() - pnt.x()) * der.left().x() -
+-            (p.y() - pnt.y()) * der.left().y() -
+-            (p.z() - pnt.z()) * der.left().z();
+-  grad[1] = -(p.x() - pnt.x()) * der.right().x() -
+-            (p.y() - pnt.y()) * der.right().y() -
+-            (p.z() - pnt.z()) * der.right().z();
++  std::pair<SVector3, SVector3> der = gf->firstDer(SPoint2(x[0], x[1]));
++  grad[0] = -(p.x() - pnt.x()) * der.first.x() -
++            (p.y() - pnt.y()) * der.first.y() -
++            (p.z() - pnt.z()) * der.first.z();
++  grad[1] = -(p.x() - pnt.x()) * der.second.x() -
++            (p.y() - pnt.y()) * der.second.y() -
++            (p.z() - pnt.z()) * der.second.z();
+   // printf("func %22.15E Gradients %22.15E %22.15E der %g %g %g\n", func,
+-  //         grad[0], grad[1],der.left().x(),der.left().y(),der.left().z());
++  //         grad[0], grad[1],der.first.x(),der.first.y(),der.first.z());
+ }
+ #endif
+ 
+@@ -1296,8 +1296,8 @@ SVector3 GFace::normal(const SPoint2 &param) const
+ {
+   if(geomType() == BoundaryLayerSurface) return SVector3();
+ 
+-  Pair<SVector3, SVector3> der = firstDer(param);
+-  SVector3 n = crossprod(der.first(), der.second());
++  std::pair<SVector3, SVector3> der = firstDer(param);
++  SVector3 n = crossprod(der.first, der.second);
+   n.normalize();
+   return n;
+ }
diff --git a/cad/gmsh/files/patch-src_geo_GFace.h b/cad/gmsh/files/patch-src_geo_GFace.h
new file mode 100644
index 000000000000..6155c2ff1b67
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_GFace.h
@@ -0,0 +1,26 @@
+--- src/geo/GFace.h.orig	2024-03-29 22:07:00 UTC
++++ src/geo/GFace.h
+@@ -10,13 +10,13 @@
+ #include <string>
+ #include <vector>
+ #include <map>
++#include <utility>
+ #include "GmshDefines.h"
+ #include "GEntity.h"
+ #include "GPoint.h"
+ #include "GEdgeLoop.h"
+ #include "SPoint2.h"
+ #include "SVector3.h"
+-#include "Pair.h"
+ #include "Numeric.h"
+ #include "boundaryLayersData.h"
+ 
+@@ -201,7 +201,7 @@ class GFace : public GEntity { (public)
+   virtual SVector3 normal(const SPoint2 &param) const;
+ 
+   // return the first derivate of the face at the parameter location
+-  virtual Pair<SVector3, SVector3> firstDer(const SPoint2 &param) const = 0;
++  virtual std::pair<SVector3, SVector3> firstDer(const SPoint2 &param) const = 0;
+ 
+   // compute the second derivates of the face at the parameter location
+   virtual void secondDer(const SPoint2 &param, SVector3 &dudu, SVector3 &dvdv,
diff --git a/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.cpp b/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.cpp
new file mode 100644
index 000000000000..a78293d1f542
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.cpp
@@ -0,0 +1,274 @@
+--- src/geo/GeomMeshMatcher.cpp.orig	2024-03-29 22:07:00 UTC
++++ src/geo/GeomMeshMatcher.cpp
+@@ -12,7 +12,6 @@
+ #include <list>
+ #include <vector>
+ #include "GeomMeshMatcher.h"
+-#include "Pair.h"
+ #include "discreteVertex.h"
+ #include "GmshMessage.h"
+ #include "SOrientedBoundingBox.h"
+@@ -61,22 +60,22 @@ void getIntersection(std::vector<T> &res, std::vector<
+   }
+ }
+ 
+-template <class T> T findMatching(std::vector<Pair<T, T> > &matching, T &entity)
++template <class T> T findMatching(std::vector<std::pair<T, T> > &matching, T &entity)
+ {
+   for(auto pair = matching.begin(); pair != matching.end(); pair++) {
+-    if((*pair).left() == entity) return ((*pair).right());
++    if((*pair).first == entity) return ((*pair).second);
+   }
+   return (0);
+ }
+ 
+ // Matching vertices
+ 
+-std::vector<Pair<GVertex *, GVertex *> > *
++std::vector<std::pair<GVertex *, GVertex *> > *
+ GeomMeshMatcher::matchVertices(GModel *m1, GModel *m2, bool &ok)
+ {
+   // Vector that will be returned.
+-  std::vector<Pair<GVertex *, GVertex *> > *coresp_v =
+-    new std::vector<Pair<GVertex *, GVertex *> >;
++  std::vector<std::pair<GVertex *, GVertex *> > *coresp_v =
++    new std::vector<std::pair<GVertex *, GVertex *> >;
+   int num_matched_vertices = 0;
+   int num_total_vertices = m2->getNumVertices();
+ 
+@@ -107,7 +106,7 @@ GeomMeshMatcher::matchVertices(GModel *m1, GModel *m2,
+ 
+     if(choice && best_score != DBL_MAX) {
+       choice->physicals = v1->physicals;
+-      coresp_v->push_back(Pair<GVertex *, GVertex *>(v1, choice));
++      coresp_v->push_back(std::make_pair(v1, choice));
+       num_matched_vertices++;
+     }
+   }
+@@ -120,17 +119,17 @@ GeomMeshMatcher::matchVertices(GModel *m1, GModel *m2,
+ 
+ // Matching edges
+ 
+-std::vector<Pair<GEdge *, GEdge *> > *
++std::vector<std::pair<GEdge *, GEdge *> > *
+ GeomMeshMatcher::matchEdges(GModel *m1, GModel *m2,
+-                            std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
++                            std::vector<std::pair<GVertex *, GVertex *> > *coresp_v,
+                             bool &ok)
+ {
+   int num_matched_edges = 0;
+   int num_total_edges = m2->getNumEdges();
+ 
+   // Vector that will be returned.
+-  std::vector<Pair<GEdge *, GEdge *> > *coresp_e =
+-    new std::vector<Pair<GEdge *, GEdge *> >;
++  std::vector<std::pair<GEdge *, GEdge *> > *coresp_e =
++    new std::vector<std::pair<GEdge *, GEdge *> >;
+ 
+   std::vector<GEdge *> closed_curves;
+ 
+@@ -195,7 +194,7 @@ GeomMeshMatcher::matchEdges(GModel *m1, GModel *m2,
+         }
+       }
+     }
+-    coresp_e->push_back(Pair<GEdge *, GEdge *>(e1, choice));
++    coresp_e->push_back(std::make_pair(e1, choice));
+ 
+     // copy topological information
+     if(choice) {
+@@ -213,16 +212,16 @@ GeomMeshMatcher::matchEdges(GModel *m1, GModel *m2,
+ 
+ // Matching faces
+ 
+-std::vector<Pair<GFace *, GFace *> > *
++std::vector<std::pair<GFace *, GFace *> > *
+ GeomMeshMatcher::matchFaces(GModel *m1, GModel *m2,
+-                            std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
++                            std::vector<std::pair<GEdge *, GEdge *> > *coresp_e,
+                             bool &ok)
+ {
+   int num_matched_faces = 0;
+   int num_total_faces = m2->getNumFaces();
+ 
+-  std::vector<Pair<GFace *, GFace *> > *coresp_f =
+-    new std::vector<Pair<GFace *, GFace *> >;
++  std::vector<std::pair<GFace *, GFace *> > *coresp_f =
++    new std::vector<std::pair<GFace *, GFace *> >;
+ 
+   for(auto fit = m1->firstFace(); fit != m1->lastFace(); fit++) {
+     GFace *f1 = (GFace *)*fit;
+@@ -276,7 +275,7 @@ GeomMeshMatcher::matchFaces(GModel *m1, GModel *m2,
+ 
+     if(choice) {
+       Msg::Debug("Surfaces %i and %i match", f1->tag(), choice->tag());
+-      coresp_f->push_back(Pair<GFace *, GFace *>(f1, choice));
++      coresp_f->push_back(std::make_pair(f1, choice));
+       // copy topological information
+       choice->setTag(f1->tag());
+       f1->physicals = choice->physicals;
+@@ -292,17 +291,17 @@ GeomMeshMatcher::matchFaces(GModel *m1, GModel *m2,
+ 
+ // Matching regions
+ 
+-std::vector<Pair<GRegion *, GRegion *> > *
++std::vector<std::pair<GRegion *, GRegion *> > *
+ GeomMeshMatcher::matchRegions(GModel *m1, GModel *m2,
+-                              std::vector<Pair<GFace *, GFace *> > *coresp_f,
++                              std::vector<std::pair<GFace *, GFace *> > *coresp_f,
+                               bool &ok)
+ 
+ {
+   int num_matched_regions = 0;
+   int num_total_regions = 0;
+ 
+-  std::vector<Pair<GRegion *, GRegion *> > *coresp_r =
+-    new std::vector<Pair<GRegion *, GRegion *> >;
++  std::vector<std::pair<GRegion *, GRegion *> > *coresp_r =
++    new std::vector<std::pair<GRegion *, GRegion *> >;
+ 
+   std::vector<GEntity *> m1_entities;
+   m1->getEntities(m1_entities, 3);
+@@ -344,8 +343,7 @@ GeomMeshMatcher::matchRegions(GModel *m1, GModel *m2,
+     }
+ 
+     if(common_regions.size() == 1) {
+-      coresp_r->push_back(
+-        Pair<GRegion *, GRegion *>((GRegion *)*entity1, common_regions[0]));
++      coresp_r->push_back(std::make_pair((GRegion *)*entity1, common_regions[0]));
+       common_regions[0]->setTag(((GRegion *)*entity1)->tag());
+       (*entity1)->physicals = common_regions[0]->physicals;
+       num_matched_regions++;
+@@ -377,8 +375,7 @@ GeomMeshMatcher::matchRegions(GModel *m1, GModel *m2,
+           choice = (*candidate);
+         }
+       }
+-      coresp_r->push_back(
+-        Pair<GRegion *, GRegion *>((GRegion *)*entity1, choice));
++      coresp_r->push_back(std::make_pair((GRegion *)*entity1, choice));
+       if(choice) {
+         choice->setTag(((GRegion *)*entity1)->tag());
+         (*entity1)->physicals = choice->physicals;
+@@ -594,13 +591,13 @@ template <class GEType>
+ }
+ 
+ template <class GEType>
+-static void copy_periodicity(std::vector<Pair<GEType *, GEType *> > &eCor,
++static void copy_periodicity(std::vector<std::pair<GEType *, GEType *> > &eCor,
+                              std::map<MVertex *, MVertex *> &mesh_to_geom)
+ {
+   typename std::multimap<GEType *, GEType *> eMap; // (eCor.begin(),eCor.end());
+   auto eIter = eCor.begin();
+   for(; eIter != eCor.end(); ++eIter) {
+-    eMap.insert(std::make_pair(eIter->second(), eIter->first()));
++    eMap.insert(std::make_pair(eIter->second, eIter->first));
+   }
+ 
+   auto srcIter = eMap.begin();
+@@ -651,12 +648,12 @@ template <class GEType>
+ }
+ 
+ template <class GEType>
+-static bool apply_periodicity(std::vector<Pair<GEType *, GEType *> > &eCor)
++static bool apply_periodicity(std::vector<std::pair<GEType *, GEType *> > &eCor)
+ {
+   typename std::multimap<GEType *, GEType *> eMap; // (eCor.begin(),eCor.end());
+   auto eIter = eCor.begin();
+   for(; eIter != eCor.end(); ++eIter) {
+-    eMap.insert(std::make_pair(eIter->second(), eIter->first()));
++    eMap.insert(std::make_pair(eIter->second, eIter->first));
+   }
+ 
+   auto srcIter = eMap.begin();
+@@ -787,57 +784,57 @@ void copy_vertices(GModel *geom, GModel *mesh,
+ 
+ void copy_vertices(GModel *geom, GModel *mesh,
+                    std::map<MVertex *, MVertex *> &_mesh_to_geom,
+-                   std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
+-                   std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
+-                   std::vector<Pair<GFace *, GFace *> > *coresp_f,
+-                   std::vector<Pair<GRegion *, GRegion *> > *coresp_r)
++                   std::vector<std::pair<GVertex *, GVertex *> > *coresp_v,
++                   std::vector<std::pair<GEdge *, GEdge *> > *coresp_e,
++                   std::vector<std::pair<GFace *, GFace *> > *coresp_f,
++                   std::vector<std::pair<GRegion *, GRegion *> > *coresp_r)
+ {
+   // copy all elements
+   for(std::size_t i = 0; i < coresp_v->size(); ++i)
+-    copy_vertices((*coresp_v)[i].first(), (*coresp_v)[i].second(),
++    copy_vertices((*coresp_v)[i].first, (*coresp_v)[i].second,
+                   _mesh_to_geom);
+   for(std::size_t i = 0; i < coresp_e->size(); ++i)
+-    copy_vertices((*coresp_e)[i].first(), (*coresp_e)[i].second(),
++    copy_vertices((*coresp_e)[i].first, (*coresp_e)[i].second,
+                   _mesh_to_geom);
+   for(std::size_t i = 0; i < coresp_f->size(); ++i)
+-    copy_vertices((*coresp_f)[i].first(), (*coresp_f)[i].second(),
++    copy_vertices((*coresp_f)[i].first, (*coresp_f)[i].second,
+                   _mesh_to_geom);
+   for(std::size_t i = 0; i < coresp_r->size(); ++i)
+-    copy_vertices((*coresp_r)[i].first(), (*coresp_r)[i].second(),
++    copy_vertices((*coresp_r)[i].first, (*coresp_r)[i].second,
+                   _mesh_to_geom);
+ }
+ void copy_elements(GModel *geom, GModel *mesh,
+                    std::map<MVertex *, MVertex *> &_mesh_to_geom,
+-                   std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
+-                   std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
+-                   std::vector<Pair<GFace *, GFace *> > *coresp_f,
+-                   std::vector<Pair<GRegion *, GRegion *> > *coresp_r)
++                   std::vector<std::pair<GVertex *, GVertex *> > *coresp_v,
++                   std::vector<std::pair<GEdge *, GEdge *> > *coresp_e,
++                   std::vector<std::pair<GFace *, GFace *> > *coresp_f,
++                   std::vector<std::pair<GRegion *, GRegion *> > *coresp_r)
+ {
+   // copy all elements
+ 
+   for(std::size_t i = 0; i < coresp_v->size(); ++i) {
+-    GVertex *dest = (*coresp_v)[i].first();
+-    GVertex *orig = (*coresp_v)[i].second();
++    GVertex *dest = (*coresp_v)[i].first;
++    GVertex *orig = (*coresp_v)[i].second;
+     copy_elements<MPoint>(dest->points, orig->points, _mesh_to_geom);
+   }
+ 
+   for(std::size_t i = 0; i < coresp_e->size(); ++i) {
+-    GEdge *dest = (*coresp_e)[i].first();
+-    GEdge *orig = (*coresp_e)[i].second();
++    GEdge *dest = (*coresp_e)[i].first;
++    GEdge *orig = (*coresp_e)[i].second;
+     copy_elements<MLine>(dest->lines, orig->lines, _mesh_to_geom);
+   }
+ 
+   for(std::size_t i = 0; i < coresp_f->size(); ++i) {
+-    GFace *dest = (*coresp_f)[i].first();
+-    GFace *orig = (*coresp_f)[i].second();
++    GFace *dest = (*coresp_f)[i].first;
++    GFace *orig = (*coresp_f)[i].second;
+     copy_elements<MTriangle>(dest->triangles, orig->triangles, _mesh_to_geom);
+     copy_elements<MQuadrangle>(dest->quadrangles, orig->quadrangles,
+                                _mesh_to_geom);
+   }
+ 
+   for(std::size_t i = 0; i < coresp_r->size(); ++i) {
+-    GRegion *dest = (*coresp_r)[i].first();
+-    GRegion *orig = (*coresp_r)[i].second();
++    GRegion *dest = (*coresp_r)[i].first;
++    GRegion *orig = (*coresp_r)[i].second;
+     copy_elements<MTetrahedron>(dest->tetrahedra, orig->tetrahedra,
+                                 _mesh_to_geom);
+     copy_elements<MHexahedron>(dest->hexahedra, orig->hexahedra, _mesh_to_geom);
+@@ -857,10 +854,10 @@ int GeomMeshMatcher::match(GModel *geom, GModel *mesh)
+ 
+   bool ok = true;
+ 
+-  std::vector<Pair<GVertex *, GVertex *> > *coresp_v(nullptr);
+-  std::vector<Pair<GEdge *, GEdge *> > *coresp_e(nullptr);
+-  std::vector<Pair<GFace *, GFace *> > *coresp_f(nullptr);
+-  std::vector<Pair<GRegion *, GRegion *> > *coresp_r(nullptr);
++  std::vector<std::pair<GVertex *, GVertex *> > *coresp_v(nullptr);
++  std::vector<std::pair<GEdge *, GEdge *> > *coresp_e(nullptr);
++  std::vector<std::pair<GFace *, GFace *> > *coresp_f(nullptr);
++  std::vector<std::pair<GRegion *, GRegion *> > *coresp_r(nullptr);
+ 
+   coresp_v = matchVertices(geom, mesh, ok);
+   if(ok) {
diff --git a/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.h b/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.h
new file mode 100644
index 000000000000..a22748865e45
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_GeomMeshMatcher.h
@@ -0,0 +1,32 @@
+--- src/geo/GeomMeshMatcher.h.orig	2024-03-29 22:07:00 UTC
++++ src/geo/GeomMeshMatcher.h
+@@ -16,21 +16,20 @@
+ #include "GEdge.h"
+ #include "GFace.h"
+ #include "GRegion.h"
+-#include "Pair.h"
+ 
+ class GeomMeshMatcher {
+ private:
+-  std::vector<Pair<GVertex *, GVertex *> > *matchVertices(GModel *m1,
+-                                                          GModel *m2, bool &ok);
+-  std::vector<Pair<GEdge *, GEdge *> > *
++  std::vector<std::pair<GVertex *, GVertex *> > *
++  matchVertices(GModel *m1, GModel *m2, bool &ok);
++  std::vector<std::pair<GEdge *, GEdge *> > *
+   matchEdges(GModel *m1, GModel *m2,
+-             std::vector<Pair<GVertex *, GVertex *> > *coresp_v, bool &ok);
+-  std::vector<Pair<GFace *, GFace *> > *
++             std::vector<std::pair<GVertex *, GVertex *> > *coresp_v, bool &ok);
++  std::vector<std::pair<GFace *, GFace *> > *
+   matchFaces(GModel *m1, GModel *m2,
+-             std::vector<Pair<GEdge *, GEdge *> > *coresp_e, bool &ok);
+-  std::vector<Pair<GRegion *, GRegion *> > *
++             std::vector<std::pair<GEdge *, GEdge *> > *coresp_e, bool &ok);
++  std::vector<std::pair<GRegion *, GRegion *> > *
+   matchRegions(GModel *m1, GModel *m2,
+-               std::vector<Pair<GFace *, GFace *> > *coresp_f, bool &ok);
++               std::vector<std::pair<GFace *, GFace *> > *coresp_f, bool &ok);
+   static GeomMeshMatcher *_gmm_instance;
+   GeomMeshMatcher() {}
+   ~GeomMeshMatcher() {}
diff --git a/cad/gmsh/files/patch-src_geo_OCCFace.cpp b/cad/gmsh/files/patch-src_geo_OCCFace.cpp
new file mode 100644
index 000000000000..4d34954ee598
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_OCCFace.cpp
@@ -0,0 +1,19 @@
+--- src/geo/OCCFace.cpp.orig	2024-03-29 22:07:01 UTC
++++ src/geo/OCCFace.cpp
+@@ -249,13 +249,13 @@ SVector3 OCCFace::normal(const SPoint2 &param) const
+   return n;
+ }
+ 
+-Pair<SVector3, SVector3> OCCFace::firstDer(const SPoint2 &param) const
++std::pair<SVector3, SVector3> OCCFace::firstDer(const SPoint2 &param) const
+ {
+   gp_Pnt pnt;
+   gp_Vec du, dv;
+   _occface->D1(param.x(), param.y(), pnt, du, dv);
+-  return Pair<SVector3, SVector3>(SVector3(du.X(), du.Y(), du.Z()),
+-                                  SVector3(dv.X(), dv.Y(), dv.Z()));
++  return std::make_pair(SVector3(du.X(), du.Y(), du.Z()),
++                        SVector3(dv.X(), dv.Y(), dv.Z()));
+ }
+ 
+ void OCCFace::secondDer(const SPoint2 &param, SVector3 &dudu, SVector3 &dvdv,
diff --git a/cad/gmsh/files/patch-src_geo_OCCFace.h b/cad/gmsh/files/patch-src_geo_OCCFace.h
new file mode 100644
index 000000000000..bf34b80f4372
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_OCCFace.h
@@ -0,0 +1,11 @@
+--- src/geo/OCCFace.h.orig	2024-03-29 22:07:01 UTC
++++ src/geo/OCCFace.h
+@@ -42,7 +42,7 @@ class OCCFace : public GFace { (public)
+   virtual bool containsPoint(const SPoint3 &pt) const;
+   virtual bool containsParam(const SPoint2 &pt);
+   virtual SVector3 normal(const SPoint2 &param) const;
+-  virtual Pair<SVector3, SVector3> firstDer(const SPoint2 &param) const;
++  virtual std::pair<SVector3, SVector3> firstDer(const SPoint2 &param) const;
+   virtual void secondDer(const SPoint2 &, SVector3 &, SVector3 &,
+                          SVector3 &) const;
+   virtual GEntity::GeomType geomType() const;
diff --git a/cad/gmsh/files/patch-src_geo_Pair.h b/cad/gmsh/files/patch-src_geo_Pair.h
new file mode 100644
index 000000000000..d99d6a3bcd43
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_Pair.h
@@ -0,0 +1,29 @@
+--- src/geo/Pair.h.orig	2024-03-29 22:07:01 UTC
++++ src/geo/Pair.h
+@@ -1,26 +0,0 @@
+-// Gmsh - Copyright (C) 1997-2024 C. Geuzaine, J.-F. Remacle
+-//
+-// See the LICENSE.txt file in the Gmsh root directory for license information.
+-// Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
+-
+-#ifndef PAIR_H
+-#define PAIR_H
+-
+-// A pair of values, the types of which can be different
+-template <class L, class R> class Pair {
+-private:
+-  L Left;
+-  R Right;
+-
+-public:
+-  Pair() {}
+-  Pair(const L &left, const R &right) : Left(left), Right(right) {}
+-  L left() const { return Left; }
+-  void left(const L &left) { Left = left; }
+-  R right() const { return Right; }
+-  void right(const R &right) { Right = right; }
+-  L first() const { return Left; }
+-  R second() const { return Right; }
+-};
+-
+-#endif
diff --git a/cad/gmsh/files/patch-src_geo_discreteFace.cpp b/cad/gmsh/files/patch-src_geo_discreteFace.cpp
new file mode 100644
index 000000000000..52bbff44c5fe
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_discreteFace.cpp
@@ -0,0 +1,33 @@
+--- src/geo/discreteFace.cpp.orig	2024-04-18 14:52:42 UTC
++++ src/geo/discreteFace.cpp
+@@ -363,16 +363,16 @@ double discreteFace::curvatures(const SPoint2 &param, 
+   return false;
+ }
+ 
+-Pair<SVector3, SVector3> discreteFace::firstDer(const SPoint2 &param) const
++std::pair<SVector3, SVector3> discreteFace::firstDer(const SPoint2 &param) const
+ {
+-  if(_param.empty()) return Pair<SVector3, SVector3>(SVector3(), SVector3());
++  if(_param.empty()) return std::make_pair(SVector3(), SVector3());
+ 
+   MElement *e = _param.oct->find(param.x(), param.y(), 0.0, -1, true);
+   if(!e) {
+     Msg::Info("Triangle not found for first derivative at uv=(%g,%g) on "
+               "discrete surface %d",
+               param.x(), param.y(), tag());
+-    return Pair<SVector3, SVector3>(SVector3(1, 0, 0), SVector3(0, 1, 0));
++    return std::make_pair(SVector3(1, 0, 0), SVector3(0, 1, 0));
+   }
+ 
+   int position = (int)((MTriangle *)e - &_param.t2d[0]);
+@@ -403,8 +403,8 @@ Pair<SVector3, SVector3> discreteFace::firstDer(const 
+     }
+   }
+ 
+-  return Pair<SVector3, SVector3>(SVector3(dxdu[0][0], dxdu[1][0], dxdu[2][0]),
+-                                  SVector3(dxdu[0][1], dxdu[1][1], dxdu[2][1]));
++  return std::make_pair(SVector3(dxdu[0][0], dxdu[1][0], dxdu[2][0]),
++                        SVector3(dxdu[0][1], dxdu[1][1], dxdu[2][1]));
+ }
+ 
+ void discreteFace::secondDer(const SPoint2 &param, SVector3 &dudu,
diff --git a/cad/gmsh/files/patch-src_geo_discreteFace.h b/cad/gmsh/files/patch-src_geo_discreteFace.h
new file mode 100644
index 000000000000..dcbc173e68d0
--- /dev/null
+++ b/cad/gmsh/files/patch-src_geo_discreteFace.h
@@ -0,0 +1,11 @@
+--- src/geo/discreteFace.h.orig	2024-04-18 14:52:42 UTC
*** 242 LINES SKIPPED ***