FastFieldSolvers Forum
FastFieldSolvers Forum
Home | Profile | Register | Active Topics | Members | Search | FAQ
 All Forums
 FastFieldSolvers
 FasterCap and FastCap2
 Overlapping panels in FasterCap

Note: You must be registered in order to post a reply.
To register, click here. Registration is FREE!

Screensize:
UserName:
Password:
Antispam question: What do MOONwalk and MOONdance have in common?
Answer:
Format Mode:
Format: BoldItalicizedUnderlineStrikethrough Align LeftCenteredAlign Right Horizontal Rule Insert HyperlinkInsert EmailInsert Image Insert CodeInsert QuoteInsert List
   
Message:

* HTML is OFF
* Forum Code is ON

 
   

T O P I C    R E V I E W
dhimel Posted - May 31 2013 : 15:54:24
I've built a model which contains overlapping conductor and dielectric panels. The models runs without a hitch in fastcap2, but will not run in fastercap (solution will not converge). The error message states that the problem is likely overlapping panels - is there a simple way to remedy this problem without rebuilding the entire geometry?

Thank You,
Denny
9   L A T E S T    R E P L I E S    (Newest First)
Enrico Posted - Mar 17 2015 : 18:25:32
To formally close the topic also on the forum, as we discussed via private email:

Yes we have something better, but however simple it is not functional yet. It is a whole workbench you can plug as an add-on to FreeCAD.
The improvement, besides that, is the capability to transforma the 3D dielectric bodies into shells, so they can be cut by the conductors in contact with the dielectric.

Enrico

an1985 Posted - Feb 27 2015 : 18:46:12
You sent an export_mesh.py containing 1 export_mesh function and 1 export_faces function sometime back. Do you have any updates on this?


#***************************************************************************
#*                                                                         *
#*   Copyright (c) 2014                                                    *  
#*   FastFieldSolvers S.R.L.  ht*p://w*w.fastfieldsolvers.com              *  
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU Lesser General Public License (LGPL)    *
#*   as published by the Free Software Foundation; either version 2 of     *
#*   the License, or (at your option) any later version.                   *
#*   for detail see the LICENCE text file.                                 *
#*                                                                         *
#*   This program is distributed in the hope that it will be useful,       *
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#*   GNU Library General Public License for more details.                  *
#*                                                                         *
#*   You should have received a copy of the GNU Library General Public     *
#*   License along with this program; if not, write to the Free Software   *
#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
#*   USA                                                                   *
#*                                                                         *
#***************************************************************************

import FreeCAD, Mesh, Part, MeshPart, DraftGeomUtils, os
from FreeCAD import Vector

if FreeCAD.GuiUp:
    import FreeCADGui
    from PySide import QtCore, QtGui
else:
    def translate(ctxt,txt):
        return txt

__title__="FreeCAD E.M. Mesh Macros"
__author__ = "FastFieldSolvers S.R.L."
__url__ = "ht*p://w*w.fastfieldsolvers.com"

DEF_FOLDER = "."

