Index: kernel/include/IMP/DecoratorBase.h =================================================================== --- kernel/include/IMP/DecoratorBase.h (revision 514) +++ kernel/include/IMP/DecoratorBase.h (working copy) @@ -21,7 +21,7 @@ class IMPDLLEXPORT DecoratorBase { protected: - internal::ObjectPointer particle_; + internal::ObjectPointer particle_; DecoratorBase(Particle *p): particle_(p) {} bool is_default() const { return !particle_; Index: kernel/include/IMP/Particle.h =================================================================== --- kernel/include/IMP/Particle.h (revision 514) +++ kernel/include/IMP/Particle.h (working copy) @@ -45,6 +45,14 @@ return out; } +template +void check_particles_active(It b, It e, std::string msg) { + for (It c= b; c != e; ++c) { + IMP_check((*c)->get_is_active(), msg, + InactiveParticleException(msg)); + } +} + } // namespace internal #endif @@ -60,7 +68,7 @@ (set_is_optimized method). \ingroup kernel */ -class IMPDLLEXPORT Particle : public internal::Object +class IMPDLLEXPORT Particle : public internal::RefCountedObject { friend class Model; public: @@ -184,6 +192,34 @@ */ void set_value(StringKey name, String value); + + //! Add an Int attribute to this particle. + /** \param[in] name Name of the attribute being added. + \param[in] value Initial value of the attribute. + */ + void add_attribute(ParticleKey name, Particle* value); + + //! Does particle have an Int attribute with the given name. + /** \param[in] name Name of the attribute being checked. + \return true if Int attribute exists in this particle. + */ + bool has_attribute(ParticleKey name) const; + + //! Get the specified Int for this particle. + /** \param[in] name Name of the attribute being retrieved. + \exception std::out_of_range attribute does not exist. + \return value of the attribute. + */ + Particle* get_value(ParticleKey name) const; + + //! Set the specified Int for this particle. + /** \param[in] name Name of the attribute being set. + \param[in] value Value of the attribute being set. + \exception std::out_of_range attribute does not exist. + */ + void set_value(ParticleKey name, Particle* value); + + //! Set whether the particle is active. /** Restraints referencing the particle are only evaluated for 'active' particles. @@ -232,6 +268,12 @@ return string_indexes_.get_keys(); } + //! See get_particle_attributes + std::vector get_particle_attributes() const { + return particle_indexes_.get_keys(); + } + + //! An iterator through the keys of the float attributes of this particle typedef internal::AttributeTable::AttributeKeyIterator @@ -266,6 +308,19 @@ return string_indexes_.attribute_keys_end(); } + //! An iterator through the keys of the string attributes of this particle + typedef internal::AttributeTable > + ::AttributeKeyIterator ParticleKeyIterator; + //! Iterate through the keys of string attributes of the particle + ParticleKeyIterator particle_keys_begin() const { + return particle_indexes_.attribute_keys_begin(); + } + ParticleKeyIterator particle_keys_end() const { + return particle_indexes_.attribute_keys_end(); + } + + protected: void zero_derivatives(); @@ -284,6 +339,9 @@ internal::AttributeTable int_indexes_; // string attributes associated with the particle internal::AttributeTable string_indexes_; + // particle attributes associated with the particle + internal::AttributeTable > + particle_indexes_; ParticleIndex pi_; }; @@ -392,6 +450,65 @@ string_indexes_.get_value(name)= value; } + +inline bool Particle::has_attribute(ParticleKey name) const +{ + IMP_check(get_is_active(), "Do not touch inactive particles", + InactiveParticleException()); + return particle_indexes_.contains(name); +} + + + +inline Particle* Particle::get_value(ParticleKey name) const +{ + IMP_check(get_is_active(), "Do not touch inactive particles", + InactiveParticleException()); + return particle_indexes_.get_value(name).get(); +} + + +inline void Particle::set_value(ParticleKey name, Particle* value) +{ + IMP_check(get_is_active(), "Do not touch inactive particles", + InactiveParticleException()); + particle_indexes_.get_value(name)= value; +} + + +void inline Particle::add_attribute(FloatKey name, const Float value, + bool is_optimized) +{ + IMP_assert(model_ , + "Particle must be added to Model before an attributes are added"); + float_indexes_.insert(name, internal::FloatData(value, is_optimized)); +} + + +void inline Particle::add_attribute(IntKey name, const Int value) +{ + IMP_assert(model_, + "Particle must be added to Model before an attributes are added"); + int_indexes_.insert(name, value); +} + + +void inline Particle::add_attribute(StringKey name, const String value) +{ + IMP_assert(model_, + "Particle must be added to Model before an attributes are added"); + string_indexes_.insert(name, value); +} + +void inline Particle::add_attribute(ParticleKey name, Particle* value) +{ + IMP_assert(model_, + "Particle must be added to Model before an attributes are added"); + particle_indexes_.insert(name, + internal::ObjectPointer(value)); +} + + } // namespace IMP #endif /* __IMP_PARTICLE_H */ Index: kernel/include/IMP/base_types.h =================================================================== --- kernel/include/IMP/base_types.h (revision 514) +++ kernel/include/IMP/base_types.h (working copy) @@ -10,6 +10,7 @@ #include "IMP_config.h" #include "Index.h" +#include "internal/Vector.h" #include #include @@ -62,7 +63,9 @@ class Particle; //! A class which is used for representing collections of particles /** - We need this to have a uniform return type for python. + We need this to have a uniform return type for python. + \todo It would be nice to use internal::Vector instead, but that + is not as pretty for Python. */ typedef std::vector Particles; typedef std::pair ParticlePair; @@ -113,6 +116,7 @@ Name##_attribute_table_index_=next_attribute_table_index_++; \ } +class Particle; //! The type used to identify float attributes in the Particles IMP_DECLARE_KEY_TYPE(FloatKey, Float); @@ -120,7 +124,10 @@ IMP_DECLARE_KEY_TYPE(IntKey, Int); //! The type used to identify string attributes in the Particles IMP_DECLARE_KEY_TYPE(StringKey, String); +//! The type used to identify a particle attribute in the Particles +IMP_DECLARE_KEY_TYPE(ParticleKey, Particle*) + struct AtomTypeTag{}; struct ResidueTypeTag{}; Index: kernel/include/IMP/internal/Object.h =================================================================== --- kernel/include/IMP/internal/Object.h (revision 514) +++ kernel/include/IMP/internal/Object.h (working copy) @@ -10,6 +10,7 @@ #define __IMP_OBJECT_H #include "../log.h" +#include "../exception.h" namespace IMP { @@ -24,6 +25,10 @@ \note Do not use NDEBUG to remove check_value_ as that changes the memory layout and causes bad things to happen. It should get wrapped in some sort of macro later. + + \note This has ref and unref methods to simplifity ObjectContainer. + For Object, the reference count can be at most 1. + \internal */ class IMPDLLEXPORT Object @@ -36,14 +41,26 @@ //! Throw an assertion if the object has been freed void assert_is_valid() const; - bool get_is_owned() const {return is_owned_;} - void set_is_owned(bool tf) {is_owned_=tf;} + bool get_has_ref() const {return count_ != 0;} + void ref() { + assert_is_valid(); + IMP_assert(count_== 0, + "Non-reference counted objects can only belong to " \ + "one container."); + ++count_; + } + void unref() { + assert_is_valid(); + IMP_assert(count_ ==1, "Too many unrefs on object"); + --count_; + } + protected: + int count_; private: Object(const Object &o){} const internal::Object& operator=(const Object &o) {return *this;} double check_value_; - bool is_owned_; }; } // namespace internal Index: kernel/include/IMP/internal/ObjectContainer.h =================================================================== --- kernel/include/IMP/internal/ObjectContainer.h (revision 514) +++ kernel/include/IMP/internal/ObjectContainer.h (working copy) @@ -8,6 +8,8 @@ #ifndef __IMP_OBJECT_CONTAINER_H #define __IMP_OBJECT_CONTAINER_H +#include + #include namespace IMP @@ -29,55 +31,117 @@ template class ObjectContainer: public std::vector { + std::vector free_; + struct OK { + bool operator()(const O*a) const { + return a != NULL; + } + }; + + template + unsigned int get_index(II i) const {return i.get_index();} + unsigned int get_index(unsigned int i) const {return i;} + + void ref(O*o) { + if (o) o->ref(); + } + + void unref(O* o) { + if (o) { + o->unref(); + if (!o->get_has_ref()) { + delete o; + } + } + } + // hide it + void erase(){} public: typedef std::vector Vector; - using Vector::const_iterator; - using Vector::iterator; - using Vector::begin; - using Vector::end; using Vector::size; using Vector::empty; ObjectContainer(){} ~ObjectContainer() { + clear(); + } + + void clear() { for (typename Vector::iterator it= Vector::begin(); it != Vector::end(); ++it) { - delete *it; + unref(*it); } + free_.clear(); + Vector::clear(); } + + typedef boost::filter_iterator iterator; + iterator begin() {return iterator(Vector::begin(), Vector::end());} + iterator end() {return iterator(Vector::end(), Vector::end());} + + typedef boost::filter_iterator + const_iterator; + const_iterator begin() const { + return const_iterator(Vector::begin(), Vector::end()); + } + const_iterator end() const { + return const_iterator(Vector::end(), Vector::end()); + } + + void remove(I i) { + unsigned int id= get_index(i); + IMP_assert(Vector::operator[](id) != NULL, "Nothing there to remove"); + unref(Vector::operator[](id)); + Vector::operator[](id)=NULL; + free_.push_back(id); + } + O* operator[](I i) const { - IMP_check(i.get_index() < Vector::size(), + IMP_check(get_index(i) < Vector::size(), "Index " << i << " out of range", IndexException("Out of range")); - return Vector::operator[](i.get_index()); + IMP_assert(Vector::operator[](get_index(i)) != NULL, + "Attempting to access invalid slot in container"); + return Vector::operator[](get_index(i)); } I push_back(O* d) { IMP_CHECK_OBJECT(d); - for (typename Vector::const_iterator it= begin(); it != end(); ++it) { + ref(d); + for (typename Vector::const_iterator it= Vector::begin(); + it != Vector::end(); ++it) { IMP_assert(*it != d, "IMP Containers can only have one copy of " << " each object"); } -#ifndef NDEBUG - IMP_assert(!d->get_is_owned(), "Object already owned by another pointer"); - d->set_is_owned(true); -#endif - Vector::push_back(d); - return I(Vector::size()-1); + if (free_.empty()) { + Vector::push_back(d); + unsigned int idx= Vector::size()-1; + return I(idx); + } else { + unsigned int i= free_.back(); + free_.pop_back(); + Vector::operator[](i)= d; + return I(i); + } } template - void insert(typename Vector::iterator c, It b, It e) { + void insert(iterator c, It b, It e) { #ifndef NDEBUG for (It cc= b; cc != e; ++cc) { IMP_CHECK_OBJECT(*cc); - for (typename Vector::const_iterator it= begin(); it != end(); ++it) { + for (typename Vector::const_iterator it= Vector::begin(); + it != Vector::end(); ++it) { IMP_assert(*it != *cc, "IMP Containers can only have one copy of " << " each object"); } - IMP_assert(!(*cc)->get_is_owned(), - "Object already owned by another pointer"); - (*cc)->set_is_owned(true); + } +#endif + for (It cc= b; cc != e; ++cc) { + ref(*cc); } -#endif - Vector::insert(c, b, e); + while (!free_.empty()) { + push_back(*b); + ++b; + } + Vector::insert(c.base(), b, e); } }; Index: kernel/include/IMP/internal/ObjectPointer.h =================================================================== --- kernel/include/IMP/internal/ObjectPointer.h (revision 514) +++ kernel/include/IMP/internal/ObjectPointer.h (working copy) @@ -13,9 +13,10 @@ #include "Object.h" #include "../macros.h" #include "../exception.h" + #include +#include - namespace IMP { @@ -26,17 +27,17 @@ /** The pointer is NULL initialized and checks accesses to throw an exception rather than core dump on an invalid access. \param[in] O The type of IMP::Object-derived object to point to - \param[in] OWNS Whether this pointer own the object. If it does, the object - is destroyed when the pointer is. If OWNS is true, the pointer is non - copyable. - + \param[in] RC If true, the pointer is refcounted. */ -template +template class ObjectPointer { - typedef ObjectPointer This; + typedef ObjectPointer This; O* o_; + // Enforce that ref counted objects are ref counted + BOOST_STATIC_ASSERT((RC || !boost::is_base_of::value)); + void audit() const { IMP_assert(o_ != NULL, "Pointer is NULL"); IMP_CHECK_OBJECT(o_); @@ -47,27 +48,34 @@ } typedef bool (This::*unspecified_bool)() const; + void ref() { + if (RC && o_) o_->ref(); + } + + void unref() { + if (RC && o_) { + o_->unref(); + if (!o_->get_has_ref()) delete o_; + } + } + public: ObjectPointer(const ObjectPointer &o): o_(o.o_) { - BOOST_STATIC_ASSERT(!OWNS); + ref(); } ObjectPointer& operator=(const ObjectPointer &o){ - BOOST_STATIC_ASSERT(!OWNS); + unref(); o_=o.o_; + ref(); return *this; } ObjectPointer(): o_(NULL) {} explicit ObjectPointer(O* o): o_(o) { IMP_assert(o != NULL, "Can't initialize with NULL pointer"); -#ifndef NDEBUG - if (OWNS) { - IMP_assert(!o->get_is_owned(), "Object already owned by another pointer"); - o->set_is_owned(true); - } -#endif + ref(); } ~ObjectPointer(){ - if (OWNS) delete o_; + unref(); } const O& operator*() const { audit(); @@ -90,11 +98,9 @@ return o_; } void operator=(O* o) { - IMP_check(!OWNS || !o || !o->get_is_owned(), - "Cannot add the same object to multiple containers.", - ValueException("Cannot add the same object more than once")); - if (OWNS) delete o_; + unref(); o_=o; + ref(); } IMP_COMPARISONS_1(o_); Index: kernel/include/IMP/internal/RefCountedObject.h =================================================================== --- kernel/include/IMP/internal/RefCountedObject.h (revision 0) +++ kernel/include/IMP/internal/RefCountedObject.h (revision 0) @@ -0,0 +1,127 @@ +/** + * \file RefCountedObject.h + * \brief A shared base class to help in debugging and things. + * + * Copyright 2007-8 Sali Lab. All rights reserved. + * + */ + +#ifndef __IMP_REFCOUNTEDOBJECT_H +#define __IMP_REFCOUNTEDOBJECT_H + +#include "Object.h" + +#include +#include + +namespace IMP +{ + +namespace internal +{ + +//! Common base class for ref counted objects. +/** Currently the only ref counted objects are particles. + + \note Due to weirdness in swig, the external objects + are responsible for deleting the ref counted object when + the ref count goes to zero. This will change once we have + a real solution for Python. + + \internal + */ +class IMPDLLEXPORT RefCountedObject: public Object +{ + typedef Object P; + typedef RefCountedObject This; + static unsigned int live_objects_; +protected: + RefCountedObject() { + ++live_objects_; + } + +public: + + virtual ~RefCountedObject(){ + IMP_assert(count_==0, "Deleting object which still has references"); + --live_objects_; + } + + void ref() { + assert_is_valid(); + ++P::count_; + } + void unref() { + assert_is_valid(); + IMP_assert(count_ != 0, "Too many unrefs on object"); + --P::count_; + } + + static unsigned int get_number_of_live_objects(){ + return live_objects_; + } +}; + + + +template +struct Ref{ + template + static void eval(O){ + BOOST_STATIC_ASSERT((!boost::is_pointer::value + || !boost::is_base_of::value)); + } +}; + +template <> +struct Ref { + template + static void eval(O* o){ + if (o) o->ref(); + } +}; + +template +struct UnRef{ + template + static void eval(O){ + BOOST_STATIC_ASSERT((!boost::is_pointer::value + || !boost::is_base_of::value)); + } +}; + +template <> +struct UnRef { + template + static void eval(O *o){ + if (o) { + o->unref(); + if (!o->get_has_ref()) { + delete o; + } + } + } +}; + + +//! Can be called on any object and will only unref it if appropriate +template +void unref(O o) { + UnRef<(boost::is_pointer::value + && boost::is_base_of::value)>::eval(o); +} + + +//! Can be called on any object and will only ref it if appropriate +template +void ref(O o) { + Ref<(boost::is_pointer::value + && boost::is_base_of::value)>::eval(o); +} + + +} // namespace internal + +} // namespace IMP + +#endif /* __IMP_OBJECT_H */ Index: kernel/include/IMP/internal/Vector.h =================================================================== --- kernel/include/IMP/internal/Vector.h (revision 514) +++ kernel/include/IMP/internal/Vector.h (working copy) @@ -9,12 +9,16 @@ #define __IMP_VECTOR_H #include "../exception.h" +#include "Object.h" +#include "RefCountedObject.h" #include namespace IMP { +class Particle; + namespace internal { @@ -26,9 +30,17 @@ template class Vector: public std::vector { +public: typedef std::vector P; -public: Vector(){} + template + Vector(It b, It e) { + insert(P::end(), b, e); + } + Vector(const P &p) { + insert(P::end(), p.begin(), p.end()); + } + ~Vector(){clear();} const D& operator[](unsigned int i) const { IMP_check(i < P::size(), "Index " << i << " out of range", @@ -41,9 +53,45 @@ IndexException("")); return P::operator[](i); } + void erase(typename P::iterator it) { + unref(*it); + P::erase(it); + } + void erase(typename P::iterator b, + typename P::iterator e) { + for (typename P::iterator c= b; c != e; ++c) { + unref(*c); + } + P::erase(b,e); + } + unsigned int push_back(D d) { + ref(d); + P::push_back(d); + return P::size()-1; + } + void pop_back() { + unref(P::back()); + P::pop_back(); + } + void clear() { + for (typename P::iterator it= P::begin(); it != P::end(); ++it) { + unref(*it); + } + P::clear(); + } + template + void insert(typename P::iterator it, It b, It e) { + for (It c= b; c != e; ++c) { + D d=*c; + ref(d); + } + P::insert(it, b, e); + } }; + + } // namespace internal } // namespace IMP Index: kernel/include/IMP/macros.h =================================================================== --- kernel/include/IMP/macros.h (revision 514) +++ kernel/include/IMP/macros.h (working copy) @@ -225,19 +225,17 @@ \param[in] obj a vector of pointers */ \ void add_##lcname##s(const std::vector& obj); \ + /** \short Clear the contents of the container */ \ + void clear_##lcname##s(); \ + /** \short return the number of objects*/ \ + unsigned int number_of_##lcname##s() const { \ + return lcname##_vector_.size();} \ /** \short Get object refered to by the index \throws IndexException if the index is out of range */ \ Data get_##lcname(IndexType i) const { \ return lcname##_vector_[i]; \ } \ - /** \short return the number of objects*/ \ - unsigned int number_of_##lcname##s() const { \ - return lcname##_vector_.size();} \ - /** \short Get a container of all the objects. - This is for Python as the container can be used like a Python list*/\ - const Ucname##s &get_##lcname##s() const { \ - return static_cast< const Ucname##s &>(lcname##_vector_);} \ /** \short An iterator through the objects. The value type is a pointer.*/ \ typedef Container::iterator Ucname##Iterator; \ @@ -260,11 +258,10 @@ #define IMP_CONTAINER_CORE_IMPL(Class, Ucname, lcname, Data, IndexType, \ Init_obj, Onchanged) \ IndexType Class::add_##lcname(Data obj) { \ - unsigned int osz=lcname##_vector_.size(); \ - IndexType index(osz); \ - lcname##_vector_.push_back(obj); \ + IndexType index= lcname##_vector_.push_back(obj); \ Init_obj; \ Onchanged; \ + if (false) std::cout << index; \ return index; \ } \ void Class::add_##lcname##s(const std::vector &objs) { \ @@ -275,10 +272,17 @@ Data obj= lcname##_vector_[osz+i]; \ IndexType index(osz+i); \ Init_obj; \ + if (false) std::cout << *obj << index; \ } \ Onchanged; \ - } + } \ + /** \short Clear the contents of the container */ \ + void Class::clear_##lcname##s(){ \ + lcname##_vector_.clear(); \ + Onchanged; \ + } \ + //! Use this to add a container of IMP objects /** Such a container adds public methods add_foo, get_foo, number_of_foo @@ -295,10 +299,13 @@ */ #define IMP_LIST(protection, Ucname, lcname, Data) \ protection: \ - /** \short Clear the contents of the container */ \ - void clear_##lcname##s(); \ /** \short Remove any occurences of d from the container */ \ void erase_##lcname(Data d); \ + /** \short Get a container of all the objects. + This is for Python as the container can be used like a Python list*/\ + const Ucname##s &get_##lcname##s() const { \ + return static_cast< const Ucname##s &>(lcname##_vector_); \ + } \ IMP_CONTAINER_CORE(protection, Ucname, lcname, Data, unsigned int, \ IMP::internal::Vector) @@ -314,12 +321,7 @@ #define IMP_LIST_IMPL(Class, Ucname, lcname, Data, init, OnChanged) \ IMP_CONTAINER_CORE_IMPL(Class, Ucname, lcname, Data, unsigned int, \ init, OnChanged) \ - /** \short Clear the contents of the container */ \ - void Class::clear_##lcname##s(){ \ - lcname##_vector_.clear(); \ - OnChanged; \ - } \ - /** \short Remove any occurences of d from the container */ \ + /** \short Remove any occurences of d from the container */ \ void Class::erase_##lcname(Data d) { \ for (Ucname##Iterator it= lcname##s_begin(); \ it != lcname##s_end(); ++it) { \ @@ -344,15 +346,25 @@ \note The type Ucnames must be declared and be a vector of Data. \note these containers are always public - */ -#define IMP_CONTAINER(Ucname, lcname, IndexType) \ - private: \ - /** \internal - This is an implementation detail.*/ \ - typedef IMP::internal::ObjectContainer \ - Ucname##Container; \ - IMP_CONTAINER_CORE(public, Ucname, lcname, Ucname*, IndexType,\ - Ucname##Container) +*/ +#define IMP_CONTAINER(Ucname, lcname, IndexType) \ + public: \ + void remove_##lcname(IndexType i) ; \ + /** \short Get object refered to by the index + \throws IndexException if the index is out of range + */ \ + Ucname##s get_##lcname##s() const { \ + Ucname##s ret( lcname##_vector_.begin(), \ + lcname##_vector_.end()); \ + return ret; \ + } \ +private: \ +/** \internal + This is an implementation detail.*/ \ +typedef IMP::internal::ObjectContainer \ +Ucname##Container; \ +IMP_CONTAINER_CORE(public, Ucname, lcname, Ucname*, IndexType, \ + Ucname##Container) @@ -362,10 +374,19 @@ IMP_CONTAINER. \param[in] init Code to modify the passed in object. The object is obj its index index. + \param[in] onremove Code to execute when an object is removed. The object + being removed is obj. */ -#define IMP_CONTAINER_IMPL(Class, Ucname, lcname, IndexType, init) \ +#define IMP_CONTAINER_IMPL(Class, Ucname, lcname, IndexType, init, \ +onchanged, onremove) \ + void Class::remove_##lcname(IndexType i) { \ + Ucname* obj= lcname##_vector_[i]; \ + onremove; \ + lcname##_vector_.remove(i); \ + if (false) std::cout << *obj; \ + } \ IMP_CONTAINER_CORE_IMPL(Class, Ucname, lcname, Ucname*, IndexType, \ - init,) + init,onchanged) Index: kernel/pyext/IMP.i =================================================================== --- kernel/pyext/IMP.i (revision 514) +++ kernel/pyext/IMP.i (working copy) @@ -27,9 +27,6 @@ %} namespace IMP { - %pythonprepend Model::add_particle %{ - args[1].thisown=0 - %} %pythonprepend Model::add_restraint %{ args[1].thisown=0 %} @@ -126,12 +123,17 @@ %} } +%feature("ref") Particle "$this->ref();" +%feature("unref") Particle "$this->unref(); if (! $this->get_has_ref()) delete $this;" + + /* Don't wrap internal functions */ %ignore IMP::internal::evaluate_distance_pair_score; %feature("director"); %include "IMP/internal/Object.h" +%include "IMP/internal/RefCountedObject.h" %include "IMP/Index.h" %include "IMP/base_types.h" %include "IMP/VersionInfo.h" @@ -144,6 +146,7 @@ %include "IMP/unary_functions/ClosedCubicSpline.h" %include "IMP/unary_functions/Cosine.h" %include "IMP/unary_functions/Linear.h" +%include "IMP/unary_functions/WormLikeChain.h" %include "IMP/DerivativeAccumulator.h" %include "IMP/Restraint.h" %include "IMP/ScoreState.h" @@ -166,6 +169,7 @@ %include "IMP/Optimizer.h" %include "IMP/optimizers/SteepestDescent.h" %include "IMP/optimizers/ConjugateGradients.h" +%include "IMP/optimizers/BrownianDynamics.h" %include "IMP/optimizers/MolecularDynamics.h" %include "IMP/optimizers/Mover.h" %include "IMP/optimizers/MoverBase.h" Index: kernel/src/Model.cpp =================================================================== --- kernel/src/Model.cpp (revision 514) +++ kernel/src/Model.cpp (working copy) @@ -28,13 +28,17 @@ } IMP_CONTAINER_IMPL(Model, Restraint, restraint, RestraintIndex, - obj->set_model(this)); + obj->set_model(this),,obj->set_model(NULL)); IMP_CONTAINER_IMPL(Model, Particle, particle, ParticleIndex, - {obj->set_model(this, index);}); + {obj->set_model(this, index); + obj->set_is_active(true);},, + {obj->set_model(NULL, + ParticleIndex()); + obj->set_is_active(false);}); IMP_CONTAINER_IMPL(Model, ScoreState, score_state, ScoreStateIndex, - {obj->set_model(this);}); + {obj->set_model(this);},,obj->set_model(NULL)); Float Model::evaluate(bool calc_derivs) Index: kernel/src/Optimizer.cpp =================================================================== --- kernel/src/Optimizer.cpp (revision 514) +++ kernel/src/Optimizer.cpp (working copy) @@ -39,6 +39,6 @@ IMP_CONTAINER_IMPL(Optimizer, OptimizerState, optimizer_state, - OptimizerStateIndex, obj->set_optimizer(this)); + OptimizerStateIndex, obj->set_optimizer(this),,); } // namespace IMP Index: kernel/src/Particle.cpp =================================================================== --- kernel/src/Particle.cpp (revision 514) +++ kernel/src/Particle.cpp (working copy) @@ -27,6 +27,8 @@ { model_ = md; pi_ = pi; + IMP_assert(model_==NULL || model_->get_particle(pi_)== this, + "Set_model called with inconsistent data"); } void Particle::set_is_active(const bool is_active) @@ -35,31 +37,6 @@ } -void Particle::add_attribute(FloatKey name, const Float value, - bool is_optimized) -{ - IMP_assert(model_ , - "Particle must be added to Model before an attributes are added"); - float_indexes_.insert(name, internal::FloatData(value, is_optimized)); -} - - -void Particle::add_attribute(IntKey name, const Int value) -{ - IMP_assert(model_, - "Particle must be added to Model before an attributes are added"); - int_indexes_.insert(name, value); -} - - -void Particle::add_attribute(StringKey name, const String value) -{ - IMP_assert(model_, - "Particle must be added to Model before an attributes are added"); - string_indexes_.insert(name, value); -} - - void Particle::zero_derivatives() { for (FloatKeyIterator it= float_keys_begin(); it != float_keys_end(); ++it) { Index: kernel/src/Restraint.cpp =================================================================== --- kernel/src/Restraint.cpp (revision 514) +++ kernel/src/Restraint.cpp (working copy) @@ -60,7 +60,7 @@ // The index line is to disable a warning -IMP_LIST_IMPL(Restraint, Particle, particle, Particle*, { +IMP_LIST_IMPL(Restraint, Particle, particle,Particle*, { IMP_assert(number_of_particles()==0 || obj->get_model() == (*particles_begin())->get_model(), "All particles in Restraint must belong to the " Index: kernel/src/base_types.cpp =================================================================== --- kernel/src/base_types.cpp (revision 514) +++ kernel/src/base_types.cpp (working copy) @@ -31,6 +31,7 @@ IMP_DEFINE_KEY_TYPE(IntKey, Int); IMP_DEFINE_KEY_TYPE(FloatKey, Float); IMP_DEFINE_KEY_TYPE(StringKey, String); +IMP_DEFINE_KEY_TYPE(ParticleKey, Particle); IMP_DEFINE_KEY_TYPE(AtomType, AtomTypeTag); IMP_DEFINE_KEY_TYPE(ResidueType, ResidueTypeTag); Index: kernel/src/internal/Object.cpp =================================================================== --- kernel/src/internal/Object.cpp (revision 514) +++ kernel/src/internal/Object.cpp (working copy) @@ -7,6 +7,7 @@ */ #include "IMP/internal/Object.h" +#include "IMP/internal/RefCountedObject.h" namespace IMP { @@ -14,10 +15,12 @@ namespace internal { +unsigned int RefCountedObject::live_objects_=0; + Object::Object() { check_value_=111111111; - is_owned_=false; + count_=0; } Object::~Object() Index: kernel/src/optimizers/MonteCarlo.cpp =================================================================== --- kernel/src/optimizers/MonteCarlo.cpp (revision 514) +++ kernel/src/optimizers/MonteCarlo.cpp (working copy) @@ -21,7 +21,7 @@ Mover::Mover() {}; IMP_CONTAINER_IMPL(MonteCarlo, Mover, mover, MoverIndex, - obj->set_optimizer(this, index)); + obj->set_optimizer(this, index),,); MonteCarlo::MonteCarlo(): temp_(1), prior_energy_(std::numeric_limits::max()), Index: kernel/src/restraints/RestraintSet.cpp =================================================================== --- kernel/src/restraints/RestraintSet.cpp (revision 514) +++ kernel/src/restraints/RestraintSet.cpp (working copy) @@ -34,7 +34,7 @@ } IMP_CONTAINER_IMPL(RestraintSet, Restraint, restraint, RestraintIndex, - obj->set_model(get_model());); + obj->set_model(get_model());,,); Index: kernel/test/particles/test_refcount.py =================================================================== --- kernel/test/particles/test_refcount.py (revision 0) +++ kernel/test/particles/test_refcount.py (revision 0) @@ -0,0 +1,135 @@ +import unittest +import IMP +import IMP.utils +import IMP.test + + +class RefCountTests(IMP.test.TestCase): + """Test refcounting of particles""" + + def _check_number(self, expected): + print "Expected "+str(expected)\ + + " got " + str(IMP.RefCountedObject.get_number_of_live_objects()) + self.assertEqual(IMP.RefCountedObject.get_number_of_live_objects(), + expected, + "wrong number of particles") + + def _test_simple(self): + """Check that ref counting of particles works within python""" + self._check_number(0) + + p= IMP.Particle() + p=1 + + self._check_number(0) + + m= IMP.Model() + p= IMP.Particle() + m.add_particle(p) + self._check_number(1) + + p=1 + self._check_number(1) + m=1 + self._check_number(0) + + def _test_removal(self): + """Check that ref counting works with removing particles""" + self._check_number(0) + m= IMP.Model() + p= IMP.Particle() + pi= m.add_particle(p) + self._check_number(1) + m.remove_particle(pi) + self._check_number(1) + self.assert_(not p.get_is_active(), "Removed particle is still active") + p=1 + self._check_number(0) + + # This test does not work since swig refcounting is brokens + def _test_round_trip(self): + """test that tracking survives the round trip""" + + print "test that the round trip object doesn't delete it" + self._check_number(0) + m= IMP.Model() + print 1 + p= IMP.Particle() + print p + print 2 + pi= m.add_particle(p) + print 2.5 + p=1 + self._check_number(1) + print "got particle back" + print 3 + p= m.get_particle(pi) + print str(p) + self._check_number(1) + print 4 + p=None + self._check_number(1) + m=1 + print 6 + + print "test that the round trip object keeps it alive" + self._check_number(0) + m= IMP.Model() + print 7 + p= IMP.Particle() + print p + print 8 + pi= m.add_particle(p) + print 9 + p=None + self._check_number(1) + print "got particle back" + print 10 + p= m.get_particle(pi) + print p + self._check_number(1) + print "removing particle" + print 11 + p=None + print 11.25 + p= m.get_particle(pi) + print 11.5 + m.remove_particle(pi) + self._check_number(1) + print 12 + p=None + self._check_number(0) + + + def _test_shared(self): + """Check that ref counting works shared particles""" + print "max change" + self._check_number(0) + m= IMP.Model() + p= IMP.Particle() + pi= m.add_particle(p) + mc= IMP.MaxChangeScoreState(IMP.XYZDecorator.get_xyz_keys()) + mc.add_particle(p) + self._check_number(1) + m.remove_particle(pi) + self._check_number(1) + p=1 + self._check_number(1) + mc.clear_particles() + self._check_number(0) + + def _test_skip(self): + """Check that removed particles are skipped""" + print "skipped" + m= IMP.Model() + p= IMP.Particle() + pi= m.add_particle(p) + ps= m.get_particles() + self.assertEqual(len(ps), 1, "Should only be 1 particle") + m.remove_particle(pi) + ps= m.get_particles() + self.assertEqual(len(ps), 0, "Should no particles particle") + + +if __name__ == '__main__': + unittest.main()