I'm trying to analyze a circuit card assembly (CCA). The biggest problem is always trying to mesh the thin copper layers along with the thicker epoxy layers between. I'm making the approximation that because the copper layers are so thin, and copper's thermal conductivity is so high, the normal-direction temperature change is negligible. Thus, they can be modeled as 2D or shell elements. I know Gmsh can handle this part, but can I (and if so, how?) also add in 3D elements for the epoxy layers and electrical components? TIA.
If I understand what you're saying, you have something like a sandwich of epoxy layers that have appreciable thickness (modeled in 3D) and a thin copper layer between them that has negligible thickness (modeled in 2D). In that case, you probably want to use some sort of 2D cohesive element for the negligibly thick copper layer.
If you opt for that approach, there are two basic methods to try:
- intrinsic cohesive elements: you can insert the cohesive elements implicitly, so you restructure your equations to solve for a jump across the copper layer
- extrinsic cohesive elements: you insert the cohesive elements explicitly by duplicating nodes along the copper layer interface, and tweak the mesh connectivity so that the copper layer is actually represented as a gap in the mesh (a crack); you solve for the temperature on either side of the layer (I'm assuming you're doing thermal modeling)
For the extrinsic approach, Gmsh has a plug-in called Crack that's supposed to do all of the mesh arrangement for you, where you label the interface as a Physical Group (see the Gmsh documentation), label the endpoints with another Physical Group, generate your mesh without the crack, and then postprocess the mesh with the crack plugin. Here is an example of how to do that with a really simple mesh.
The problem with Crack is that it will insert duplicate nodes correctly, but it will louse up the connectivity of edges and elements. In theory, if you have say, just two epoxy layers separated by a thin copper layer, you should get two connected components in your mesh, and no edges, faces, or 3D elements should cross the copper interface. In practice, you can get edges and 3D elements (well, I tried this with a 2D test case, so I had 2D elements that spanned the cracked interface in my mesh). I described this behavior to the developers and I haven't heard back from them as to whether it is a bug, or intentional. Regardless, for my application, I couldn't use the resulting mesh, and I suspect it won't work for your problem either.
You can, however, use Gmsh or some other generator anyway to generate a 3D mesh, and then manually modify it within your code to duplicate nodes along a crack and connect those duplicate nodes to the mesh in the proper fashion. The best paper to describe this process I could find is this one by Mota, Knap, and Ortiz; most of the other papers I found weren't terribly useful (Paulino's work didn't go into the algorithms very much; an earlier algorithm by Ortiz didn't yield the correct result, as mentioned in the linked paper).
Similar algorithms for inserting cohesive elements and changing the mesh connectivity are in PETSc within DMPlex, such as DMPlexConstructCohesiveCells, although I don't think there's very much documentation on them (there are a couple algorithms papers that describe it, but I found the math in the Ortiz paper easier to understand, despite knowing nothing about algebraic topology), so if you use PETSc, there's no need to reinvent the wheel, as long as you can figure out how to use the cohesive element insertion functions; the PETSc mailing list should be able to help you with that if you decide to go that route.
If you understand the gist of the Mota-Knap-Ortiz paper, you could also write your own routines for manipulating the mesh, which is what I did in a private fork of MeshPy.
EDIT: The difference between the intrinsic and extrinsic approaches, from what I understand, is that in the extrinsic approach, you modify your mesh explicitly, and then mesh nodes correspond to degrees of freedom in your problem. In the intrinsic approach, you don't modify your mesh, you just modify the system of equations you get from your FEM discretization to get a system of equations equivalent to what you would get if you took the extrinsic approach. I don't think the intrinsic approach is any easier; if you can construct the equations in the intrinsic approach, you can probably back out what your mesh would have to look like in the extrinsic approach, and vice versa. Then again, I've only implemented the extrinsic approach.
Also, if you can get the mesh you need with a break in it, then setting up the equations is relatively easy. The interfacial contributions look very similar to a discontinuous Galerkin approach, so you can calculate the terms in your weak form by analogy. Any really basic treatment of discontinuous Galerkin, like Chapter 14 in The Finite Element Method: Theory, Implementation, and Applications (Texts in Computational Science and Engineering) by Larson and Bengzon will work.
In theory, Cubit is supposed to generate cohesive elements, but I could never get that functionality to work. Gmsh's Crack Plugin works sometimes, but not reliably. If your geometry is relatively simple, you might try to construct the mesh yourself by hand, or fix up a mesh generated by Gmsh, but for more complicated geometries, you definitely want to automate the procedure.
You could also use an XFEM approach. I can't help you with how to implement it, but you could look at this paper, which is also useful in providing a linear heat transfer problem similar to the one you are describing. The linear heat transfer problem is useful as a test case for debugging your implementation.
Another approach is to tie together using constraint equations. You need to have the same number of DOFs at each node participating in a constraint equation. So, if this is structural problem (is it?) then shell elements have 6 DOFs at each node and 3D mesh nodes need to have the 6 DOFs also, namely 3 displacement and 3 rotatoinal DOFs. If it a scalar problem (heat equation or equivalently Poisson equation) then obviously nothing to do other than impose the constraint equations. in any case, if one has a conforming mesh, then the constraint equations are of simpler form.
Most FEA software do genertate constraint equations and coupling equations and pass them on to the solver as side constraints. The solver has to find a solution to the linear system subject to the condition that the solution vector lies in the subspace satisfying the constraint equations.
Most static mesh generators create a mesh in stages. First it meshes all the edges (1D spaces), then the faces of the geometry (2D spaces), and finally the volumes (3D spaces). As such, gmsh is already doing what you want. Place a face where the copper layer is located with volumes on each side for the epoxy. You can mark the face as a different material group to differentiate it, then in your solver you handle that case in 2D, while handling the rest in 3D.
I haven't used worked with GMSH outputs in a while, so I don't remember exactly how the outputs are formatted. Likely the copper layers would be formatted very similarly to how external boundary faces would be formatted. The hard part of mixing 2D and 3D geometry is in the solver, as the mesh generators already handle it in most cases.
Based on my imperfect understanding of the geometry, an idea occurred to me that you might want to consider.
I'm assuming the copper circuit traces are laid out on a rectangular grid even though the circuits may be quite different on either side of the epoxy insulating layer. I suspect that a 1D representation of the copper circuit elements is not a bad approximation.
It may not be very difficult to write a small function that creates a conforming, rectangular, but not necessarily uniform hexahedral mesh in the epoxy layers. Here are some details of what I have in mind:
You start by constructing three lists of x, y, and z coordinate values. The list of z-values contains (at least) the z-coordinates of all circuit layers. The x and y lists contain the values of the appropriate center-line locations of each 1D circuit trace at all z-levels (I'm ignoring the case of 2D circuit regions for now). With these 3 lists, constructing a hexahedral mesh in the epoxy layers with a triply-nested loop is straightforward.
The next step is constructing the mesh of 1D circuit elements (again, I'm ignoring the case of 2D circuit elements for now). For each circuit, you need to be able to construct a data structure that I'm loosely calling a "netlist". By that I mean a list of the starting and ending points of each trace and whether it runs parallel to the x or y axis. The nodes corresponding to those end points were already defined in the first step. Finding them (their ids) is simply a matter of indexing into the x, y, and z lists and computing a global offset into the node list. Given the node ids, you can define one or more 1D elements for each trace. The process is repeated for every trace at every circuit level.
My proposed solution is based on the fact that creating good meshes directly from the geometry, when there are very thin layers, is quite difficult. Most general 3D meshers create tetrahedral elements which are undesirable not just in the very thin copper layers (as you've pointed out) but also in the fairly thin epoxy layers. Hexahedral elements are much better suited to thin layers but I don't know of any free/open-source hexahedral meshers for this class of problem.
If you want to look for existing meshing software, I think that meshing the copper conductor layers with one hex element through the thickness is a more straightforward approach. I think you are more likely to find meshers that can do this and that the computational disadvantages, compared with creating a 2D circuit mesh between the 3D regions, are minor.
If you want to consider commercial software, CoventorWare (http://www.coventor.com/) has a "Manhattan" hexahedral mesher that I think would be suitable for this application. (The term Manhattan comes from the fact that the element mesh is laid out on a rectangular grid.)