How to convert a surface into a solid

Method 1: Construct mesh elements manually

We can triangulate a periodic quad-lattice on the surface:

n = {180, 20};  (* number of points in each direction *)
pts = Table[
   g[4. Pi/n[[1]] t, 2. Pi/ n[[2]] θ], {t, n[[1]]}, {θ, n[[2]]}];

idcs = {{{1, 2, 4}, {1, 4, 3}}, {{1, 2, 3}, {2, 4, 3}}};  (* for a diamond pattern *)
tri = 1 +
  Array[Function[quad, quad[[#]] & /@ idcs[[Mod[+##, 2, 1]]]][Tuples[
        {Mod[#1 + {-1, 0}, Dimensions[pts][[1]]],
         Mod[#2 + {-1, 0}, Dimensions[pts][[2]]]}].{Length[First@pts], 1}] &,
       Most@Dimensions[pts]];

Needs["NDSolve`FEM`"].
bmesh = ToBoundaryMesh[
  "Coordinates" -> Flatten[pts, 1],
  "BoundaryElements" -> {TriangleElement[Flatten[tri, 2]]}
  ]

emesh = ToElementMesh[bmesh]
(*
  ElementMesh[{{-4.86396, 1.5}, {-3.32664, 3.32664}, {-1.5, 1.5}},
   {TetrahedronElement["<" 21544 ">"]}]
*)

MeshRegion@emesh

Mathematica graphics

Notes:

Tuple generates the indices of the quadrilaterals in each row (#1) & column (#2`), wrapping around at the end of the domain to close up the tube:

Tuples[{Mod[#1 + {-1, 0}, Dimensions[pts][[1]]],
        Mod[#2 + {-1, 0}, Dimensions[pts][[2]]]}]

The dot product with {Length[First@pts], 1} converts a {row, column} pair to the index of the corresponding point in pts.

We triangulate the quadrilaterals by alternating which diagonal is used. The variable idcs contains two lists of two triangles, representing both ways. The integers themselves are indices of the quadrilateral (given by Tuples[..].{Length[..], 1} above).

idcs = {{{1, 2, 4}, {1, 4, 3}},   (* 1-4 diagonal *)
        {{1, 2, 3}, {2, 4, 3}}};  (* 2-3 diagonal *)

Method 2: Mesh the domain and apply parametrization

This takes more advantage of FEM/ElementMesh capabilities. First mesh the domain. Then apply g to map domain mesh coordinates onto to the surface. Use these coordinates and the domain mesh to construct a boundary mesh on the surface. Finally, use ToElementMesh to construct a mesh of the solid.

 Needs["NDSolve`FEM`"]

tscale = 4; θscale = 0.5;                (* scale roughly proportional to speeds *)
dom = ToElementMesh[FullRegion[2], {{0, tscale}, {0, θscale}},         (* domain *)
   MaxCellMeasure -> {"Area" -> 0.001}];
coords = g[4 Pi #1/tscale, 2 Pi #2/θscale] & @@@ dom["Coordinates"];   (* apply g *)
bmesh2 = ToBoundaryMesh[
   "Coordinates" -> coords,
   "BoundaryElements" -> dom["MeshElements"]
   ];
emesh2 = ToElementMesh@ bmesh2
(*
  ElementMesh[{{-4.86407, 1.5}, {-3.32362, 3.32362}, {-1.49991, 1.49991}},
   {TetrahedronElement["<" 5581 ">"]}]
*)

MeshRegion@ emesh2

Mathematica graphics

Note: I thought I would have to glue the boundaries together by hand, but ToBoundaryMesh seems to handle it for me. :D


Here is an attempt to use MichaelE2's method 2 but only using built-in functions with no need to load the FEM package.

tscale = 4; θscale = 0.5;
domain = DiscretizeRegion[FullRegion[2], {{0, tscale}, {0, θscale}}, 
                          MaxCellMeasure -> {"Area" -> 0.0005}]
coords = g[4 Pi #1/tscale, 2 Pi #2/θscale] & @@@ MeshCoordinates[domain];  
         (* This is the same g defined in the question *)
mr = MeshRegion[coords, MeshCells[domain, 2]];

Here is where it gets tricky with built-in functions. I first convert the MeshRegion mr to a Graphics3D object using Show then discretize the boundary and finally use TriangulateMesh to get a solid. BoundaryMeshRegion seems to fail here, hence, the workaround.

tm = TriangulateMesh @ BoundaryDiscretizeGraphics @ Show @ mr

Mathematica graphics

MeshCellCount[tm, 3] > 0    (* check that there are 3D cells *)

True


For a closed surface such as this one, a slight modification of the function MakeTriangleMesh[] in this answer can be used:

MakeTriangleMesh[vl_List, {closedu : (True | False) : False,
                           closedv : (True | False) : False}, opts___] := 
       Module[{dims = Most[Dimensions[vl]], v = vl, idx},
              idx = Partition[Range[Times @@ dims], Last[dims]];
              If[TrueQ[closedu],
                 v = Most[v]; idx = Append[Most[idx], First[idx]]];
              If[TrueQ[closedv],
                 v = Most /@ v; idx = Composition[Append[#, First[#]] &, Most] /@ idx];
              BoundaryMeshRegion[Apply[Join, vl], 
                                 Triangle[Flatten[Apply[{Append[Reverse[#1], Last[#2]], 
                                                         Prepend[#2, First[#1]]} &, 
                                 Partition[idx, {2, 2}, {1, 1}], {2}], 2]], opts]] /;
       ArrayQ[vl, 3]

With[{m = 101, n = 31},
     MakeTriangleMesh[N[Table[Evaluate @ g[t, θ],
                              {t, 0, 4 π, 4 π/(m - 1)}, {θ, 0, 2 π, 2 π/(n - 1)}]],
                      {True, True}]]

meshed tube

Compute the volume:

Volume[%]
   24.674785447032324