IMP logo
IMP Reference Guide  develop.cb6747d2d1,2024/03/28
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-2022 IMP Inventors. All rights reserved.
7  */
8 
9 #ifndef IMPKINEMATICS_KINEMATIC_FOREST_H
10 #define IMPKINEMATICS_KINEMATIC_FOREST_H
11 
12 #include <IMP/kinematics/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 architecture 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  //! apply a rigid body transformation to the entire forest
165  //! safelt, such that the forest will return correct external
166  //! and internal coordinates if queries through get_coordinates_safe()
167  //! or get_reference_frame_safe(), or after updating with
168  //! update_all_external_coordinates() or update_all_internal_coordinates(),
169  //! respectively.
171  for(KinematicNode root : roots_){
172  IMP::core::transform(root, tr);
173  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
174  }
175  }
176 
177  /**
178  notifies the tree that joint (internal) coordinates
179  have changed and therefore external coordinates are not
180  up to date
181  */
183  is_external_coords_updated_ = false;
184  }
185 
186  /**
187  notifies the tree that external Cartesian coordinates
188  have changed and therefore internal (joint) coordinates are not
189  up to date
190  */
192  is_internal_coords_updated_ = false;
193  }
194 
195  /**
196  sets the coordinates of a particle, and makes sure that particles
197  and joints in the tree will return correct external and internal
198  coordinates
199 
200  @param rb a rigid body that was previously added to the tree
201  @param c new coordinates
202  */
204  IMP_USAGE_CHECK(get_is_member(rb),
205  "A KinematicForest can only handle particles "
206  << " that were previously added to it");
207  rb.set_coordinates(c);
208  mark_external_coordinates_changed();
209  }
210 
211  /**
212  */
213  IMP::algebra::Vector3D get_coordinates_safe(IMP::core::RigidBody rb) const {
214  IMP_USAGE_CHECK(get_is_member(rb),
215  "A KinematicForest can only handle particles "
216  << " that were previously added to it");
217  const_cast<KinematicForest*>(this)->update_all_external_coordinates();
218  return rb.get_coordinates();
219  }
220 
221  /**
222  */
223  bool get_is_member(IMP::core::RigidBody rb) const {
224  Particle* p = rb.get_particle();
225  return KinematicNode::get_is_setup(p) &&
226  nodes_.find(KinematicNode(p)) != nodes_.end();
227  }
228 
229  // TODO: do we want to add safe access to rigid body members?
230 
231  /**
232  */
233  IMP::algebra::ReferenceFrame3D get_reference_frame_safe(
234  IMP::core::RigidBody rb) const {
235  IMP_USAGE_CHECK(get_is_member(rb),
236  "A KinematicForest can only handle particles "
237  << " that were previously added to it");
238  const_cast<KinematicForest*>(this)->update_all_external_coordinates();
239  return rb.get_reference_frame();
240  }
241 
242  /**
243  sets the reference frame of a rigid body, and makes sure that
244  particles and joints in the tree will return correct
245  internal coordinates when queried directly through the
246  KinematicForest
247 
248  @param rb a rigid body that was previously added to the tree
249  @param r new reference frame
250  */
253  IMP_USAGE_CHECK(get_is_member(rb),
254  "A KinematicForest can only handle particles "
255  << " that were previously added to it");
256  rb.set_reference_frame(r);
257  mark_external_coordinates_changed();
258  }
259 
260  //! apply a rigid body transformation to the entire forest safely
261  /** Apply a rigid body transformation to the entire forest
262  safely, such that the forest will return correct external
263  and internal coordinates if queries through get_coordinates_safe()
264  or get_reference_frame_safe(), or after updating with
265  update_all_external_coordinates() or update_all_internal_coordinates(),
266  respectively.
267  */
269  {
270  for(KinematicNode root : roots_){
271  IMP::core::transform(root, tr);
272  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
273  }
274  }
275 
276  // TODO: handle derivatives, and safe getting / setting of them
277 
278  private:
279  IMP::Particles get_children(IMP::Particle parent) const;
280 
281  IMP::Particle get_parent(IMP::Particle child) const;
282 
283 #ifndef SWIG
284  friend std::ostream& operator<<(std::ostream& s, const KinematicForest& kt);
285 #endif
286 
287  private:
288  Model* m_;
289 
290  bool is_internal_coords_updated_;
291  bool is_external_coords_updated_;
292 
293  /** the root nodes that serves as spatial anchor to the
294  kinematic trees in the forest */
295  boost::unordered_set<KinematicNode> roots_;
296 
297  /** the set of nodes in the tree */
298  boost::unordered_set<KinematicNode> nodes_;
299 
300  Joints joints_;
301 };
302 
304 
305 IMPKINEMATICS_END_NAMESPACE
306 
307 #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:74
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:86
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:111
Macros to control compiler warnings.
#define IMP_UNUSED(variable)
void set_coordinates(const algebra::Vector3D &v)
set all coordinates from a vector
Definition: XYZ.h:62
Produce copious output to allow someone to trace through the computation.
Definition: enums.h:33
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:194
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)
Helper macros for throwing and handling exceptions.
Base class for joints between rigid bodies in a kinematic tree.
Definition: Joint.h:29
A shared base class to help in debugging and things.
VectorD< 3 > Vector3D
Definition: VectorD.h:408
Class to handle individual particles of a Model object.
Definition: Particle.h:43
#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:882
#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:215
void transform_safe(IMP::algebra::Transformation3D tr)