##
def export_mesh(filename, meshobj=None, isDiel=False, showNormals=False, folder=DEF_FOLDER):
    '''export mesh in FasterCap format as conductor or dielectric interface
    
    'filename' is the name of the export file
    'meshobj' must be a Mesh::Feature object
    'isDiel' specifies if the mesh is a dielectric, so the function will add 
        a reference point to each panel to indicate which is the external side (outside)
    'showNormals' will add a compound object composed by a set of arrows showing the 
        normal direction for each panel
    'folder' is the folder in which 'filename' will be saved
    
    Example:
    mymeshGui = Gui.ActiveDocument.Mesh
    mymeshObj = mymeshGui.Object
    export_mesh("mymesh.txt", meshobj=mymeshObj, folder="C:/temp")
'''
    # if no valid mesh was passed
    if meshobj == None:
        return
    elif meshobj.TypeId != "Mesh::Feature":
        FreeCAD.Console.PrintMessage("Error: 'meshobj' is not an object of type 'Mesh::Feature'")
        return
    
    if not os.path.isdir(folder):
        os.mkdir(folder)
        
    with open(folder + os.sep + filename, 'w') as fid:
        # write the preamble
        if isDiel == True:
            fid.write("0 dielectric definition file for mesh '" + meshobj.Label)
        else:
            fid.write("0 conductor definition file for mesh '" + meshobj.Label)
        fid.write("' created using FreeCAD's ElectroMagnetic workbench\n")
        fid.write("* see ht*p://w*w.freecad.org and ht*p://w*w.fastfieldsolvers.com\n")
        fid.write("\n")
        # export facets
        arrows = []
        condName = meshobj.Label.replace(" ","_")
        for facet in meshobj.Mesh.Facets:
            if len(facet.Points) == 3:
                fid.write("T " + condName)
            elif len(facet.Points) == 4:
                fid.write("Q " + condName)
            else:
                FreeCAD.Console.PrintMessage("Unforseen number of mesh facet points: " + len(facet.Points) + ", skipping facet")
                continue
            center = Vector(0.0, 0.0, 0.0)
            avgSideLen = 0.0
            for j, point in enumerate(facet.Points):
                fid.write(" ")
                for i in range(3):
                    fid.write(" " + str(point[i]))
                if isDiel == True or showNormals == True:
                    # 'point' is a tuple, transform in vector
                    center = center + Vector(point)
                    # get side length
                    side = Vector(facet.Points[(j+1)%3]) - Vector(point)
                    avgSideLen += side.Length
            if isDiel == True or showNormals == True:
                # calculate the reference point
                # (there should be a better way to divide a vector by a scalar..)
                center.multiply(1.0 / len(facet.Points) )
                # and now move along the normal, proportional to the average facet dimension
                scaledNormal = Vector(facet.Normal)
                scaledNormal.multiply(avgSideLen / len(facet.Points) )
                refpoint = center + scaledNormal
                if isDiel == True:
                    fid.write(" ")
                    for i in range(3):
                        fid.write(" " + str(refpoint[i]))           
            fid.write("\n")
            if showNormals == True:
                arrows.append(make_arrow(center, refpoint))
        
        if showNormals == True:
            # add the vector normals visualization to the view
            # Note: could also use Part.show(normals) but in this case we could
            # not give the (permanent) name to the object, only change the label afterwards
            normals = Part.makeCompound(arrows)
            normalobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Normals")
            normalobj.Shape = normals

    fid.closed
##
def make_arrow(startpoint, endpoint):
    '''create an arrow
    
    'startpoint' is a Vector specifying the start position
    'endpoint' is a Vector specifying the end position
'''

    line = Part.makeLine(startpoint, endpoint)
    # calculate arrow head base
    dir = endpoint - startpoint
    len = dir.Length
    base = dir
    base.normalize()
    base.multiply(len * 0.8)
    base = startpoint + base
    # radius2 is calculated for a fixed arrow head angle tan(15deg)=0.27
    cone = Part.makeCone(0.2 * len * 0.27, 0.0, 0.2 * len, base, dir, 360)
    
    # add the compound representing the arrow
    arrow = Part.makeCompound([line, cone])
    
    return arrow
