thliebig / CSXCAD

A C++ library to describe geometrical objects and their physical or non-physical properties.
http://openEMS.de
GNU Lesser General Public License v3.0
31 stars 35 forks source link

Understanding how primitives are picked up by mesh lines #31

Open 0xCoto opened 1 year ago

0xCoto commented 1 year ago

Hi Thorsten, this is more of a question rather than a technical issue/bug, but since the forum is down at the moment, I thought I'd ask here (sorry for the long question - thought I'd try to be as thorough as possible 🙂):

I'm having a hard time understanding how openEMS "detects" shapes. Specifically, I'm only working with STLs that realistically represent the actual geometry model. E.g. a microstrip patch antenna will have a patch and ground plane microstrip thickness of 35 μm instead of being flat faces, and it is the goal of my mesh-generation algorithm to figure out precisely where to sample each mesh line.

While I've made quite a bit of progress on my automatic mesh-generation algorithm (which I'm hoping to contribute with), I've reached a point where I'm having a hard time understanding where certain mesh lines have to be placed on the model so that openEMS does not spit out Warning: Unused primitive detected in property: ... (which appears to be derived from here).

Here's an example: let's say you're given a realistic model of a patch antenna (where all objects are 3D volumes; no 2D surfaces). Where exactly on the model must you place lines, so that all 3 shapes (patch, substrate and ground plane) are properly detected?

image

One solution would obviously sample a line on the edge of every shape (with possibly a few more lines on the substrate to sample its thickness). However, that would imply that you end up with extremely narrow cells for the PEC thickness (patch and ground plane), yielding a tiny timestep.

What I've observed that typically works is sampling a single line right in the middle of ~35 μm microstrip traces, like so: image

But this creates a few minor problems when it comes to algorithmically handling this detection and midpoint resampling (though I've already partially achieved this). Other times, sampling a single line at the edge of a trace also works, but not always, and it is unclear to me when a primitive becomes "unused" due to poor line sampling. Could you please comment on how CSXCAD/openEMS handles that?

Other proprietary software (like CST in this case) appear to handle such cases by only sampling one edge of thin PEC traces (which is easier in terms of automatic mesh generation, but it's unclear how their "CSXCAD"-equivalent geometry engine handles the representation of thin traces): image

I think something that might be useful is for openEMS to look at the content of a cell (not just the edge/line), and determine what material it should be set to. That way (unless you've set the priority of the primitive low enough to be dominated by another primitive), you would never see primitives become "unused", as there would always be cells occupying that particular material.

One idea I haven't tried is to fill up the entire model with a dummy material representing air/vacuum (ε_r = 1) and set a low priority, so that the metals and dielectrics would be above in priority, and thus detected? Any idea if this idea is sensible at all?

I've also had a similar issue where the ridges of a horn antenna model were thin, and the mesh could only pick it up in certain spots (not yielding an Unusued primitive error):

e_field

But once I made the ridge thicker, it was properly picked up by the mesh:

e_field-1

Many thanks again for your time - really really appreciate it!

thliebig commented 1 year ago

Yes that the forum is down is a real big issue and I have no idea if it will ever return or the university will just scrap everything after the hacker attack... I'm thinking to maybe give the github discussions a test...

As for your question: It is very valid and I can see how this is giving you trouble to understand. The answer will not be easy because it is deeply linked to the FDTD algorithm itself.

First of, using only surface (STL) objects is not a really good idea because of how this all works ;) I really have to write this maybe down in the new rst documentation. But the short answer for now is. For metals (e.g. PEC), at the coordinates of the middle of the edges is probed for which material can be found there. And for your STL surfaces this gets numerical unstable very quickly. Boxes are much more reliable here. And if a box is rotated to result in a closed surface is not easy again. openEMS really needs a new feature in the future to reliably map metal surfaces onto the grid... So to slightly oversize your surface (with a fixed mesh) should work fine until then ;)

0xCoto commented 1 year ago

Thanks for the reply! Let me address a few things I didn't quite understand:

First of, using only surface (STL) objects is not a really good idea because of how this all works ;)

