IMP logo
IMP Reference Guide  2.13.0
The Integrative Modeling Platform
KinematicForest.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kinematics/KinematicForest.h
3  * \brief Define and manipulate a kinematic structure over a model.
4  * \authors Dina Schneidman, Barak Raveh
5  *
6  * Copyright 2007-2020 IMP Inventors. All rights reserved.
7  */
8 
9 #ifndef IMPKINEMATICS_KINEMATIC_FOREST_H
10 #define IMPKINEMATICS_KINEMATIC_FOREST_H
11 
12 #include "kinematics_config.h"
13 #include <IMP/Model.h>
15 #include <IMP/kinematics/Joint.h>
17 #include <IMP/Object.h>
18 #include <IMP/Decorator.h>
19 #include <boost/unordered_set.hpp>
20 #include <IMP/exception.h>
21 #include <IMP/Object.h>
22 #include <IMP/check_macros.h>
23 #include <IMP/warning_macros.h>
24 #include <IMP/atom/Hierarchy.h>
25 #include <queue>
26 #include <algorithm>
27 
28 IMPKINEMATICS_BEGIN_NAMESPACE
29 
30 //! Define and manipulate a kinematic structure over a model.
31 /** The kinematic structure is defined as a
32  forest over model particles at a certain hierarchy, such that a
33  directed edge indicates the propagation of changes in internal
34  coordinates (joint values) to values of external (Cartesian)
35  coordinates.
36 
37  \see Joint
38  */
39 class IMPKINEMATICSEXPORT KinematicForest
40  : public Object // or ModelObject?
41  {
42  public:
44 
46 
47  // TODO: think about what foldtree scheme to use (star?),
48  /**
49  Builds a kinematic forest automatically from a hierarchy that
50  contains rigid bodies and adds a ScoreState to the model, to
51  make sure the internal and external coordinates are synced
52  before model updating
53  */
55 
56  /**
57  Adds a kinematic edge between parent and child,
58  using a TransformationJoint between them, and
59  decorating them as KinematicNodes if needed.
60  */
61  // NOTE: must have root on first call
62  // TODO: verify parent_rb is in tree
64  // create joint and associate it with parent and child
65  IMP_NEW(TransformationJoint, joint, (parent, child));
66  add_edge(joint);
67  return joint;
68  }
69 
70  /**
71  Adds a kinematic edge between the joint parent and child
72  rigid bodies, decorating them as KinematicNodes if needed.
73  The joint becomes owned by this KinematicForest, such that
74  changes to the joint are synchronized with the KinematicForest
75 
76  @note it is assumed that neither the joint or the rigid bodies in it
77  were previously added to a kinematic forest (might change in
78  future IMP versions)
79  */
80  void add_edge(Joint* joint);
81 
82  /**
83  adds edges between each pair of consecutive rigid bodies in the list
84  rbs, using default TransformationJoint joints (transforming from one
85  rigid body to the next)
86 
87  @param rbs list of n consecutive rigid bodies
88  */
90  for (int i = 0; i < (int)rbs.size() - 1; i++) {
91  add_edge(rbs[i], rbs[i + 1]);
92  }
93  }
94 
95  //! rebuild tree (same topology but change directionality)
96  void reset_root(IMP::Particle* new_root) {
97  // TODO: implement
99  IMP_UNUSED(new_root);
100  }
101 
102  //! updated internal coordinates in the forest based on the current cartesian
103  //! coordinates and the architechture of joints in the tree
105  IMP_LOG(VERBOSE, "updating internal coords needed?" << std::endl);
106  if (is_internal_coords_updated_) {
107  return;
108  }
109  IMP_LOG(VERBOSE, "updating!" << std::endl);
110  for (unsigned int i = 0; i < joints_.size(); i++) {
111  joints_[i]->update_joint_from_cartesian_witnesses();
112  }
113  is_internal_coords_updated_ = true;
114  }
115 
116  //! update all external coordinates of particles in the forest
117  //! based on their internal coordinates
119  if (is_external_coords_updated_) {
120  return;
121  }
122  // tree BFS traversal from roots
123  std::queue<KinematicNode> q;
124  boost::unordered_set<KinematicNode>::iterator it;
125  for (it = roots_.begin(); it != roots_.end(); it++) {
126  q.push(*it);
127  }
128  while (!q.empty()) {
129  KinematicNode n = q.front();
130  q.pop();
131  JointsTemp out_joints = n.get_out_joints();
132  for (unsigned int i = 0; i < out_joints.size(); i++) {
133  Joint* joint_i = out_joints[i];
134  // TODO: add and implement to joint
136  q.push(KinematicNode(joint_i->get_child_node()));
137  }
138  }
139  is_external_coords_updated_ = true;
140  }
141 
142  //! return joints sorted by BFS traversal
144  Joints ret;
145  // tree BFS traversal from roots
146  std::queue<KinematicNode> q;
147  boost::unordered_set<KinematicNode>::iterator it;
148  for (it = roots_.begin(); it != roots_.end(); it++) q.push(*it);
149 
150  while (!q.empty()) {
151  KinematicNode n = q.front();
152  q.pop();
153  if (n.get_in_joint() != nullptr) ret.push_back(n.get_in_joint());
154 
155  JointsTemp out_joints = n.get_out_joints();
156  for (unsigned int i = 0; i < out_joints.size(); i++) {
157  Joint* joint_i = out_joints[i];
158  q.push(KinematicNode(joint_i->get_child_node()));
159  }
160  }
161  return ret;
162  }
163 
164  /**
165  notifies the tree that joint (internal) coordinates
166  have changed and therefore external coordinates are not
167  up to date
168  */
170  is_external_coords_updated_ = false;
171  }
172 
173  /**
174  notifies the tree that external Cartesian coordinates
175  have changed and therefore internal (joint) coordinates are not
176  up to date
177  */
179  is_internal_coords_updated_ = false;
180  }
181 
182  /**
183  sets the coordinates of a particle, and makes sure that particles
184  and joints in the tree will return correct external and internal
185  coordinates
186 
187  @param rb a rigid body that was previously added to the tree
188  @param c new coordinates
189  */
191  IMP_USAGE_CHECK(get_is_member(rb),
192  "A KinematicForest can only handle particles "
193  << " that were previously added to it");
194  rb.set_coordinates(c);
195  mark_external_coordinates_changed();
196  }
197 
198  /**
199  */
200  IMP::algebra::Vector3D get_coordinates_safe(IMP::core::RigidBody rb) const {
201  IMP_USAGE_CHECK(get_is_member(rb),
202  "A KinematicForest can only handle particles "
203  << " that were previously added to it");
204  const_cast<KinematicForest*>(this)->update_all_external_coordinates();
205  return rb.get_coordinates();
206  }
207 
208  /**
209  */
210  bool get_is_member(IMP::core::RigidBody rb) const {
211  Particle* p = rb.get_particle();
212  return KinematicNode::get_is_setup(p) &&
213  nodes_.find(KinematicNode(p)) != nodes_.end();
214  }
215 
216  // TODO: do we want to add safe access to rigid body members?
217 
218  /**
219  */
220  IMP::algebra::ReferenceFrame3D get_reference_frame_safe(
221  IMP::core::RigidBody rb) const {
222  IMP_USAGE_CHECK(get_is_member(rb),
223  "A KinematicForest can only handle particles "
224  << " that were previously added to it");
225  const_cast<KinematicForest*>(this)->update_all_external_coordinates();
226  return rb.get_reference_frame();
227  }
228 
229  /**
230  sets the reference frame of a rigid body, and makes sure that
231  particles and joints in the tree will return correct
232  internal coordinates when queried directly through the
233  KinematicForest
234 
235  @param rb a rigid body that was previously added to the tree
236  @param r new reference frame
237  */
240  IMP_USAGE_CHECK(get_is_member(rb),
241  "A KinematicForest can only handle particles "
242  << " that were previously added to it");
243  rb.set_reference_frame(r);
244  mark_external_coordinates_changed();
245  }
246 
247  //! apply a rigid body transformation to the entire forest safely
248  /** Apply a rigid body transformation to the entire forest
249  safely, such that the forest will return correct external
250  and internal coordinates if queries through get_coordinates_safe()
251  or get_reference_frame_safe(), or after updating with
252  update_all_external_coordinates() or update_all_internal_coordinates(),
253  respectively.
254  */
256  {
257  IMP_FOREACH(KinematicNode root, roots_){
258  IMP::core::transform(root, tr);
259  mark_internal_coordinates_changed(); // technically, roots reference frames is a part of the internal tree coordinates, so external coordinates will need to be updated at some point
260  }
261  }
262 
263  // TODO: handle derivatives, and safe getting / setting of them
264 
265  private:
266  IMP::Particles get_children(IMP::Particle parent) const;
267 
268  IMP::Particle get_parent(IMP::Particle child) const;
269 
270 #ifndef SWIG
271  friend std::ostream& operator<<(std::ostream& s, const KinematicForest& kt);
272 #endif
273 
274  private:
275  Model* m_;
276 
277  bool is_internal_coords_updated_;
278  bool is_external_coords_updated_;
279 
280  /** the root nodes that serves as spatial anchor to the
281  kinematic trees in the forest */
282  boost::unordered_set<KinematicNode> roots_;
283 
284  /** the set of nodes in the tree */
285  boost::unordered_set<KinematicNode> nodes_;
286 
287  Joints joints_;
288 };
289 
291 
292 IMPKINEMATICS_END_NAMESPACE
293 
294 #endif /* IMPKINEMATICS_KINEMATIC_FOREST_H */
The base class for decorators.
Simple 3D transformation class.
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
Definition: object_macros.h:25
Storage of a model, its restraints, constraints and particles.
Exception definitions and assertions.
A reference frame in 3D.
a kinematic joints between rigid bodies that allows any transformation
#define IMP_NEW(Typename, varname, args)
Declare a ref counted pointer to a new object.
Definition: object_macros.h:64
void reset_root(IMP::Particle *new_root)
rebuild tree (same topology but change directionality)
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:72
Decorator for helping deal with a hierarchy of molecules.
void set_reference_frame_safe(IMP::core::RigidBody rb, IMP::algebra::ReferenceFrame3D r)
void add_rigid_bodies_in_chain(IMP::core::RigidBodies rbs)
functionality for defining a kinematic joint between rigid bodies as part of a kinematic tree ...
The standard decorator for manipulating molecular structures.
void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr)
Set the current reference frame.
Common base class for heavy weight IMP objects.
Definition: Object.h:106
Various general useful macros for IMP.
#define IMP_UNUSED(variable)
void set_coordinates(const algebra::Vector3D &v)
set all coordinates from a vector
Definition: XYZ.h:62
void set_coordinates_safe(IMP::core::RigidBody rb, IMP::algebra::Vector3D c)
functionality for defining nodes on a kinematic chain
virtual void update_child_node_reference_frame() const
Particle * get_particle() const
Returns the particle decorated by this decorator.
Definition: Decorator.h:171
Joints get_ordered_joints() const
return joints sorted by BFS traversal
#define IMP_OBJECTS(Name, PluralName)
Define the types for storing lists of object pointers.
Definition: object_macros.h:44
A rigid body that is connected by a joint to other rigid bodies.
Definition: KinematicNode.h:26
Joint * add_edge(IMP::core::RigidBody parent, IMP::core::RigidBody child)
Exception definitions and assertions.
Base class for joints between rigid bodies in a kinematic tree.
Definition: Joint.h:30
A shared base class to help in debugging and things.
VectorD< 3 > Vector3D
Definition: VectorD.h:421
Class to handle individual particles of a Model object.
Definition: Particle.h:41
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
void transform(RigidBody a, const algebra::Transformation3D &tr)
Transform a rigid body.
Definition: rigid_bodies.h:864
#define IMP_NOT_IMPLEMENTED
Use this to mark that the method is not implemented yet.
Definition: check_macros.h:81
void apply_transform_safely(IMP::algebra::Transformation3D tr)
apply a rigid body transformation to the entire forest safely
A decorator for a rigid body.
Definition: rigid_bodies.h:82
Define and manipulate a kinematic structure over a model.
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Definition: rigid_bodies.h:207