00001
00002
00003
00004
00005
00006
00007
00008 #ifndef IMP_PARTICLE_H
00009 #define IMP_PARTICLE_H
00010
00011 #include "kernel_config.h"
00012 #include "base_types.h"
00013 #include "Object.h"
00014 #include "internal/particle.h"
00015 #include "utility.h"
00016 #include "Key.h"
00017 #include "internal/AttributeTable.h"
00018 #include "DerivativeAccumulator.h"
00019 #include "Pointer.h"
00020 #include "VectorOfRefCounted.h"
00021 #include "container_base.h"
00022 #include <utility>
00023 #include <memory>
00024
00025
00026
00027
00028
00029 #include <list>
00030
00031 #define IMP_PI(func) if (name.get_index() < IMP_NUM_INLINE) floats_.func;\
00032 else ps_->floats_.func;
00033 #define IMP_RPI(func) if (name.get_index() < IMP_NUM_INLINE) { \
00034 return floats_.func; \
00035 } \
00036 else return ps_->floats_.func;
00037
00038
00039 #if IMP_BUILD < IMP_FAST
00040 #define IMP_CHECK_ACTIVE \
00041 IMP_USAGE_CHECK(get_is_active(), "Particle " << get_name() << " is inactive");
00042 #else
00043 #define IMP_CHECK_ACTIVE
00044 #endif
00045
00046 #define IMP_CHECK_READABLE IMP_IF_CHECK(USAGE) {assert_values_readable();}
00047 #define IMP_CHECK_MUTABLE IMP_IF_CHECK(USAGE) {assert_values_mutable();}
00048 #define IMP_CHECK_VALID_DERIVATIVES IMP_IF_CHECK(USAGE) \
00049 {assert_valid_derivatives();}
00050
00051 #define IMP_PARTICLE_ATTRIBUTE_TYPE(UCName, lcname, Value, cond, \
00052 table0, table1, \
00053 add_action, remove_action) \
00054 void add_attribute(UCName##Key name, Value initial_value){ \
00055 IMP_CHECK_ACTIVE; \
00056 IMP_CHECK_MUTABLE; \
00057 IMP_USAGE_CHECK(name != UCName##Key(), \
00058 "Cannot use attributes without " \
00059 << "naming them."); \
00060 IMP_USAGE_CHECK(!has_attribute(name), \
00061 "Cannot add attribute " << name << " to particle " \
00062 << get_name() << " twice."); \
00063 IMP_USAGE_CHECK(UCName##Table::Traits::get_is_valid(initial_value), \
00064 "Initial value is not valid when adding attribute" \
00065 << name << " to particle " << get_name()); \
00066 on_changed(); \
00067 add_action; \
00068 if (cond) table0.add(name.get_index(), initial_value); \
00069 else table1.add(name.get_index(), initial_value); \
00070 } \
00071 void remove_attribute(UCName##Key name) { \
00072 IMP_CHECK_ACTIVE; \
00073 IMP_USAGE_CHECK(name != UCName##Key(), \
00074 "Cannot use attributes without " \
00075 << "naming them."); \
00076 on_changed(); \
00077 remove_action; \
00078 IMP_USAGE_CHECK(has_attribute(name), \
00079 "Cannot remove attribute " << name << " from particle " \
00080 << get_name() << " as it is not there."); \
00081 if (cond) table0.remove(name.get_index()); \
00082 else table1.remove(name.get_index()); \
00083 } \
00084 bool has_attribute(UCName##Key name) const{ \
00085 IMP_USAGE_CHECK(name != UCName##Key(), \
00086 "Cannot use attributes without " \
00087 << "naming them."); \
00088 IMP_CHECK_ACTIVE; \
00089 if (cond) { \
00090 if (!table0.fits(name.get_index())) return false; \
00091 else { \
00092 return UCName##Table::Traits::get_is_valid( \
00093 table0.get(name.get_index())); \
00094 } \
00095 } else { \
00096 if (!table1.fits(name.get_index())) return false; \
00097 else { \
00098 return UCName##Table::Traits::get_is_valid( \
00099 table1.get(name.get_index())); \
00100 } \
00101 } \
00102 } \
00103 Value get_value(UCName##Key name) const { \
00104 IMP_CHECK_ACTIVE; \
00105 IMP_CHECK_READABLE; \
00106 IMP_USAGE_CHECK(name != UCName##Key(), \
00107 "Cannot use attributes without " \
00108 << "naming them."); \
00109 IMP_USAGE_CHECK(has_attribute(name), \
00110 "Cannot get value " << name << " from particle " \
00111 << get_name() << " as it is not there."); \
00112 if (cond) return table0.get(name.get_index()); \
00113 else return table1.get(name.get_index()); \
00114 } \
00115 void set_value(UCName##Key name, Value value) { \
00116 IMP_USAGE_CHECK(name != UCName##Key(), \
00117 "Cannot use attributes without " \
00118 << "naming them."); \
00119 IMP_IF_CHECK(USAGE) { \
00120 if (!UCName##Table::Traits::get_is_valid(value)) { \
00121 IMP_THROW("Cannot set value of " << name \
00122 << " to " << value \
00123 << " on particle " << get_name(), ModelException); \
00124 } \
00125 } \
00126 IMP_CHECK_ACTIVE; \
00127 IMP_CHECK_MUTABLE; \
00128 IMP_USAGE_CHECK(has_attribute(name), \
00129 "Cannot set value " << name << " from particle " \
00130 << get_name() << " as it is not there."); \
00131 on_changed(); \
00132 if (cond) table0.set(name.get_index(), value); \
00133 else table1.set(name.get_index(), value); \
00134 } \
00135 IMP_SWITCH_DOXYGEN(class UCName##KeyIterator, \
00136 typedef UCName##IteratorTraits::Iterator UCName##KeyIterator); \
00137 UCName##KeyIterator lcname##_keys_begin() const { \
00138 return UCName##IteratorTraits::create_iterator(this, 0, \
00139 table1.get_length()); \
00140 } \
00141 UCName##KeyIterator lcname##_keys_end() const { \
00142 return UCName##IteratorTraits::create_iterator(this, \
00143 table1.get_length(), \
00144 table1.get_length()); \
00145 } \
00146 UCName##Keys get_##lcname##_attributes() const { \
00147 return UCName##Keys(lcname##_keys_begin(), \
00148 lcname##_keys_end()); \
00149 }
00150
00151
00152
00153 IMP_BEGIN_NAMESPACE
00154
00155 class Model;
00156 class Changed;
00157 class SaveOptimizeds;
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 class IMPEXPORT Particle : public Container
00204 {
00205 private:
00206
00207 #ifndef IMP_DOXYGEN
00208 friend class Model;
00209 friend class Changed;
00210 friend class SaveOptimizeds;
00211 friend class internal::ReadLock;
00212 friend class internal::WriteLock;
00213
00214 typedef internal::ParticleStorage::Storage Storage;
00215 void zero_derivatives();
00216
00217 void assert_values_mutable() const;
00218 void assert_values_readable() const;
00219
00220 void assert_can_change_optimization() const;
00221
00222 void assert_can_change_derivatives() const;
00223
00224 void assert_valid_derivatives() const;
00225
00226
00227 void on_changed() {
00228 ps_->dirty_=true;
00229 }
00230
00231 void set_is_not_changed() {
00232 if (ps_->dirty_) {
00233 ps_->shadow_->floats_= floats_;
00234 ps_->shadow_->ps_->floats_= ps_->floats_;
00235 ps_->shadow_->ps_->strings_= ps_->strings_;
00236 ps_->shadow_->ps_->ints_= ps_->ints_;
00237 ps_->shadow_->ps_->optimizeds_= ps_->optimizeds_;
00238 ps_->shadow_->ps_->particles_.clear();
00239 for (ParticleKeyIterator it= particle_keys_begin();
00240 it != particle_keys_end(); ++it) {
00241 ps_->shadow_->ps_->particles_.add(it->get_index(),
00242 get_value(*it)->ps_->shadow_);
00243 }
00244 }
00245 ps_->dirty_=false;
00246 }
00247
00248 void setup_incremental();
00249
00250 void teardown_incremental();
00251
00252
00253 Particle();
00254
00255 void accumulate_derivatives_from_shadow();
00256 void move_derivatives_to_shadow();
00257
00258
00259 typedef internal::FixedInlineStorage<internal::FloatAttributeTableTraits,
00260 IMP_NUM_INLINE>
00261 FloatTable;
00262 typedef internal::ParticleStorage::IntTable IntTable;
00263 typedef internal::ParticleStorage::StringTable StringTable;
00264 typedef internal::ParticleStorage::ParticleTable ParticleTable;
00265 typedef internal::ParticleStorage::ObjectTable ObjectTable;
00266
00267 typedef internal::ArrayStorage<internal::DoubleAttributeTableTraits>
00268 DerivativeTable;
00269 typedef internal::ParticleKeyIterator<FloatKey, Particle,
00270 internal::IsAttribute<FloatKey, Particle> > FloatIteratorTraits;
00271 typedef internal::ParticleKeyIterator<IntKey, Particle,
00272 internal::IsAttribute<IntKey, Particle> > IntIteratorTraits;
00273 typedef internal::ParticleKeyIterator<StringKey, Particle,
00274 internal::IsAttribute<StringKey, Particle> > StringIteratorTraits;
00275 typedef internal::ParticleKeyIterator<ParticleKey, Particle,
00276 internal::IsAttribute<ParticleKey, Particle> > ParticleIteratorTraits;
00277 typedef internal::ParticleKeyIterator<ObjectKey, Particle,
00278 internal::IsAttribute<ObjectKey, Particle> > ObjectIteratorTraits;
00279
00280
00281 typedef internal::ParticleKeyIterator<FloatKey, Particle,
00282 internal::IsOptimized<FloatKey, Particle> > OptimizedIteratorTraits;
00283
00284 private:
00285 FloatTable floats_;
00286 std::auto_ptr<internal::ParticleStorage> ps_;
00287 #endif
00288
00289 IMP_OBJECT(Particle);
00290 public:
00291
00292
00293 Particle(Model *m, std::string name="P%1%");
00294
00295
00296
00297
00298 Model* get_model() const {
00299 return ps_->model_;
00300 }
00301
00302 #ifdef IMP_DOXYGEN
00303
00304
00305
00306
00307
00308
00309
00310 void add_attribute(KeyType name, Type initial_value);
00311 void remove_attribute(KeyType name);
00312 bool has_attribute(KeyType name) const;
00313 Type get_value(KeyType name) const;
00314
00315 #else
00316
00317 IMP_PARTICLE_ATTRIBUTE_TYPE(Float, float, Float,
00318 name.get_index() < IMP_NUM_INLINE,
00319 floats_, ps_->floats_,
00320 { ps_->derivatives_.add(name.get_index(), 0);},
00321 {if (ps_->optimizeds_.fits(name.get_index())) {
00322 ps_->optimizeds_.remove(name.get_index());
00323 }
00324 ps_->derivatives_.remove(name.get_index());});
00325
00326 #ifdef IMP_DOXYGEN
00327 class OptimizedKeyIterator;
00328 #else
00329 typedef OptimizedIteratorTraits::Iterator OptimizedKeyIterator;
00330 #endif
00331
00332
00333 OptimizedKeyIterator optimized_keys_begin() const {
00334 return OptimizedIteratorTraits::create_iterator(this, 0,
00335 ps_->floats_.get_length());
00336 }
00337 OptimizedKeyIterator optimized_keys_end() const {
00338 return OptimizedIteratorTraits::create_iterator(this,
00339 ps_->floats_.get_length(),
00340 ps_->floats_.get_length());
00341 }
00342 IMP_PARTICLE_ATTRIBUTE_TYPE(Int, int, Int,
00343 true, ps_->ints_,ps_->ints_,,);
00344 IMP_PARTICLE_ATTRIBUTE_TYPE(String, string, String,
00345 true,ps_->strings_,ps_->strings_,,)
00346 IMP_PARTICLE_ATTRIBUTE_TYPE(Particle, particle, Particle*,
00347 true,ps_->particles_,ps_->particles_,,)
00348 IMP_PARTICLE_ATTRIBUTE_TYPE(Object, object, Object*,
00349 true,ps_->objects_,ps_->objects_,,);
00350
00351 #endif
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 void add_cache_attribute(IntKey name, unsigned int value) {
00365 IMP_USAGE_CHECK(name != IntKey(),
00366 "Cannot use attributes without "
00367 << "naming them.");
00368 IMP_USAGE_CHECK(!has_attribute(name),
00369 "Cannot add attribute " << name << " to particle "
00370 << get_name() << " twice.");
00371 IMP_USAGE_CHECK(IntTable::Traits::get_is_valid(value),
00372 "Initial value is not valid when adding attribute"
00373 << name << " to particle " << get_name());
00374 ps_->ints_.add(name.get_index(), value);
00375 }
00376 void add_cache_attribute(ObjectKey name, Object *value) {
00377 IMP_CHECK_ACTIVE;
00378 IMP_USAGE_CHECK(name != ObjectKey(), "Cannot use attributes without "
00379 << "naming them.");
00380 IMP_USAGE_CHECK(!has_attribute(name),
00381 "Cannot add attribute " << name << " to particle "
00382 << get_name() << " twice.");
00383 IMP_USAGE_CHECK(ObjectTable::Traits::get_is_valid(value),
00384 "Initial value is not valid when adding attribute"
00385 << name << " to particle " << get_name());
00386 ps_->objects_.add(name.get_index(), value);
00387 ps_->cache_objects_.push_back(name);
00388 }
00389
00390 void clear_caches();
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 void add_attribute(FloatKey name, const Float initial_value, bool optimized){
00404 add_attribute(name, initial_value);
00405 if (optimized) set_is_optimized(name, optimized);
00406 }
00407
00408 void add_to_derivative(FloatKey key, Float value,
00409 const DerivativeAccumulator &da);
00410
00411 void set_is_optimized(FloatKey k, bool tf);
00412
00413 bool get_is_optimized(FloatKey k) const;
00414
00415 Float get_derivative(FloatKey name) const;
00416
00417
00418
00419
00420
00421
00422
00423
00424 bool get_is_active() const {
00425 IMP_IF_CHECK(USAGE_AND_INTERNAL) {
00426 IMP_INTERNAL_CHECK(get_is_valid(), "Particle has been previously freed.");
00427 }
00428 return ps_->model_;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 bool get_is_changed() const {
00440 return ps_->dirty_;
00441 }
00442
00443
00444
00445 Particle *get_prechange_particle() const {
00446 return ps_->shadow_;
00447 }
00448
00449
00450 #if !defined(IMP_DOXYGEN)&& !defined(SWIG)
00451 void *operator new(std::size_t sz, void*p);
00452 void operator delete(void *p);
00453 void *operator new(std::size_t sz);
00454 #endif
00455
00456 #if !defined(IMP_DOXYGEN)
00457 ContainersTemp get_input_containers() const;
00458 bool get_contained_particles_changed() const;
00459 ParticlesTemp get_contained_particles() const;
00460 #endif
00461 };
00462
00463
00464 IMP_OUTPUT_OPERATOR(Particle);
00465
00466 inline Float Particle::get_derivative(FloatKey name) const
00467 {
00468 IMP_CHECK_ACTIVE;
00469 IMP_INTERNAL_CHECK(has_attribute(name), "Particle " << get_name()
00470 << " does not have attribute " << name);
00471 IMP_CHECK_VALID_DERIVATIVES;
00472 return ps_->derivatives_.get(name.get_index());
00473 }
00474
00475
00476 inline bool Particle::get_is_optimized(FloatKey name) const
00477 {
00478 IMP_CHECK_ACTIVE;
00479 if (!ps_->optimizeds_.fits(name.get_index())) return false;
00480 else return ps_->optimizeds_.get(name.get_index());
00481 }
00482
00483 inline void Particle::set_is_optimized(FloatKey name, bool tf)
00484 {
00485 IMP_CHECK_ACTIVE;
00486 IMP_USAGE_CHECK(has_attribute(name), "set_is_optimized called "
00487 << "with invalid attribute" << name);
00488 IMP_IF_CHECK(USAGE) {assert_can_change_optimization();}
00489
00490 if (tf) {
00491 ps_->optimizeds_.add(name.get_index(), true);
00492 } else {
00493 ps_->optimizeds_.remove(name.get_index());
00494 }
00495 }
00496
00497 inline void Particle::add_to_derivative(FloatKey name, Float value,
00498 const DerivativeAccumulator &da)
00499 {
00500 IMP_CHECK_ACTIVE;
00501 IMP_IF_CHECK(USAGE_AND_INTERNAL) {
00502 if (is_nan(value) || !DerivativeTable::Traits::get_is_valid(value)) {
00503 std::string message
00504 =std::string("Can't add NaN to derivative in particle ")+
00505 get_name();
00506 internal::assert_fail(message.c_str());
00507 throw ModelException(message.c_str());
00508 }
00509 }
00510 IMP_INTERNAL_CHECK(has_attribute(name), "Particle " << get_name()
00511 << " does not have attribute " << name);
00512 IMP_IF_CHECK(USAGE_AND_INTERNAL) { assert_can_change_derivatives();}
00513 IMP_INTERNAL_CHECK(name.get_index() < ps_->derivatives_.get_length(),
00514 "Something is wrong with derivative table.");
00515 ps_->derivatives_.set(name.get_index(),
00516 ps_->derivatives_.get(name.get_index())
00517 + da(value));
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 template <unsigned int D>
00531 class ParticleTuple {
00532 Particle *d_[D];
00533 int compare(const ParticleTuple<D> &o) const {
00534 for (unsigned int i=0;i<D; ++i) {
00535 if (d_[i] < o.d_[i]) return -1;
00536 else if (d_[i] > o.d_[i]) return 1;
00537 }
00538 return 0;
00539 }
00540 public:
00541 static const unsigned int get_dimension() {return D;};
00542 typedef ParticleTuple<D> This;
00543 ParticleTuple(){
00544 for (unsigned int i=0; i< D; ++i) {d_[i]=NULL;}
00545 }
00546 ParticleTuple(Particle* x, Particle* y) {
00547 IMP_USAGE_CHECK(D==2, "Need " << D << " to construct a "
00548 << D << "-tuple.");
00549 d_[0] = x;
00550 d_[1] = y;
00551 }
00552 ParticleTuple(Particle* x, Particle* y, Particle* z) {
00553 IMP_USAGE_CHECK(D==3, "Need " << D << " to construct a "
00554 << D << "-tuple.");
00555 d_[0] = x;
00556 d_[1] = y;
00557 d_[2] = z;
00558 }
00559 ParticleTuple(Particle* x0, Particle* x1, Particle* x2, Particle* x3) {
00560 IMP_USAGE_CHECK(D==4, "Need " << D << " to construct a "
00561 << D << "-tuple.");
00562 d_[0] = x0;
00563 d_[1] = x1;
00564 d_[2] = x2;
00565 if (D==4) {
00566
00567 d_[3] = x3;
00568 }
00569 }
00570 IMP_COMPARISONS;
00571 Particle * operator[](unsigned int i) const {
00572 IMP_USAGE_CHECK(i <D, "Out of range member");
00573 return d_[i];
00574 }
00575 Particle *& operator[](unsigned int i) {
00576 IMP_USAGE_CHECK(i <D, "Out of range member");
00577 return d_[i];
00578 }
00579
00580 Particle *get(unsigned int i) const {
00581 return operator[](i);
00582 }
00583
00584 std::string get_name() const {
00585 bool first=true;
00586 std::string ret;
00587 for (unsigned int i=0; i< D; ++i) {
00588 if (!first) {
00589 ret+= " and ";
00590 first=false;
00591 }
00592 ret+=d_[i]->get_name();
00593 }
00594 return ret;
00595 }
00596 IMP_SHOWABLE_INLINE({
00597 out << get_name();
00598 });
00599 };
00600
00601 IMP_OUTPUT_OPERATOR_D(ParticleTuple);
00602
00603 #if !defined(IMP_DOXYGEN)
00604
00605 template <unsigned int D>
00606 struct RefCountParticleTuple {
00607 template <class O>
00608 static void ref(O o) {
00609 for (unsigned int i=0; i< D; ++i) {
00610 internal::ref(o[i]);
00611 }
00612 }
00613 template <class O>
00614 static void unref(O o) {
00615 for (unsigned int i=0; i< D; ++i) {
00616 internal::unref(o[i]);
00617 }
00618 }
00619 };
00620
00621 #endif
00622 typedef ParticleTuple<2> ParticlePair;
00623 typedef std::vector<ParticleTuple<2> > ParticlePairsTemp;
00624 typedef VectorOfRefCounted<ParticleTuple<2>,
00625 RefCountParticleTuple<2> > ParticlePairs;
00626 typedef ParticleTuple<3> ParticleTriplet;
00627 typedef std::vector<ParticleTuple<3> > ParticleTripletsTemp;
00628 typedef VectorOfRefCounted<ParticleTuple<3>,
00629 RefCountParticleTuple<3> > ParticleTriplets;
00630 typedef ParticleTuple<4> ParticleQuad;
00631 typedef std::vector<ParticleTuple<4> > ParticleQuadsTemp;
00632 typedef VectorOfRefCounted<ParticleTuple<4>,
00633 RefCountParticleTuple<4> > ParticleQuads;
00634
00635
00636 typedef std::vector<ParticlesTemp> ParticlesList;
00637
00638 IMP_END_NAMESPACE
00639
00640 #undef IMP_CHECK_ACTIVE
00641 #undef IMP_CHECK_MUTABLE
00642 #undef IMP_CHECK_VALID_DERIVATIVES
00643
00644 #include "Model.h"
00645
00646 #endif