Are you saying that the nature of the STL format (representing surface meshes) is a "hacky" way of importing external CAD files (my understanding is that openEMS "converts" these surfaces to represent 3D volumes)? I've found that as long as the mesh is OK, I've found no problems with STLs at all. I've tried microtstrip designs, reflectors, dipoles and horns, and I've seen no problem with STLs if the mesh is right, so that's what I'm trying to figure out. The reason I've been going with STLs is the ease of importing designs from other CAD tools, rather than using scripting to build a complex model.

For metals (e.g. PEC), at the coordinates of the middle of the edges is probed for which material can be found there.

Sorry, could you expand on this a bit? What is meant by "at the coordinates of the middle of the edges" exactly, and is the behavior different for non-metal materials? Are you saying that because e.g. this circular wire does not cross the midpoint of an edges of any cell, it will not be picked up at all?

image

So to slightly oversize your surface (with a fixed mesh) should work fine until then

Wouldn't it make more sense for the mesher/solver to interpret the geometry like this, instead of expecting a material to be at just the right position on a mesh cell?

image

If this does indeed sound reasonable but would be tricky to do it in the openEMS code, I could probably craft a CAD pre-processor that takes the STL and FDTD grid (XY, YZ and XZ lists), and produces a "pixelated" blocky version, e.g. something like image resizing/pixelization: image

thliebig commented 1 year ago

No it would pick up all blue dots that ate inside the STL and make these edges like a metal... What you can use is the flag --debug-PEC. It will create a vtk file that you can load into paraview and can really see all the edges that where set to be metal...

And yes with (large) volumetric surface objects all is good. But if you e.g. have really thin sheets, then you might get into trouble that no edge centers are inside or at least not enough to form an EM tight metal surface...

Yes unfortunate dielectrics are handled different once again, but usually are less of a problem because a very thin dielectric does not make much sense in the first place. So for these as well having rather bulky materials is a good idea...

0xCoto commented 1 year ago

No it would pick up all blue dots that ate inside the STL and make these edges like a metal...

Right, if I understand correctly that's basically what I described above. For example, the model I sent could represent a circular thin wire loop antenna (like this): image

and if the blue dots are not inside the metal, then it won't be picked up properly (if it is even picked up at all...)

What you can use is the flag --debug-PEC

Never actually tried this but will take a look, thanks!

But if you e.g. have really thin sheets, then you might get into trouble that no edge centers are inside

This makes sense, but I've got a few questions: 1) Let's say you have a simple STL cube (no rotations etc., so the cube's edges are parallel to the XYZ axes). If the blue dot is inside the cube, it will be picked up. If it is outside, it will not be picked up. But happens if the blue dot is exactly at the edge of the cube? Would it be picked up, or not? I have experimentally observed that on "50-50" cases, it might depend on whether the primitive is "above" or "below" (in terms of ≥ or ≤ on the X, Y or Z axis), relative to the blue dot. I'm not 100% sure though.

2) I guess this is more of an FDTD question, but what exactly happens here in terms of the microstrips and the dielectric? Does this translate to the PCB trace having a height of 35 μm 0 mm (2D surface), or a height equal to the mesh cell size? And what happens to the thickness of the dielectric? I should probably try --debug-PEC for this (at least for the microstrip metals) as you suggested... image

Edit: Tried debug-PEC, looks like it's represented as 2D surfaces indeed (which seems reasonable): image

