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 <boost/scoped_ptr.hpp>
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
00043 #define IMP_CHECK_READABLE IMP_IF_CHECK(USAGE) {assert_values_readable();}
00044 #define IMP_CHECK_MUTABLE IMP_IF_CHECK(USAGE) {assert_values_mutable();}
00045 #define IMP_CHECK_VALID_DERIVATIVES IMP_IF_CHECK(USAGE) \
00046 {assert_valid_derivatives();}
00047
00048 #else
00049 #define IMP_CHECK_ACTIVE
00050 #define IMP_CHECK_READABLE
00051 #define IMP_CHECK_MUTABLE
00052 #define IMP_CHECK_VALID_DERIVATIVES
00053
00054 #endif
00055
00056 #define IMP_PARTICLE_ATTRIBUTE_TYPE(UCName, lcname, Value, cond, \
00057 table0, table1, \
00058 add_action, remove_action) \
00059 void add_attribute(UCName##Key name, Value initial_value){ \
00060 IMP_CHECK_ACTIVE; \
00061 IMP_CHECK_MUTABLE; \
00062 IMP_USAGE_CHECK(name != UCName##Key(), \
00063 "Cannot use attributes without " \
00064 << "naming them."); \
00065 IMP_USAGE_CHECK(!has_attribute(name), \
00066 "Cannot add attribute " << name << " to particle " \
00067 << get_name() << " twice."); \
00068 IMP_USAGE_CHECK(UCName##Table::Traits::get_is_valid(initial_value), \
00069 "Initial value is not valid when adding attribute" \
00070 << name << " to particle " << get_name()); \
00071 on_changed(); \
00072 add_action; \
00073 if (cond) table0.add(name.get_index(), initial_value); \
00074 else table1.add(name.get_index(), initial_value); \
00075 } \
00076 void remove_attribute(UCName##Key name) { \
00077 IMP_CHECK_ACTIVE; \
00078 IMP_USAGE_CHECK(name != UCName##Key(), \
00079 "Cannot use attributes without " \
00080 << "naming them."); \
00081 on_changed(); \
00082 remove_action; \
00083 IMP_USAGE_CHECK(has_attribute(name), \
00084 "Cannot remove attribute " << name << " from particle " \
00085 << get_name() << " as it is not there."); \
00086 if (cond) table0.remove(name.get_index()); \
00087 else table1.remove(name.get_index()); \
00088 } \
00089 bool has_attribute(UCName##Key name) const{ \
00090 IMP_USAGE_CHECK(name != UCName##Key(), \
00091 "Cannot use attributes without " \
00092 << "naming them."); \
00093 IMP_CHECK_ACTIVE; \
00094 if (cond) { \
00095 if (!table0.fits(name.get_index())) return false; \
00096 else { \
00097 return UCName##Table::Traits::get_is_valid( \
00098 table0.get(name.get_index())); \
00099 } \
00100 } else { \
00101 if (!table1.fits(name.get_index())) return false; \
00102 else { \
00103 return UCName##Table::Traits::get_is_valid( \
00104 table1.get(name.get_index())); \
00105 } \
00106 } \
00107 } \
00108 inline Value get_value(UCName##Key name) const { \
00109 IMP_CHECK_ACTIVE; \
00110 IMP_CHECK_READABLE; \
00111 IMP_USAGE_CHECK(name != UCName##Key(), \
00112 "Cannot use attributes without " \
00113 << "naming them."); \
00114 IMP_USAGE_CHECK(has_attribute(name), \
00115 "Cannot get value " << name << " from particle " \
00116 << get_name() << " as it is not there."); \
00117 if (cond) return table0.get(name.get_index()); \
00118 else return table1.get(name.get_index()); \
00119 } \
00120 void set_value(UCName##Key name, Value value) { \
00121 IMP_USAGE_CHECK(name != UCName##Key(), \
00122 "Cannot use attributes without " \
00123 << "naming them."); \
00124 if (!UCName##Table::Traits::get_is_valid(value)) { \
00125 IMP_THROW("Cannot set value of " << name \
00126 << " to " << value \
00127 << " on particle " << get_name(), ModelException); \
00128 } \
00129 IMP_CHECK_ACTIVE; \
00130 IMP_CHECK_MUTABLE; \
00131 IMP_USAGE_CHECK(has_attribute(name), \
00132 "Cannot set value " << name << " from particle " \
00133 << get_name() << " as it is not there."); \
00134 on_changed(); \
00135 if (cond) table0.set(name.get_index(), value); \
00136 else table1.set(name.get_index(), value); \
00137 } \
00138 IMP_SWITCH_DOXYGEN(class UCName##KeyIterator, \
00139 typedef UCName##IteratorTraits::Iterator UCName##KeyIterator); \
00140 UCName##KeyIterator lcname##_keys_begin() const { \
00141 return UCName##IteratorTraits::create_iterator(this, 0, \
00142 table1.get_length()); \
00143 } \
00144 UCName##KeyIterator lcname##_keys_end() const { \
00145 return UCName##IteratorTraits::create_iterator(this, \
00146 table1.get_length(), \
00147 table1.get_length()); \
00148 } \
00149 UCName##Keys get_##lcname##_attributes() const { \
00150 return UCName##Keys(lcname##_keys_begin(), \
00151 lcname##_keys_end()); \
00152 } \
00153 IMP_REQUIRE_SEMICOLON_CLASS(lcname)
00154
00155
00156
00157 IMP_BEGIN_NAMESPACE
00158
00159 class Model;
00160 class Changed;
00161 class SaveOptimizeds;
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
00204
00205
00206
00207 class IMPEXPORT Particle : public Container
00208 {
00209 private:
00210
00211 #ifndef IMP_DOXYGEN
00212 friend class Model;
00213 friend class Changed;
00214 friend class SaveOptimizeds;
00215 friend struct internal::ReadLock;
00216 friend struct internal::WriteLock;
00217
00218 typedef internal::ParticleStorage::Storage Storage;
00219 void zero_derivatives();
00220
00221 void assert_values_mutable() const;
00222 void assert_values_readable() const;
00223
00224 void assert_can_change_optimization() const;
00225
00226 void assert_can_change_derivatives() const;
00227
00228 void assert_valid_derivatives() const;
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 void validate_float_derivatives() const {
00248 for (unsigned int i=0; i< ps_->derivatives_.get_length(); ++i) {
00249 if (ps_->optimizeds_.fits(i) && ps_->optimizeds_.get(i)) {
00250 if (! (ps_->derivatives_.get(i) < std::numeric_limits<double>::max())) {
00251 IMP_THROW("Bad attribute value", ModelException);
00252 }
00253 }
00254 }
00255 }
00256
00257 void on_changed() {
00258 dirty_=true;
00259 }
00260
00261 void set_is_not_changed() {
00262 if (dirty_ && ps_->shadow_) {
00263 ps_->shadow_->floats_= floats_;
00264 ps_->shadow_->ps_->floats_= ps_->floats_;
00265 ps_->shadow_->ps_->strings_= ps_->strings_;
00266 ps_->shadow_->ps_->ints_= ps_->ints_;
00267 ps_->shadow_->ps_->optimizeds_= ps_->optimizeds_;
00268 ps_->shadow_->ps_->particles_.clear();
00269 for (ParticleKeyIterator it= particle_keys_begin();
00270 it != particle_keys_end(); ++it) {
00271 ps_->shadow_->ps_->particles_.add(it->get_index(),
00272 get_value(*it)->ps_->shadow_);
00273 }
00274 }
00275 dirty_=false;
00276 }
00277
00278 void setup_incremental();
00279
00280 void teardown_incremental();
00281
00282
00283 Particle();
00284
00285 void accumulate_derivatives_from_shadow();
00286 void move_derivatives_to_shadow();
00287
00288
00289 typedef internal::SphereInlineStorage FloatTable;
00290 typedef internal::ParticleStorage::IntTable IntTable;
00291 typedef internal::ParticleStorage::StringTable StringTable;
00292 typedef internal::ParticleStorage::ParticleTable ParticleTable;
00293 typedef internal::ParticleStorage::ObjectTable ObjectTable;
00294
00295 typedef internal::ArrayStorage<internal::DoubleAttributeTableTraits>
00296 DerivativeTable;
00297 typedef internal::ParticleKeyIterator<FloatKey, Particle,
00298 internal::IsAttribute<FloatKey, Particle> > FloatIteratorTraits;
00299 typedef internal::ParticleKeyIterator<IntKey, Particle,
00300 internal::IsAttribute<IntKey, Particle> > IntIteratorTraits;
00301 typedef internal::ParticleKeyIterator<StringKey, Particle,
00302 internal::IsAttribute<StringKey, Particle> > StringIteratorTraits;
00303 typedef internal::ParticleKeyIterator<ParticleKey, Particle,
00304 internal::IsAttribute<ParticleKey, Particle> > ParticleIteratorTraits;
00305 typedef internal::ParticleKeyIterator<ObjectKey, Particle,
00306 internal::IsAttribute<ObjectKey, Particle> > ObjectIteratorTraits;
00307
00308
00309 typedef internal::ParticleKeyIterator<FloatKey, Particle,
00310 internal::IsOptimized<FloatKey, Particle> > OptimizedIteratorTraits;
00311
00312 private:
00313 FloatTable floats_;
00314 boost::scoped_ptr<internal::ParticleStorage> ps_;
00315 bool dirty_;
00316 #endif
00317
00318 IMP_OBJECT(Particle);
00319 public:
00320
00321
00322 Particle(Model *m, std::string name="P%1%");
00323
00324
00325 #ifdef IMP_DOXYGEN
00326
00327
00328
00329
00330
00331
00332
00333 void add_attribute(KeyType name, Type initial_value);
00334 void remove_attribute(KeyType name);
00335 bool has_attribute(KeyType name) const;
00336 Type get_value(KeyType name) const;
00337
00338 #else
00339
00340 IMP_PARTICLE_ATTRIBUTE_TYPE(Float, float, Float,
00341 name.get_index() < IMP_NUM_INLINE,
00342 floats_, ps_->floats_,
00343 { ps_->derivatives_.add(name.get_index(), 0);},
00344 {if (ps_->optimizeds_.fits(name.get_index())) {
00345 ps_->optimizeds_.remove(name.get_index());
00346 }
00347 ps_->derivatives_.remove(name.get_index());});
00348
00349 #ifdef IMP_DOXYGEN
00350 class OptimizedKeyIterator;
00351 #else
00352 typedef OptimizedIteratorTraits::Iterator OptimizedKeyIterator;
00353 #endif
00354
00355
00356 OptimizedKeyIterator optimized_keys_begin() const {
00357 return OptimizedIteratorTraits::create_iterator(this, 0,
00358 ps_->floats_.get_length());
00359 }
00360 OptimizedKeyIterator optimized_keys_end() const {
00361 return OptimizedIteratorTraits::create_iterator(this,
00362 ps_->floats_.get_length(),
00363 ps_->floats_.get_length());
00364 }
00365 IMP_PARTICLE_ATTRIBUTE_TYPE(Int, int, Int,
00366 true, ps_->ints_,ps_->ints_,{},{});
00367 IMP_PARTICLE_ATTRIBUTE_TYPE(String, string, String,
00368 true,ps_->strings_,ps_->strings_,{},{});
00369 IMP_PARTICLE_ATTRIBUTE_TYPE(Particle, particle, Particle*,
00370 true,ps_->particles_,ps_->particles_,{},{});
00371 IMP_PARTICLE_ATTRIBUTE_TYPE(Object, object, Object*,
00372 true,ps_->objects_,ps_->objects_,{},{});
00373
00374 #endif
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 void add_cache_attribute(IntKey name, unsigned int value) {
00388 IMP_USAGE_CHECK(name != IntKey(),
00389 "Cannot use attributes without "
00390 << "naming them.");
00391 IMP_USAGE_CHECK(!has_attribute(name),
00392 "Cannot add attribute " << name << " to particle "
00393 << get_name() << " twice.");
00394 IMP_USAGE_CHECK(IntTable::Traits::get_is_valid(value),
00395 "Initial value is not valid when adding attribute"
00396 << name << " to particle " << get_name());
00397 ps_->ints_.add(name.get_index(), value);
00398 }
00399 void add_cache_attribute(ObjectKey name, Object *value) {
00400 IMP_CHECK_ACTIVE;
00401 IMP_USAGE_CHECK(name != ObjectKey(), "Cannot use attributes without "
00402 << "naming them.");
00403 IMP_USAGE_CHECK(!has_attribute(name),
00404 "Cannot add attribute " << name << " to particle "
00405 << get_name() << " twice.");
00406 IMP_USAGE_CHECK(ObjectTable::Traits::get_is_valid(value),
00407 "Initial value is not valid when adding attribute"
00408 << name << " to particle " << get_name());
00409 ps_->objects_.add(name.get_index(), value);
00410 ps_->cache_objects_.push_back(name);
00411 }
00412
00413 void clear_caches();
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 void add_attribute(FloatKey name, const Float initial_value, bool optimized){
00427 add_attribute(name, initial_value);
00428 if (optimized) set_is_optimized(name, optimized);
00429 }
00430
00431 void add_to_derivative(FloatKey key, Float value,
00432 const DerivativeAccumulator &da);
00433
00434 void set_is_optimized(FloatKey k, bool tf);
00435
00436 bool get_is_optimized(FloatKey k) const;
00437
00438 Float get_derivative(FloatKey name) const;
00439
00440
00441
00442
00443
00444
00445
00446
00447 bool get_is_active() const {
00448 IMP_CHECK_OBJECT(this);
00449 return get_has_model();
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 bool get_is_changed() const {
00461 return dirty_;
00462 }
00463
00464
00465
00466 Particle *get_prechange_particle() const {
00467 return ps_->shadow_;
00468 }
00469
00470
00471 #if !defined(IMP_DOXYGEN)&& !defined(SWIG)
00472 void *operator new(std::size_t sz, void*p);
00473 void operator delete(void *p);
00474 void *operator new(std::size_t sz);
00475 #endif
00476
00477 #if !defined(IMP_DOXYGEN)
00478 #if !defined(SWIG)
00479 const algebra::Sphere3D &_get_coordinates() const {
00480 return floats_.get_data();
00481 }
00482 algebra::Sphere3D &_access_coordinates() {
00483 dirty_=true;
00484 return floats_.access_data();
00485 }
00486 #endif
00487 ContainersTemp get_input_containers() const;
00488 bool get_contained_particles_changed() const;
00489 ParticlesTemp get_contained_particles() const;
00490 bool get_is_up_to_date() const { return true;}
00491 #endif
00492 };
00493
00494
00495 IMP_OUTPUT_OPERATOR(Particle);
00496
00497 inline Float Particle::get_derivative(FloatKey name) const
00498 {
00499 IMP_CHECK_ACTIVE;
00500 IMP_INTERNAL_CHECK(has_attribute(name), "Particle " << get_name()
00501 << " does not have attribute " << name);
00502 IMP_CHECK_VALID_DERIVATIVES;
00503 return ps_->derivatives_.get(name.get_index());
00504 }
00505
00506
00507 inline bool Particle::get_is_optimized(FloatKey name) const
00508 {
00509 IMP_CHECK_ACTIVE;
00510 if (!ps_->optimizeds_.fits(name.get_index())) return false;
00511 else return ps_->optimizeds_.get(name.get_index());
00512 }
00513
00514 inline void Particle::set_is_optimized(FloatKey name, bool tf)
00515 {
00516 IMP_CHECK_ACTIVE;
00517 IMP_USAGE_CHECK(has_attribute(name), "set_is_optimized called "
00518 << "with invalid attribute" << name);
00519 IMP_IF_CHECK(USAGE) {assert_can_change_optimization();}
00520
00521 if (tf) {
00522 ps_->optimizeds_.add(name.get_index(), true);
00523 } else {
00524 ps_->optimizeds_.remove(name.get_index());
00525 }
00526 }
00527
00528 inline void Particle::add_to_derivative(FloatKey name, Float value,
00529 const DerivativeAccumulator &da)
00530 {
00531 IMP_CHECK_ACTIVE;
00532 IMP_IF_CHECK(USAGE_AND_INTERNAL) {
00533 if (is_nan(value) || !DerivativeTable::Traits::get_is_valid(value)) {
00534 std::string message
00535 =std::string("Can't add NaN to derivative in particle ")+
00536 get_name();
00537 internal::assert_fail(message.c_str());
00538 throw ModelException(message.c_str());
00539 }
00540 }
00541 IMP_INTERNAL_CHECK(has_attribute(name), "Particle " << get_name()
00542 << " does not have attribute " << name);
00543 IMP_IF_CHECK(USAGE_AND_INTERNAL) { assert_can_change_derivatives();}
00544 IMP_INTERNAL_CHECK(name.get_index() < ps_->derivatives_.get_length(),
00545 "Something is wrong with derivative table.");
00546 ps_->derivatives_.set(name.get_index(),
00547 ps_->derivatives_.get(name.get_index())
00548 + da(value));
00549 }
00550
00551
00552 IMP_END_NAMESPACE
00553
00554 #undef IMP_CHECK_ACTIVE
00555 #undef IMP_CHECK_MUTABLE
00556 #undef IMP_CHECK_VALID_DERIVATIVES
00557
00558 #include "Model.h"
00559
00560 #endif