##    
def export_faces(filename, isDiel=False, name="", showNormals=False, folder=DEF_FOLDER):
    '''export faces in FasterCap format as conductor or dielectric interface
    
    The function operates on the selection. The selection can be a face or a compound.
    'filename' is the name of the export file
    'isDiel' specifies if the mesh is a dielectric, so the function will add 
        a reference point to each panel to indicate which is the external side (outside)
    'name' is the name of the conductor created in the file. If not specified, defaults
        to the label of the first element in the selection set
    'showNormals' will add a compound object composed by a set of arrows showing the 
        normal direction for each panel
    'folder' is the folder in which 'filename' will be saved
    
    Example:
    export_faces("mymesh.txt", folder="C:/temp")
'''
    # get selection
    sel = FreeCADGui.Selection.getSelection()
    # if no valid mesh was passed
    if sel == None:
        return
    
    if name == "":
        condName = sel[0].Label.replace(" ","_")
    else:
        condName = name

    # scan objects in selection and extract all faces
    faces = []
    facets = []
    for obj in sel:
        if obj.TypeId == "Mesh::Feature":
            facets.extend(obj.Mesh.Facets)
        else:
            if obj.Shape.ShapeType == "Face":
                faces.append(obj.Shape)
            elif obj.Shape.ShapeType == "Compound":
                faces.extend(obj.Shape.Faces)
    # scan faces and find out which faces have more than 4 vertexes
    # TBD warning: should mesh also curve faces
    facesComplex = [x for x in faces if len(x.Vertexes) >= 5]
    facesSimple = [x for x in faces if len(x.Vertexes) < 5]
    # mesh complex faces
    doc = FreeCAD.ActiveDocument
    for face in facesComplex:
        mesh = doc.addObject("Mesh::Feature","Mesh")
        mesh.Mesh = MeshPart.meshFromShape(Shape=face, Fineness=0, SecondOrder=0, Optimize=1, AllowQuad=0)
        facets.extend(mesh.Mesh.Facets)
    # now we have faces and facets. Uniform all
    panels = []
    for face in facesSimple:
        sortEdges = DraftGeomUtils.sortEdges(face.Edges)
        # Point of a Vertex is a Vector, as well as Face.normalAt()
        points = [x.Vertexes[0].Point for x in sortEdges]
        panels.append( [points, face.normalAt(0,0)] )
    for facet in facets:
        points = [ Vector(x) for x in facet.Points]
        panels.append( [points, Vector(facet.Normal)] )
        
    if not os.path.isdir(folder):
        os.mkdir(folder)
        
    with open(folder + os.sep + filename, 'w') as fid:
        # write the preamble
        if isDiel == True:
            fid.write("0 dielectric definition file for the following objects\n")
        else:
            fid.write("0 conductor definition file for the following objects\n")
        for obj in sel:
            fid.write("* - " + obj.Label + "\n")
        fid.write("* created using FreeCAD's ElectroMagnetic workbench\n")
        fid.write("* see ht*p://w*w.freecad.org and ht*p://w*w.fastfieldsolvers.com\n\n")
    
        arrows = []
        # export faces
        for panel in panels:
            pointsNum = len(panel[0])
            if pointsNum == 3:
                fid.write("T " + condName)
            elif pointsNum == 4:
                fid.write("Q " + condName)
            else:
                FreeCAD.Console.PrintMessage("Unforseen number of panel vertexes: " + pointsNum + ", skipping panel")
                continue
            center = Vector(0.0, 0.0, 0.0)
            avgSideLen = 0.0
            for j, vertex in enumerate(panel[0]):
                fid.write(" ")
                for i in range(3):
                    fid.write(" " + str(vertex[i]))
                if isDiel == True or showNormals == True:
                    # 'point' is a tuple, transform in vector
                    center = center + vertex
                    # get side length
                    side = panel[0][(j+1)%3] - vertex
                    avgSideLen += side.Length
            if isDiel == True or showNormals == True:
                # calculate the reference point
                # (there should be a better way to divide a vector by a scalar..)
                center.multiply(1.0 / pointsNum )
                # and now move along the normal, proportional to the average facet dimension
                scaledNormal = panel[1]
                scaledNormal.multiply(avgSideLen / pointsNum )
                refpoint = center + scaledNormal
                if isDiel == True:
                    fid.write(" ")
                    for i in range(3):
                        fid.write(" " + str(refpoint[i]))           
            fid.write("\n")
            if showNormals == True:
                arrows.append(make_arrow(center, refpoint))
        
    fid.closed
    
    if showNormals == True:
        # add the vector normals visualization to the view
        # Note: could also use Part.show(normals) but in this case we could
        # not give the (permanent) name to the object, only change the label afterwards
        normals = Part.makeCompound(arrows)
        normalobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Normals")
        normalobj.Shape = normals