3) Any idea if the "pixelization" idea I mentioned earlier make sense to tackle the problem? In other words, it would convert metals that are inside mesh cells (that don't happen to cross through the blue dots), into larger blocks (where each block has the dimensions of the associated mesh cell), so that even if the metal is super thin, it would still be picked up.

Yes unfortunate dielectrics are handled different once again, but usually are less of a problem because a very thin dielectric does not make much sense in the first place. So for these as well having rather bulky materials is a good idea...

This makes sense, but just to make sure my meshing algorithm is robust, could you perhaps very very briefly describe how non-metals are picked up? Is it a completely different/more complicated process than the edge midpoints (blue dots) for metals?

thliebig commented 1 year ago

You ask so many (important!) stuff at once... I hope I can keep up, just re-ask if I don't ;) Giving it numbers helps!

1) Unfortunately it is indeed a bit unclear what happens if a blue dot (aka center of an edge aka location of the electric fields in the FDTD algorithm) hits the surface. What CSXCAD's function IsInside does is to shoot a ray from the point and check if the surface is hit an odd number of times... So if it is more or less exactly on the surface? I have no idea... I guess it will depend on some (random?) float comparisons... Better so avoid of possible?

2) If in a 2D Planes say all x- and y-egdes are set to E=0 (--> PEC) does that mean it has zero thickness... No I guess it is more like half a cell up and down maybe? But it is really not so easy to answer, because the E-Field in z-direction is unaffected... but the edge effects are present as if it would have some thickness... My observation is.. it does not have much of an influence and you should never try to resolve the 35um as this will destroy the timestep and thus simulation time...

3) I'm not sure if this really helps. For your loop antenna it would really be better if you would use the 1D curve object, as it will be mapped as a uninterrupted curve of PEC edges. Unless of course the thickness really matters for you, but in this case the mesh would need to be much smaller than the radius and then the edge inside would work good enough again?

As for dielectrics... It is probed with the same IsInside function but at different locations inside the voxel (cube created by the mesh line edges). Thus this usually is much less of an issue...

0xCoto commented 1 year ago

Regarding (3), my main limitation is that I'm essentially only dealing with externally imported CAD files (STLs), and so to keep things as simple as possible (i.e. as long as you have a model of what the geometry looks like "in real life" as accurately as possible, meaning everything is a 3D shape), I'm hoping to make the mesh generation algorithm suitable for such realistic models...

I guess it's partially a UX problem rather than a physical limitation, but that's the reason I wouldn't like to use 1D and 2D shapes, but would rather hope to adapt my mesher to arbitrary 3D shapes (I'm already very close!) :)

As for the mesh resolution... Well, let's say the diameter of the wire is around 3 mm. I think a mesh length of about 1 mm ensures that the wire is covered by 2-3 mesh cells, and this is pretty reasonable considering that's roughly the mesh resolution you'd expect to see on a typical microstrip line...

Guess I'll have to look at some image processing algorithms to figure out the best way to carry out this "pixelization" technique :grin:

thliebig commented 1 year ago

Well that is a very impressive list... Let's see how that all goes... I must say for me the strength of openEMS always was that you actually can model everything by using openEMS like a programming language and not having to do all this using any kind of GUI that only limits you in what you can do... my biggest projects really at the end were huge collections of functions and very flexible and powerful design tool for the antennas I was designing... Sometimes "simple creation" or "easy to use" just means you can do it only in a very limited way and not how you just now happen to need... But of course not everyone prefers this way and ideally one can have both worlds...

I was thinking of re-implementing AppCSXCAD in pure python using the CSXCAD and openEMS python modules in combination with PyQt/PySide and vtk etc. But I'm still pondering about it. Doing a proper/better auto-mesher was on my list too, but more based on the CSXCAD internal primitives as they of course have much more information about their shape and features...

As for AVX-2: Maybe someday I will have a look into it, but unfortunately I do not expect much speedup. The engine is already 100% memory bandwidth bottle necked, faster computation does not help here much... I think there are better ways to reduce numerical overhead, we will see... I think somebody already experimented with CUDA, but again it suffers from the same problem (memory vs computing). A GPU has faster memory too, but no cache to speak of and more nasty transfers from main memory to GPU memory... Calculating digits of pi or sha256 hashes may be perfect for GPU's. FDTD absolutely is not unfortunately...