diff --git a/src/ComputeGridGrid.cu b/src/ComputeGridGrid.cu
index 1ecfb9fad191cb1e70d787e384198b57b2a87883..f6cb72cc78899b85ca0395e28e9021dedd9c92ed 100644
--- a/src/ComputeGridGrid.cu
+++ b/src/ComputeGridGrid.cu
@@ -171,9 +171,11 @@ void computePartGridForce(const Vector3* __restrict__ pos, Vector3* particleForc
 	}
 }
 
+
 __global__
 void createPartlist(const Vector3* __restrict__ pos,
 				const int numTypeParticles, const int* __restrict__ typeParticles_d,
+		    const int attached_particle_start, const int attached_particle_end,
 				int* numParticles_d, int* particles_d,
 				const Vector3 gridCenter, const float radius2, BaseGrid* sys_d) {
 	const int tid = threadIdx.x;
@@ -182,11 +184,13 @@ void createPartlist(const Vector3* __restrict__ pos,
 	const int i = blockIdx.x * blockDim.x + threadIdx.x;
 	if (i < numTypeParticles) {
 		int aid = typeParticles_d[i];
-		float dist = (sys_d->wrapDiff(pos[aid] - gridCenter)).length2();
-
-		if (dist <= radius2) {
+		if (aid < attached_particle_start || aid >= attached_particle_end) { 
+		    float dist = (sys_d->wrapDiff(pos[aid] - gridCenter)).length2();
+		
+		    if (dist <= radius2) {
 			int tmp = atomicAggInc(numParticles_d, warpLane);
 			particles_d[tmp] = aid;
+		    }
 		}
 	}
 }		
diff --git a/src/ComputeGridGrid.cuh b/src/ComputeGridGrid.cuh
index 739aa622e2514840f8586c47d0a277d306427ff4..27fc32ccb6b3b3fd43dd005fd9eda7eb1689c8f8 100644
--- a/src/ComputeGridGrid.cuh
+++ b/src/ComputeGridGrid.cuh
@@ -29,6 +29,7 @@ void computePartGridForce(const Vector3* __restrict__ pos, Vector3* particleForc
 extern __global__
 void createPartlist(const Vector3* __restrict__ pos,
 				const int numTypeParticles, const int* __restrict__ typeParticles_d,
+		    const int attached_particle_start, const int attached_particle_end,
 				int* numParticles_d, int* particles_d,
 				const Vector3 gridCenter, const float radius2, BaseGrid* sys_d);
 	
diff --git a/src/Configuration.cpp b/src/Configuration.cpp
index 679daac15e9d595c81ec74848126c6a58aad79bf..e7bdfd71c57e163646c644d6ef3bb85485f4e7a7 100644
--- a/src/Configuration.cpp
+++ b/src/Configuration.cpp
@@ -133,6 +133,20 @@ Configuration::Configuration(const char* config_file, int simNum, bool debug) :
 	serial = new int[(num+num_rb_attached_particles) * simNum];
 	posLast = new Vector3[(num+num_rb_attached_particles) * simNum];
 
+	{
+	    int pidx = 0;
+	    for (int i = 0; i < numRigidTypes; i++) { // Loop over RB types
+		RigidBodyType &rbt = rigidBody[i];
+		for (int j = 0; j < rbt.num; ++j) { // Loop over RBs
+		    for (const int& t: rbt.get_attached_particle_types()) {
+			type[num+pidx] = t;
+			serial[num+pidx] = num+pidx;
+			pidx++;
+		    }
+		}
+	    }
+	}	
+	
         //Han-Yi Chou
         if(ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin"))
            momLast = new Vector3[(num+num_rb_attached_particles) * simNum];
@@ -434,10 +448,9 @@ Configuration::Configuration(const char* config_file, int simNum, bool debug) :
 
 
 	// Create exclusions from the exclude rule, if it was specified in the config file
-    assert(false); // TODO implement RB exclusions
 	if (excludeRule != String("")) {
 		int oldNumExcludes = numExcludes;
-		Exclude* newExcludes = makeExcludes(bonds, bondMap, num+num_rb_attached_particles, numBonds, excludeRule, numExcludes);
+		Exclude* newExcludes = makeExcludes(bonds, bondMap, num, numBonds, excludeRule, numExcludes);
 		if (excludes == NULL) {
 			excludes = new Exclude[numExcludes];
 		} else if (numExcludes >= excludeCapacity) {
@@ -445,13 +458,45 @@ Configuration::Configuration(const char* config_file, int simNum, bool debug) :
 			excludes = new Exclude[numExcludes];
 			for (int i = 0; i < oldNumExcludes; i++)
 				excludes[i] = tempExcludes[i];
-			delete tempExcludes;
+			delete [] tempExcludes;
 		}
 		for (int i = oldNumExcludes; i < numExcludes; i++)
 			excludes[i] = newExcludes[i - oldNumExcludes];
 		printf("Built %d exclusions.\n",numExcludes);
 	}
 
+	{ // Add exclusions for RB attached particles
+	    std::vector<Exclude> ex;
+	    int start = num;
+	    for (int i = 0; i < numRigidTypes; i++) { // Loop over RB types
+		RigidBodyType &rbt = rigidBody[i];
+		const int nap = rbt.num_attached_particles();
+		for (int j = 0; j < rbt.num; ++j) { // Loop over RBs
+		    for (int ai = 0; ai < nap-1; ++ai) {
+			for (int aj = ai+1; aj < nap; ++aj) {
+			    ex.push_back( Exclude( ai+start, aj+start ) );
+			}
+		    }
+		    start += nap;
+		}
+	    }
+	    // copy
+	    int oldNumExcludes = numExcludes;
+	    numExcludes = numExcludes + ex.size();
+	    if (excludes == NULL) {
+		excludes = new Exclude[numExcludes];
+	    } else if (numExcludes >= excludeCapacity) {
+		Exclude* tempExcludes = excludes;
+		excludes = new Exclude[numExcludes];
+		for (int i = 0; i < oldNumExcludes; i++)
+		    excludes[i] = tempExcludes[i];
+		delete [] tempExcludes;
+	    }
+	    for (int i = oldNumExcludes; i < numExcludes; i++)
+		excludes[i] = ex[i - oldNumExcludes];
+	}
+
+	printf("Built %d exclusions.\n",numExcludes);		
 	buildExcludeMap();
 
 	// Count number of particles of each type
@@ -459,7 +504,6 @@ Configuration::Configuration(const char* config_file, int simNum, bool debug) :
 	for (int i = 0; i < numParts; ++i) {
 		numPartsOfType[i] = 0;
 	}
-    assert(false); // First assign type[i] for rb particles
 	for (int i = 0; i < num+num_rb_attached_particles; ++i) {
 		++numPartsOfType[type[i]];
 	}
@@ -1303,7 +1347,7 @@ void Configuration::readAtoms() {
 		for (int i = 0; i < numParts; i++)
 			if (part[i].num == 0)
 				found = false;
-		assert(false); // TODO probably relax constraint that particle must be found; could just be in RB
+		// assert(false); // TODO probably relax constraint that particle must be found; could just be in RB
 		if (!found) {
 			printf("ERROR: Number of particles not specified in config file.\n");
 			exit(1);
diff --git a/src/GrandBrownTown.cu b/src/GrandBrownTown.cu
index f6c9d380421fbd63a22ccfe65d9dbcb234ed636d..339a9f37938bdb0481e8d52f022e7b3d6a288f8a 100644
--- a/src/GrandBrownTown.cu
+++ b/src/GrandBrownTown.cu
@@ -503,8 +503,7 @@ void GrandBrownTown::RunNoseHooverLangevin()
     // Open the files for recording ionic currents
     for (int repID = 0; repID < numReplicas; ++repID) 
     {
-
-        writers[repID]->newFile(pos + (repID * num), name, 0.0f, num); // 'pos + (repID*num)' == array-to-pointer decay
+        writers[repID]->newFile(pos + repID*(num+num_rb_attached_particles), name, 0.0f, num); // 'pos + (repID*num)' == array-to-pointer decay
         if(particle_dynamic == String("Langevin") || particle_dynamic == String("NoseHooverLangevin"))
             momentum_writers[repID]->newFile((momentum + repID * num), name, 0.0f, num); // 'pos + (repID*num)' == array-to-pointer decay
         //random_writers[repID]->newFile(random + (repID * num), name, 0.0f, num);
@@ -606,6 +605,18 @@ void GrandBrownTown::RunNoseHooverLangevin()
 	    internal->clear_force();
 	    internal->clear_energy();
 	    const std::vector<Vector3*>& _pos = internal->getPos_d();
+
+	    if (num_rb_attached_particles > 0) {
+		#pragma omp parallel for
+		for(int i = 0; i < numReplicas; ++i) {
+		    RBC[i]->update_attached_particle_positions(
+			internal->getPos_d()[0]+i*(num+num_rb_attached_particles),
+			internal->getForceInternal_d()[0]+i*(num+num_rb_attached_particles),
+			internal->getEnergy()+i*(num+num_rb_attached_particles),
+			sys_d);
+		}
+	    }
+
 	    if (numGroupSites > 0) updateGroupSites<<<(numGroupSites/32+1),32>>>(_pos[0], groupSiteData_d, num + num_rb_attached_particles, numGroupSites, numReplicas);
 
 	    #ifdef USE_NCCL
@@ -720,7 +731,7 @@ void GrandBrownTown::RunNoseHooverLangevin()
 	internal->clear_energy();
 	gpuman.sync();
 
-	assert(false); // TODO update RB particels
+
         if(particle_dynamic == String("Langevin"))
             updateKernelBAOAB<<< numBlocks, NUM_THREADS >>>(internal->getPos_d()[0], internal->getMom_d(), internal->getForceInternal_d()[0], internal->getType_d(), part_d, kT, kTGrid_d, electricField, tl, timestep, num, num_rb_attached_particles, sys_d, randoGen_d, numReplicas, ParticleInterpolationType);
         else if(particle_dynamic == String("NoseHooverLangevin"))
@@ -760,6 +771,17 @@ void GrandBrownTown::RunNoseHooverLangevin()
             }
         }
 
+	if (num_rb_attached_particles > 0) {
+	    #pragma omp parallel for
+	    for(int i = 0; i < numReplicas; ++i) {
+		RBC[i]->update_attached_particle_positions(
+		    internal->getPos_d()[0]+i*(num+num_rb_attached_particles),
+		    internal->getForceInternal_d()[0]+i*(num+num_rb_attached_particles),
+		    internal->getEnergy()+i*(num+num_rb_attached_particles),
+		    sys_d);
+	    }
+	}
+	
         if (s % outputPeriod == 0) {
             // Copy particle positions back to CPU
 	    gpuErrchk(cudaDeviceSynchronize());
@@ -842,6 +864,7 @@ void GrandBrownTown::RunNoseHooverLangevin()
         for(int i = 0; i < numReplicas; ++i) 
             RBC[i]->clearForceAndTorque();
 
+	
 	if (numGroupSites > 0) {
 	    gpuman.sync();
 	    updateGroupSites<<<(numGroupSites/32+1),32>>>(internal->getPos_d()[0], groupSiteData_d, num + num_rb_attached_particles, numGroupSites, numReplicas);
diff --git a/src/Makefile b/src/Makefile
index b0356b86521cc4ca5448f5fdb8b0b35ea106b2dc..4f6bb5779b9248ff6e4ef7e018387e236b18ab58 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -102,11 +102,16 @@ endif
 all: $(TARGET)
 	@echo "Done ->" $(TARGET)
 
-$(TARGET): $(CU_OBJ) $(CC_OBJ) arbd.cpp vmdsock.c imd.c imd.h
-	$(NVCC) $(NVLD_FLAGS) $(CU_OBJ) $(CC_OBJ) -o $(TARGET)_link.o
+$(TARGET)_link.o: $(CU_OBJ)
+#	$(NVCC) $(NVLD_FLAGS) $(CU_OBJ) $(CC_OBJ) -o $(TARGET)_link.o
 	$(NVCC) $(NVLD_FLAGS) $(CU_OBJ) -o $(TARGET)_link.o
+
+$(TARGET): $(TARGET)_link.o $(CU_OBJ) $(CC_OBJ) arbd.cpp vmdsock.c imd.c imd.h
+#	$(NVCC) $(NVLD_FLAGS) $(CU_OBJ) $(CC_OBJ) -o $(TARGET)_link.o
+#	$(NVCC) $(NVLD_FLAGS) $(CU_OBJ) -o $(TARGET)_link.o
 	$(CC) $(CC_FLAGS) $(EX_FLAGS) arbd.cpp vmdsock.c imd.c $(TARGET)_link.o $(CU_OBJ) $(CC_OBJ) $(LD_FLAGS)  -o $(TARGET)
 
+
 .SECONDEXPANSION:
 $(CU_OBJ): %.o: %.cu $$(wildcard %.h) $$(wildcard %.cuh)
 	$(NVCC) $(NV_FLAGS) $(EX_FLAGS) -dc $< -o $@
diff --git a/src/RigidBody.cu b/src/RigidBody.cu
index f65fcc75298816e893a6052045e4815c0ef08527..abd693bdd3895f19af9027655132825501b52c37 100644
--- a/src/RigidBody.cu
+++ b/src/RigidBody.cu
@@ -18,10 +18,10 @@ inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=t
 }
 #endif
 
-RigidBody::RigidBody(String name, const Configuration& cref, const RigidBodyType& tref, RigidBodyController* RBCref) 
-    : name(name), c(&cref), t(&tref), RBC(RBCref), impulse_to_momentum(4.1867999435271e4) /*impulse_to_momentum(4.184e8f)*/ { init(); }
+RigidBody::RigidBody(String name, const Configuration& cref, const RigidBodyType& tref, RigidBodyController* RBCref, int attached_particle_start, int attached_particle_end) 
+    : name(name), c(&cref), t(&tref), RBC(RBCref), attached_particle_start(attached_particle_start), attached_particle_end(attached_particle_end), impulse_to_momentum(4.1867999435271e4) /*impulse_to_momentum(4.184e8f)*/ { init(); }
 RigidBody::RigidBody(const RigidBody& rb)
-    : name(rb.name), c(rb.c), t(rb.t), RBC(rb.RBC), impulse_to_momentum(4.1867999435271e4)/*impulse_to_momentum(4.184e8f)*/ { init(); }
+    : name(rb.name), c(rb.c), t(rb.t), RBC(rb.RBC), attached_particle_start(rb.attached_particle_start), attached_particle_end(rb.attached_particle_end), impulse_to_momentum(4.1867999435271e4)/*impulse_to_momentum(4.184e8f)*/ { init(); }
 void RigidBody::init() {
 	// units "(kcal_mol/AA) * ns" "dalton AA/ns" * 4.184e+08	
 	timestep = c->timestep;
@@ -103,6 +103,23 @@ int RigidBody::appendNumParticleBlocks( std::vector<int>* blocks ) {
     return ret;
 }
 
+__global__
+void update_particle_positions_kernel(Vector3* __restrict__ pos, const int start, const int num,
+			       const Vector3* __restrict__ pos_rb,
+			       const Vector3 center, const Matrix3 orientation) {
+	const int i = blockIdx.x * blockDim.x + threadIdx.x;
+	if (i < num) {
+	    const int aid = i+start;
+	    pos[aid] = orientation*pos_rb[i] + center;
+	}
+}		
+void RigidBody::update_particle_positions(Vector3* pos_d, Vector3* force_d, float* energy_d) {
+    int num = attached_particle_end - attached_particle_start;
+    int nb = floor(num/NUMTHREADS) + 1;
+    update_particle_positions_kernel<<<nb,NUMTHREADS>>>(pos_d, attached_particle_start, num,
+						 t->attached_particle_positions_d, position, orientation);
+}
+
 void RigidBody::addForce(Force f) { 
 	force += f; 
 } 
@@ -113,8 +130,142 @@ void RigidBody::addEnergy(float e)
 {
     energy += e;
 }
+
+// TODO move code snippet to more general location
+template<class C, class T>
+auto contains(const C& v, const T& x)
+-> decltype(end(v), true)
+{
+    return end(v) != std::find(begin(v), end(v), x);
+}
+/*
+void RigidBody::initialize_possible_particles()
+{
+    std::vector<int> atomic_ids;
+
+    // Loop over potential grids
+    for (int i = 0; i < t->numPotGrids; ++i) {
+	atomic_ids.clear();
+
+	String& gridName = t->potentialGridKeys[i];
+	
+	// Loop over particle types to count the number of particles
+	for (int j = 0; j < conf->numParts; ++j) {
+	    if (contains(conf->partRigidBodyGrid[j], gridName)) {
+		// gridNames contained gridName, so add the particles to atomic_ids
+		for (int aid = 0; aid < conf->num + conf->num_rb_attached_particles; ++aid) {
+		    if (conf->type[aid] == j && (aid < exclude_start || aid > exclude_end)) {
+			atomic_ids.push_back(aid);
+		    }
+		}
+	    }
+	}
+
+	// Initialize device data
+	size_t sz = sizeof(int) * atomic_ids.size();
+	gpuErrchk(cudaMalloc( &(possible_particles_d[i]), sz ));
+	gpuErrchk(cudaMemcpyAsync( possible_particles_d[i], &atomic_ids[0], sz, cudaMemcpyHostToDevice))
+
+	// // Add particles attached to OTHER RBs
+	// int rb_particle_offset = conf->num;
+	// for (const auto& rbs: RBC->rigidBodyByType)
+	// {
+	//     int rb_type
+	//     const RigidBodyType& rb_type = rbs[0].t;
+	//     if (rbs.t != 
+	//     for (int& ptype: rb_type->attached_particle_types) {
+	// 	// This could be made much more efficient
+	// 	if (contains(conf->partRigidBodyGrid[ptype], gridName)) {
+	// 	// Add particles
+	// 	rb
+	// 	rbs[0].sum
+	// 	    }
+	//     rb_particle_offset += rb_type.attached_particle_types
+	    
+	//     for (int k = 0; k < t->gridNames.size(); ++k) {
+	// 	    if (t->gridNames[k] == gridName) {
+	// 		t->numParticles[i] += conf->numPartsOfType[j];			
+	// 	    }
+
+	    
+	// 		// Loop over rigid body grid names associated with particle type
+	// 		const std::vector<String>& gridNames = conf->partRigidBodyGrid[j];
+	// 		for (int k = 0; k < gridNames.size(); ++k) {
+	// 		    if (gridNames[k] == gridName) {
+	// 			// Copy type j particles to particles[i]
+	// 			memcpy( &(particles[i][pid]), tmp, sizeof(int)*currId );
+	// 			assert(currId == conf->numPartsOfType[j]);
+	// 			pid += conf->numPartsOfType[j];
+	// 		    }
+	// 		}
+	// 	    }
+
+	// numParticles[i] = 0;
+
+	    // Count the particles interacting with potential grid i
+	    // Loop over particle types
+	    for (int j = 0; j < conf->numParts; ++j) {
+
+		// Loop over rigid body grid names associated with particle type
+		const std::vector<String>& gridNames = conf->partRigidBodyGrid[j];
+		for (int k = 0; k < t->gridNames.size(); ++k) {
+		    if (t->gridNames[k] == gridName) {
+			numParticles[i] += conf->numPartsOfType[j];			
+		    }
+		}
+	    }
+
+	    // Add RB particles
+	    for (const auto& rbv: RBC->rigidBodyByType)
+	    {
+		int ptype = rbv[0].t->attached_particle_types;
+		const std::vector<String>& gridNames = conf->partRigidBodyGrid[ptype];
+		for (int k = 0; k < t->gridNames.size(); ++k) {
+		    if (t->gridNames[k] == gridName) {
+			t->numParticles[i] += conf->numPartsOfType[j];			
+		    }
+		
+	    attached_particle_
+	    
+	    if (numParticles[i] > 0) {
+
+		    // allocate array of particle ids for the potential grid 
+		    particles[i] = new int[numParticles[i]];
+		    int pid = 0;
+		
+		    // Loop over particle types to count the number of particles
+		    for (int j = 0; j < conf->numParts; ++j) {
+
+			// Build temporary id array of type j particles
+			int tmp[conf->numPartsOfType[j]];
+			int currId = 0;
+			for (int aid = 0; aid < conf->num; ++aid) {
+			    if (conf->type[aid] == j)
+				tmp[currId++] = aid;
+			}
+			if (currId == 0) continue;
+
+			// Loop over rigid body grid names associated with particle type
+			const std::vector<String>& gridNames = conf->partRigidBodyGrid[j];
+			for (int k = 0; k < gridNames.size(); ++k) {
+			    if (gridNames[k] == gridName) {
+				// Copy type j particles to particles[i]
+				memcpy( &(particles[i][pid]), tmp, sizeof(int)*currId );
+				assert(currId == conf->numPartsOfType[j]);
+				pid += conf->numPartsOfType[j];
+			    }
+			}
+		    }
+
+		    // Initialize device data
+		    size_t sz = sizeof(int) * numParticles[i];
+		    gpuErrchk(cudaMalloc( &(particles_d[i]), sz ));
+		    gpuErrchk(cudaMemcpyAsync( particles_d[i], particles[i], sz, cudaMemcpyHostToDevice));
+		}
+	}
+}
+*/
 void RigidBody::updateParticleList(Vector3* pos_d, BaseGrid* sys_d) {
-    assert(false); // TODO update particles, excluding own particles
 	for (int i = 0; i < t->numPotGrids; ++i) {
 		numParticles[i] = 0;
 		int& tnp = t->numParticles[i];
@@ -132,10 +283,12 @@ void RigidBody::updateParticleList(Vector3* pos_d, BaseGrid* sys_d) {
 			int nb = floor(tnp/NUMTHREADS) + 1;
 #if __CUDA_ARCH__ >= 300
 			createPartlist<<<nb,NUMTHREADS>>>(pos_d, tnp, t->particles_d[i],
+							  attached_particle_start, attached_particle_end,
 							tmp_d, particles_d[i],
 							gridCenter + position, cutoff*cutoff, sys_d);
 #else
 			createPartlist<<<nb,NUMTHREADS,NUMTHREADS/WARPSIZE>>>(pos_d, tnp, t->particles_d[i],
+							  attached_particle_start, attached_particle_end,
 							tmp_d, particles_d[i],
 							gridCenter + position, cutoff*cutoff, sys_d);
 #endif			
diff --git a/src/RigidBody.h b/src/RigidBody.h
index 5854a082a29f975d11281b9ad45ffd5bc8cc0fbf..636c80e94fd0f17475156bbc84e0cd74409d8e94 100644
--- a/src/RigidBody.h
+++ b/src/RigidBody.h
@@ -31,7 +31,9 @@ class RigidBody { // host side representation of rigid bodies
 	| splitting methods for rigid body molecular dynamics". J Chem Phys. (1997) |
 	`––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––*/
 		public:
-	RigidBody(String name, const Configuration& c, const RigidBodyType& t, RigidBodyController* RBC);
+    RigidBody(String name, const Configuration& c, const RigidBodyType& t, RigidBodyController* RBC,
+	      int attached_particle_start, int attached_particle_end);
+
     RigidBody(const RigidBody& rb);
     // RigidBody(const RigidBody& rb) : RigidBody(rb.name, *rb.c, *rb.t) {};
 	void init();
@@ -40,6 +42,8 @@ class RigidBody { // host side representation of rigid bodies
 
 	int appendNumParticleBlocks( std::vector<int>* blocks );
 
+    void update_particle_positions(Vector3* pos_d, Vector3* force_d, float* energy_d);
+
 	HOST DEVICE void addForce(Force f); 
 	HOST DEVICE void addTorque(Force t);
         HOST DEVICE void addEnergy(float e);
@@ -76,6 +80,7 @@ class RigidBody { // host side representation of rigid bodies
               return Vector3( angularMomentum.x, angularMomentum.y, angularMomentum.z);
         }
 
+        void initializeParticleLists();
 	void updateParticleList(Vector3* pos_d, BaseGrid* sys_d);
 	void callGridParticleForceKernel(Vector3* pos_d, Vector3* force_d, int s, float* energy, bool get_energy, int scheme, BaseGrid* sys, BaseGrid* sys_d, ForceEnergy* forcestorques_d, const std::vector<int>& forcestorques_offset, int& fto_idx);
 	void applyGridParticleForces(BaseGrid* sys, ForceEnergy* forcestorques, const std::vector<int>& forcestorques_offset, int& fto_idx);
@@ -122,9 +127,12 @@ private:
 	bool isFirstStep; 
 	
 	int* numParticles;		  /* particles affected by potential grids */
+	int** possible_particles_d;		 	
 	int** particles_d;		 	
 	const cudaStream_t** particleForceStreams;
-	
+
+    int attached_particle_start, attached_particle_end;
+    
 	/*–––––––––––––––––––––––––––––––––––––––––.
 	| units "kcal_mol/AA * ns" "(AA/ns) * amu" |
 	`–––––––––––––––––––––––––––––––––––––––––*/
diff --git a/src/RigidBodyController.cu b/src/RigidBodyController.cu
index c5e855ebb34692a168a72198431ff1450d914a53..b16eedbe24610071705a3772919ac3561eef8840 100644
--- a/src/RigidBodyController.cu
+++ b/src/RigidBodyController.cu
@@ -45,15 +45,14 @@ RigidBodyController::RigidBodyController(const Configuration& c, const char* pre
 
 	gpuErrchk(cudaDeviceSynchronize()); /* RBTODO: this should be extraneous */
 	construct_grids();
-	for (int i = 0; i < conf.numRigidTypes; i++)
-		conf.rigidBody[i].initializeParticleLists();
 
 	int numRB = 0;
 	// grow list of rbs
 
-
+	int attached_particle_offset = 0;
 	for (int i = 0; i < conf.numRigidTypes; i++) {			
 		numRB += conf.rigidBody[i].num;
+		int attached_particle_in_type = conf.rigidBody[i].num_attached_particles();
 		std::vector<RigidBody> tmp;
 		// RBTODO: change conf.rigidBody to conf.rigidBodyType
 		const int jmax = conf.rigidBody[i].num;
@@ -64,13 +63,16 @@ RigidBodyController::RigidBodyController(const Configuration& c, const char* pre
 			    snprintf(stmp, 128, "#%d", j);
 			    name.add( stmp );
 			}
-			RigidBody r(name, conf, conf.rigidBody[i], this);
+			RigidBody r(name, conf, conf.rigidBody[i], this,
+				    attached_particle_offset, attached_particle_offset+attached_particle_in_type);
+			attached_particle_offset += attached_particle_in_type;
+
 			int nb = r.appendNumParticleBlocks( &particleForceNumBlocks );
 			tmp.push_back( r );
 		}
 		rigidBodyByType.push_back(tmp);
 	}
-	
+
 	totalParticleForceNumBlocks = 0;
 	for (int i=0; i < particleForceNumBlocks.size(); ++i) {
 	    particleForce_offset.push_back(2*totalParticleForceNumBlocks);
@@ -525,6 +527,16 @@ void RigidBodyController::initializeForcePairs() {
 			
 }
 
+void RigidBodyController::update_attached_particle_positions(Vector3* pos_d, Vector3* force_d, float* energy_d, BaseGrid* sys_d) {
+    for (int i = 0; i < rigidBodyByType.size(); i++) {
+	for (int j = 0; j < rigidBodyByType[i].size(); j++) {
+	    rigidBodyByType[i][j].update_particle_positions(pos_d, force_d, energy_d);
+	}
+    }
+    assert(false); // clear force and energy
+}
+
+
 void RigidBodyController::updateParticleLists(Vector3* pos_d, BaseGrid* sys_d) {
 	for (int i = 0; i < rigidBodyByType.size(); i++) {
 		for (int j = 0; j < rigidBodyByType[i].size(); j++) {
diff --git a/src/RigidBodyController.h b/src/RigidBodyController.h
index 0e2dbadbf1e5eb35f9ad4fd007fe1eeb145e8f81..bf8e58637d2b9860a8d1fd132f2c34a108ecfcb2 100644
--- a/src/RigidBodyController.h
+++ b/src/RigidBodyController.h
@@ -110,6 +110,7 @@ public:
         void integrateDLM(BaseGrid* sys, int step);
 	void updateForces(Vector3* pos_d, Vector3* force_d, int s, float* energy, bool get_energy, int scheme, BaseGrid* sys, BaseGrid* sys_d);
 	void updateParticleLists(Vector3* pos_d, BaseGrid* sys_d);
+    void update_attached_particle_positions(Vector3* pos_d, Vector3* force_d, float* energy_d, BaseGrid* sys_d);
         void clearForceAndTorque(); 
         void KineticEnergy();
         void print(int step);
diff --git a/src/RigidBodyType.cu b/src/RigidBodyType.cu
index 8f7739ceecc4a15b50dd0258e0f58d82ea6480d8..ec0f8b65c7a25587755326291ce45542af777c44 100644
--- a/src/RigidBodyType.cu
+++ b/src/RigidBodyType.cu
@@ -128,6 +128,9 @@ void RigidBodyType::attach_particles() {
 	}
 	fclose(inp);
     }
+    size_t sz = sizeof(Vector3)*attached_particle_positions.size();
+    gpuErrchk(cudaMalloc( &(attached_particle_positions_d), sz ));
+    gpuErrchk(cudaMemcpyAsync( attached_particle_positions_d, &attached_particle_positions[0], sz, cudaMemcpyHostToDevice));
 }
 
 void RigidBodyType::addGrid(String s, std::vector<String> &keys, std::vector<String> &files) {
diff --git a/src/RigidBodyType.h b/src/RigidBodyType.h
index 7a6edcc1dc6d1294e2a8cb37ce61b4eacd221870..5cc1442052a102da7198e1e6eeda806c4cdaa8b7 100644
--- a/src/RigidBodyType.h
+++ b/src/RigidBodyType.h
@@ -17,9 +17,10 @@ class BaseGrid;
 class RigidBodyGrid;
 class Configuration;
 class RigidBodyController;
+class RigidBody;
 
 class RigidBodyType {
-	
+    friend class RigidBody;
 public:
 RigidBodyType(const String& name = "", const Configuration* conf = NULL ) :
 	name(name), conf(conf), num(0),
@@ -41,7 +42,8 @@ public:
 	
     void append_attached_particle_file(String s) { attached_particle_files.push_back(s); }
     void attach_particles();
-    size_t num_attached_particles() { return attached_particle_types.size() ;}
+    size_t num_attached_particles() const { return attached_particle_types.size() ;}
+    const std::vector<int>& get_attached_particle_types() const { return attached_particle_types; }
 
 	void addPotentialGrid(String s);
 	void addDensityGrid(String s);
@@ -59,8 +61,10 @@ public:
 private:
 	const Configuration* conf;
 	std::vector<String> attached_particle_files;
-    std::vector<int>attached_particle_types;
+	std::vector<int>attached_particle_types;
+private:
     std::vector<Vector3>attached_particle_positions;
+    Vector3* attached_particle_positions_d;
 
 public:
 	int num; // number of particles of this type