opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
790 stars 317 forks source link

Issues with Integrating Frames into Model #153

Closed aymanhab closed 8 years ago

aymanhab commented 10 years ago
  1. When to create BodyFrame(s) for all Bodies in the model?
    • Can't rely on deserialization since Bodies can be added programmatically. -> Should serialization call addBody so there's only one path to modify/test/maintain in the code?
    • How to handle Body renames (connection of BodyFrame to Body is thru a body connector that references a body by name, keeping the name in multiple places can lead to inconsistency.
  2. How to Handle Body removal/deletions (can we get a list of all objects connected to Body, so as to signal them as "disconnected")? how to get a list of all downstream objects (recursively)
chrisdembia commented 10 years ago

How to handle Body renames (connection of BodyFrame to Body is thru a body connector that references a body by name, keeping the name in multiple places can lead to inconsistency.

If there is a body "A" and a body "B", the user might want to rename "A" to be "B", and might do so as follows: B.setName("B-old"), A.setName("B"). They might want all the connections to the original "B" to now be to the new "B" (old "A"), in which case they wouldn't want automatic rewiring. Maybe they could get a message when they set the name that there are connections that will now be broken?

aymanhab commented 10 years ago

@sherm1 A default-constructed Body should already have a Frame

Agreed but it's not clear if it'd be a subcomponent or not and also not clear if there's a single place/function shared or invoked by all constructors of Body(). Name is also important, will the name be just "Frame" and disambiguated using the full name (e.g. r_pelvis/Frame) or embedded as r_pelvisFrame?, does either require subcomponents? Should references use the full qualified name or relative name? Your thoughts @aseth1 and @msdemers

aseth1 commented 10 years ago

Thinking about it more, I am not sure a Body should contain a Frame? A body is already acting like a Frame since a Frame has to be associated with a Frame as in BodyFrame (where the body serves as the reference frame). Maybe all that is needed is that Body implements a getBodyFrame() when a Frame is needed to connect Geometry or whatever else. We teach people that at the most fundamental level all a Body is is a Frame. If a Body provides a getTransform and getGroundTransform, then isn't it a Frame? Why not make Body derive from Frame and get rid of BodyFrame? It seems to make the semantics better too. We do want a Joint to connect two Bodies and for the Joint to own the joint Frames that are relative to the Body (Frame). I generally vote for a has-a versus an is-a, but in this case it seems justified that a Body is a Frame. Then Geometry can refer to just Frames and Bodies aren't anything special to deal with.

msdemers commented 10 years ago

@chrisdembia This is an interesting idea, but it seems hard to predict which "convenience" the users will want. Also, when building models programatically, the users may connect ModelComponents to Frame objects directly, or they may connect by frame name. I can imagine both types of cases: one where I want the model component to stay associated with the same Frame object, and one where I want the name association to matter. Begs the question, should we limit the way you connect to frames? Should you only be able to connect to a frame by calling it's name, or can you point directly at it by reference to its instance? @aymanhab @sherm1 @aseth1

aymanhab commented 10 years ago

@msdemers the only way any connections can be made persistent is through names. Unfortunately we have no way as far as I can tell to enforce the presence of names or their uniqueness.

msdemers commented 10 years ago

@aymanhab Good point, and this tells me that Body renaming/removing/deleting is not a "Frame issue". This is a general problem we will encounter with all model components and all connectors once we support interactive model creation/editing. Any name change or deletion can break Connectors. I think this will require a general consensus and solution outside the scope of frames.

aseth1 commented 10 years ago

How to Handle Body removal/deletions (can we get a list of all objects connected to Body, so as to signal them as "disconnected")? how to get a list of all downstream objects (recursively)

Not yet. You can get a list of connectors and the ones that are not connected. If you have a list of Frames that require a particular Body (to be connected to) and the connection cannot be resolved then you will have unconnected Frames. We aren't doing anything with these Connectors yet, but my thought was that 1) you can identify Components with unresolved connectors and 2) you can query them about what they were supposed to connect to. Why is that not sufficient?

I don't think of connections as upstream or down stream they are either made or not and we have a mechanism to retrieve that information.

I think it is another issue how best to present unresolved connections to the user. Definitely worth discussing.

msdemers commented 10 years ago

@aseth1 We've already had this "Frame is a Body is a Frame, Not its not...Yes it is." discussion multiple times. Ultimately, it's obvious that Frames and Bodies are not the same thing because we invented a Frame Class to serve a different purpose.

BodyFrame should be there as soon as a body is made. A body already has an implicit frame, and we measure things by transformations away from that frame already! We even draw it on our diagrams of bodies and mobilizers! We just don't let anyone do anything useful with it, or call it by name. That should change as soon as possible.

If someone is attaching a muscle, joint, etc to a model, it doesn't matter to them if its a BodyFrame, FixedFrame, or any other type we invent. If they are attaching to a Station, it should matter which frame the station is connected to. They shouldn't have to worry about it.

aymanhab commented 10 years ago

@aseth1 A good example of Upstream/downstream from my perspective is when a BodyFrame used to attach a Body Outboard of a Joint can't be satisfied, then the Joint itself is invalid and all Coordinates/etc. that depend on the Joint can't be evaluated either. Is this an incorrect mental picture?

Is there an API call to get the list of connectors, their types and to check if they have been satisfied?

sherm1 commented 10 years ago

If a Body provides a getTransform and getGroundTransform, then isn't it a Frame? Why not make Body derive from Frame and get rid of BodyFrame?

I like that idea since it really is true that a body is a frame, plus additional stuff. I'm not sure whether it would work in the class heirarchy though but it sounds right. An odd thing about it would be that Frame::getTransform() would always return an identity transform if the frame were a body. But maybe that's reasonable?

aseth1 commented 10 years ago

@aymanhab Good point, and this tells me that Body renaming/removing/deleting is not a "Frame issue". This is a general problem we will encounter with all model components and all connectors once we support interactive model creation/editing. Any name change or deletion can break Connectors. I think this will require a general consensus and solution outside the scope of frames.

Names are how Connectors resolve their connections. I am open to suggestions on how else to do this. Once a connection is made all internal communication is with the object and the name is not used. So technically connections are not broken by renaming them once they are connected, at least not yet. But why would you rename once the model is connected and the system in created?

I am not convinced unique IDs make things any better/easier. If you rename you simply are saying the ID based connection is stronger than the name based. For all the talk about uniqueness of names I have not run or been presented with one use case where this is a problem or presents a foreseeable problem. Are you thinking of a generic leg and making a copy to make two legged model. Would you not expect to have a left and right hip? You could not connect the leg with doing other operations like mirroring and changing the location of the base joint so why not give the joint a new name? I don't think that is a big usability issue. For the most part, name, type and parent name of component makes for some pretty unique keys.

msdemers commented 10 years ago

@aseth1 Think of it this way. When you built the Body interface, you had a frame in mind. Users define masses and inertias at a different frame which they define. Users attached geometry at a different frame that they define.

aseth1 commented 10 years ago

I like that idea since it really is true that a body is a frame, plus additional stuff. I'm not sure whether it would work in the class heirarchy though but it sounds right. An odd thing about it would be that Frame::getTransform() would always return an identity transform if the frame were a body. But maybe that's reasonable?

BodyFrame already does that AFAIK.

msdemers commented 10 years ago

@sherm1 That's exactly how BodyFrame behaves now.

sherm1 commented 10 years ago

I think we discussed at the meeting earlier using the Body name as the BodyFrame name. That would happen naturally if a Body isA Frame. Just sayin' ...

msdemers commented 10 years ago

I like that. A RigidBody is a specific type of Frame. A Frame with inertia and mobilizer.

aymanhab commented 10 years ago

Well, with the added quirk that a BodyFrame has a connector to a Body, if a Body becomes a Frame it wouldn't need that but making a Body into a Frame means that it needs to implement all the methods in Frame.h (5 methods which seems a bit asking the Body to do too much) and also may have downstream side-effects (e.g. when you search for a Frame to connect to you need to search a mix of Bodies, BodyFrame(s) and FixedFrame(s))

aseth1 commented 10 years ago

Think of it this way. When you built the Body interface, you had a frame in mind. Users define masses and inertias at a different frame which they define. Users attached geometry at a different frame that they define.

I totally agree with what you are saying. Depending on the topology that the user defines the Body/BodyFrame has a completely different meaning. Whether it is the hip center, the origin of your bone scanned geometry, whatever, it represents the base reference for everything else you want to attach to the Body. The Body itself is a Frame. The fact that you can connect other Frames to it means that it is a Frame. I love the idea of adding other meaningful frames to capture attachments, landmarks, and other regions of interest too. I must have been absent on the raging debate if Body is or isn't a Frame. It most certainly is! It also happens to make the API semantics a lot cleaner too.

aseth1 commented 10 years ago

Well, with the added quirk that a BodyFrame has a connector to a Body, if a Body becomes a Frame it wouldn't need that but making a Body into a Frame means that it needs to implement all the methods in Frame.h (5 methods which seems a bit asking the Body to do too much) and also may have downstream side-effects (e.g. when you search for a Frame to connect to you need to search a mix of Bodies, BodyFrame(s) and FixedFrame(s))

If Body is a Frame why would you need BodyFrame any more. You would only see Bodies and FixedFrames. The tranfsormation/expression operations of the Frame make perfect sense (to me) on Body as well.

msdemers commented 10 years ago

A rigid body certainly looks like a frame which makes for a nice convenience. A Deformable body clearly is not a frame. I guess my time in FEA/continuum corrupted my soul. It's charred and dead... and argumentative! LOL

aymanhab commented 10 years ago

@sherm1 @aseth1 @msdemers @chrisdembia So, do we have an agreement to try change BodyFrame so that it doesn't connect to a "Body" but rather to serve as a base class of Body? It seems reasonable but will need to see how it works in our class hierarchy and serialization scheme.

chrisdembia commented 10 years ago

I think so; it seems like an elegant way to deal with:

When to create BodyFrame(s) for all Bodies in the model?

sherm1 commented 10 years ago

A rigid body certainly looks like a frame which makes for a nice convenience. A Deformable body clearly is not a frame. I guess my time in FEA/continuum corrupted my soul. It's charred and dead... and argumentative! LOL

Sorry about your soul, Matt! You're totally right that body==frame is only true in rigid body world. But even in flexible-body multibody dynamics, the deformations are usually (I think) expressed as offsets from an associated rigid frame (to keep the deformations small). So this concept probably would work for us even if we added flexible bodies.

msdemers commented 10 years ago

In deformable world, mass and strain are distributed between nodes/frames. They can be distributed as nonlinear functions between frames, linear function between frames, or as discrete things attached to frames. The last one would probably be the flexible-body multibody dynamics you're talking about, and the body=frame simplification would hold! Oh god I hope we're not planning to do that any time soon. :P

chrisdembia commented 10 years ago

Oh god I hope we're not planning to do that any time soon. :P

"Feature Requests" milestone!

aymanhab commented 8 years ago

Any reason why not to close this one, @aseth1 ?

aseth1 commented 8 years ago

Any reason why not to close this one,

Nope. Closing!