AJ
Enrico Posted - Feb 26 2015 : 20:06:00
You should create a dielectric interface wherever two different dielectric mediums touch.

Actually creating such a geometry manually is cumbersome, I agree with you, but using any modeling CAD application you can script eases the task a lot.

As I said in other posts, we are working on a simple interface over FreeCAD, which is a powerful and completely open-source and free multi-platform CAD. I can provide you the raw scripts to perform the export, if you are interested.

Best Regards,
Enrico
an1985 Posted - Feb 24 2015 : 20:54:21
Hi Enrico,
I have quick followup question on the same topic.

In your white paper parallel plate example, all the parallel plates and the dielectric length and width are equal. Lets suppose instead you have a '+' like top and bottom conductor parallel plate formation. For instance as follows:

Conductor 1 (lxwxh or x,y,z) = 0.5 x 1 x 0.2 [xoffset: 0.25]
Conductor 2 (lxwxh or x,y,z) = 1 x 0.5 x 0.2 [yoffset: 0.25]

And lets suppose that in between the conductors lies a dielectric layer same as the one in your whitepaper.

Dielectric 1 (x,y,z) = 1 x 1 x 0.6

Can I get away with (and still get relatively accurate capacitance) modeling the dielectric interface between the two plates as a simple 1x1x0.6 and bounding the dielectric only in the sides like in the whitepaper?
Or do I have to create a top and bottom boundary that fills the gap where there is no conductor present (this process would get really tedious if there are multiple stripped i.e. '++++' pattern) ?



Regards,
AJ
dhimel Posted - Jun 11 2013 : 19:30:37
Great - thank you! I am finding the white paper to be very helpful.
Enrico Posted - Jun 11 2013 : 18:19:30
You can download the white paper I was speaking of from the 'literature' page.

The title is "The Treatment of Dielectrics in FasterCap"

Best Regards,
Enrico
Enrico Posted - Jun 05 2013 : 23:58:48
I am writing a paper on this topic that we'll publish in the 'literature' page.

To answer your specific question, unless the conductor is really, really thin (and therefore would require a B model), you can model it as a thin box, with a different dielectric constant on each side / group of sides.

You can check the sample file 'capacitor.lst'. Even if this conductor is not thin, you can leverage the structure of the file to define your own conductor.

If too thin, and you are getting convergence problems, you can tune the parameters lowering the -d value and selecting -g to use the Galerkin solution scheme.

Best Regards,
Enrico

dhimel Posted - May 31 2013 : 19:47:17
Thank you for the helpful response.

So the lst files allow the user to specify the dielectric constant of the surrounding medium for a conductor. If you have a situation where there are different dielectrics surrounding a conductor, e.g. a thin box with a different dielectric medium on either side, how would you specify this when building up your model?

Thank You,
Denny
Enrico Posted - May 31 2013 : 16:33:10
The point is, you should never overlap a conductor and a dielectric panel. If your goal is to model a conductor at the interface between two different materials, and you want to do it with a conductor with no thickness, you should need another element model (what is called in FastCap2 User's Guide 'B', instead of 'D' or 'C'); but this is not implemented so far.
As a matter of fact, real conductors always have a finite thickness, so in most cases you can model a thin box, with one permittivity on one side and another permittivity on the other.
Take care that even if FastCap2 is not complaining about the input file and giving you a result, it cannot be trusted to be in line with your expectations.

Best Regards,
Enrico

FastFieldSolvers Forum © 2020 FastFieldSolvers S.R.L. Go To Top Of Page
Powered By: Snitz Forums 2000 Version 3.4.06