2

I'm trying to get the normal of every face in a surface (EDIT: the surface is extracted from a solid, not a shell). I can't seem to get the face objects though. According to the scripting reference guide this should be the syntax:

mdb.models[name].rootAssembly.instances[name].surfaces[name].faces[i]

I tried this:

femur_instance.surfaces['IMPLANT_SHAFT'].faces[0]

but when trying to get the normal using pointOn[1] attribute it gave me an attribute error. When I look at the attributes I get this:

['__class__', '__copy__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getstate__', '__hash__', '__init__', '__lt__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_addToCache', '_cache', '_counter', '_id', '_p', '_scdId', 'getId', 'getText', 'name']

the type of the returned object is: 'symbolicConstant'

What am I doing wrong?

EDIT: femur_instance was defined as, odb.rootAssembly.instances['FEMUR_SHAFT_1'] which caused the error, see answer.

ThaNoob
  • 520
  • 7
  • 23
  • Is this a face of a shell? According to the docs, then `(...).faces[0].pointOn[1]` should return a tuple representing the normal at the 1st face. Are you saying that this is not the case? If it is a solid, then that's different. – Matt P Apr 05 '18 at 15:13
  • I don't really know the definition of a shell, it's a face of a part though. This is the full line of code: `odb.rootAssembly.instances['FEMUR_SHAFT_1'].surfaces['IMPLANT_SHAFT'].faces[0]` So indeed, it is not returning the normal of the first face. It is returning a 'symbolicConstant' object. – ThaNoob Apr 05 '18 at 16:11
  • You probably ought to know what a solid and a shell are. I don't explain it in my answer, but I do try to point you in a direction so you can look into it. – Matt P Apr 05 '18 at 19:52
  • I believe right now that a solid is a volume mesh and a shell is a surface mesh, is that correct? – ThaNoob Apr 06 '18 at 07:56

1 Answers1

1

You are referring to two different objects in your post and in your comment. One is a Face object in the mdb, the other is an OdbSet object in the odb. Although they are similarly named, they do not have the same meaning, attributes, or methods. This is the source of the error message you mention.

For example, in your original post you are referencing the geometric Face object in the mdb. For example:

`f = mdb.rootAssembly.instances[name].surfaces[name].faces[N]` 

where N references the specific Face object in the faces array and we are assigning it to the variable f. Now, f has a handful of "members" or attributes. One of the them is f.pointOn. See how to use this below.

However, in your comments, you refer to the OdbSet object. For example:

`g = odb.rootAssembly.instances[name].surfaces[name].faces[N]`

In this case, faces is a tuple of symbolic constants that specify the element face on the geometric face. It seems you are trying to use g, but you actually should be using the mdb Face object f.


Using the mdb Face object: If your part is a solid (meshed using continuum elements such as CPS4 in 2D or C3D8 in 3D), then:

((x,y,z),) = f.pointOn

The pointOn member is a tuple of tuples of floats. There is actually only one inner tuple, and it contains the coordinates of a point on the face.

If your part is a shell (meshed using shell elements such as S4), then you will instead get:

((x,y,z),(a,b,c)) = f.pointOn

which is again, a tuple of tuples of floats. There are two inner tuples. The first contains the coordinates of a point on the face, and the second contains the components of the normal to the face in the global coordinate system.

I have the feeling that your part is a solid, however, so this technique will not return the normal to the surface.

Matt P
  • 2,287
  • 1
  • 11
  • 26
  • Allright, I think I get it. This way of getting the face normal only works if you have a shell, which actually is an empty hull (a surface mesh and not a volume mesh). In my case it is indeed a solid according to this definition. Although I don't really get why they make the distinction since we're working on a surface of that solid. Still there is something odd. Because this line of code: `print(odb.rootAssembly.instances['FEMUR_SHAFT_1'].surfaces['IMPLANT_SHAFT'].faces[0].pointOn)`returns an attribute error. According to your answer it shouldn't. – ThaNoob Apr 06 '18 at 07:55
  • No, you're still mixing up the odb and mdb objects. So, actually according to my answer the odb object returns a symbolic constant, which doesn't have the pointOn member, and that's why you get an attribute error. – Matt P Apr 06 '18 at 09:18
  • Oh damn, so stupid. I get it now. I've been working for a while with the Odb so I just overlooked the 'M' at the beginning. Is it possible that in your answer the first example should be `f=mdb.rootAssembly.instances[name].surfaces[name].faces[N]` instead of odb? – ThaNoob Apr 06 '18 at 09:56