diff --git a/Configuration.cpp b/Configuration.cpp
index 2efe3e77603d7e8a54422e7ce7609efb94111578..42b9f27ea0e49fb4c98cde409c47d4aebfcb2684 100644
--- a/Configuration.cpp
+++ b/Configuration.cpp
@@ -295,6 +295,15 @@ Configuration::Configuration(const char* config_file, int simNum, bool debug) :
 		}
 	}
 
+	// Count number of particles of each type
+	numPartsOfType = new int[numParts];
+	for (int i = 0; i < numParts; ++i) {
+		numPartsOfType[i] = 0;
+	}
+	for (int i = 0; i < num; ++i) {
+		++numPartsOfType[type[i]];
+	}
+
 	// Some geometric stuff that should be gotten rid of.
 	Vector3 buffer = (sys->getCenter() + 2.0f*sys->getOrigin())/3.0f;
 	initialZ = buffer.z;
@@ -381,6 +390,7 @@ Configuration::~Configuration() {
 	delete[] partForceZGridFile;
 	delete[] partDiffusionGridFile;
 	delete[] partReservoirFile;
+	delete[] partRigidBodyGrid;
 	
 	// TODO: plug memory leaks
 	if (partsFromFile != NULL) delete[] partsFromFile;
@@ -391,6 +401,8 @@ Configuration::~Configuration() {
 	if (angles != NULL) delete[] angles;
 	if (dihedrals != NULL) delete[] dihedrals;
 
+	delete[] numPartsOfType;
+	  
 	// Table parameters
 	delete[] partTableFile;
 	delete[] partTableIndex0;
@@ -588,13 +600,14 @@ int Configuration::readParameters(const char * config_file) {
 	partForceZGridFile = new String[numParts];
 	partDiffusionGridFile = new String[numParts];
 	partReservoirFile = new String[numParts];
-
+	partRigidBodyGrid = new std::vector<String>[numParts];
+	
 	// Allocate the table variables.
 	partTableFile = new String[numParts*numParts];
 	partTableIndex0 = new int[numParts*numParts];
 	partTableIndex1 = new int[numParts*numParts];
 
-  // Allocate rigid body types
+	// Allocate rigid body types
 	rigidBody = new RigidBodyType[numRigidTypes];
 	
 	int btfcap = 10;
@@ -764,7 +777,9 @@ int Configuration::readParameters(const char * config_file) {
 			}
 			if (readDihedralFile(value, ++currDihedral))
 				numTabDihedralFiles++;
-		} 
+		} else if (param == String("rigidBodyPotential")) {
+			partRigidBodyGrid[currPart].push_back(value);
+		}
 		// RIGID BODY
 		else if (param == String("rigidBody")) {
 			// part[++currPart] = BrownianParticleType(value);
diff --git a/Configuration.h b/Configuration.h
index 058b0bb31ecb2f4e39a472b42517a313d5b33c1a..9d23bb83bf6232c1b4a044ff77004aa155b2372e 100644
--- a/Configuration.h
+++ b/Configuration.h
@@ -156,6 +156,7 @@ public:
 	int numExcludes;
 	int numAngles;
 	int numDihedrals;
+	int* numPartsOfType;
 	String partFile;
 	String bondFile;
 	String excludeFile;
@@ -167,6 +168,7 @@ public:
 	bool readAnglesFromFile;
 	bool readDihedralsFromFile;
 	String* partGridFile;
+	std::vector<String>* partRigidBodyGrid;
 	String* partDiffusionGridFile;
 	String* partForceXGridFile;
 	String* partForceYGridFile;
diff --git a/GrandBrownTown.cu b/GrandBrownTown.cu
index 4eb25721ed2c5549c4b25d3fb8f03b4afd62f579..bc4788cd471cd789ca3e5b420c3152013b89635f 100644
--- a/GrandBrownTown.cu
+++ b/GrandBrownTown.cu
@@ -451,7 +451,7 @@ void GrandBrownTown::run() {
 		int numBlocks = (num * numReplicas) / NUM_THREADS + (num * numReplicas % NUM_THREADS == 0 ? 0 : 1);
 		int tl = temperatureGrid.length();
 
-		RBC.updateForces(s);					/* update RB forces before update particle positions... */
+		RBC.updateForces(internal->getPos_d(), internal->getForceInternal_d(), s);					/* update RB forces before update particle positions... */
 
 		/* DEBUG: reduce net force on particles
 		{  
diff --git a/RigidBodyController.cu b/RigidBodyController.cu
index e3744a2db8583ac62e8b59064db37f5ae3df110e..e7bc0c55477d9d59ad89efc69e6261a6502bdb99 100644
--- a/RigidBodyController.cu
+++ b/RigidBodyController.cu
@@ -59,7 +59,8 @@ RigidBodyController::RigidBodyController(const Configuration& c, const char* out
 
 	random = new RandomCPU(conf.seed + 1); /* +1 to avoid using same seed as RandomCUDA */
 	
-initializeForcePairs();
+	initializeForcePairs();
+	initializeParticleLists();
 }
 RigidBodyController::~RigidBodyController() {
 	for (int i = 0; i < rigidBodyByType.size(); i++)
@@ -166,8 +167,90 @@ void RigidBodyController::initializeForcePairs() {
 		forcePairs[i].initialize();
 			
 }
+
+void RigidBodyController::initializeParticleLists() {
+	// Populate RigidBodyType.particles
+	
+	// TODO: ensure no duplicates in conf.partRigidBodyGrid[i]
 	
-void RigidBodyController::updateForces(int s) {
+    // Allocate RB type's numParticles array
+	for (int rb = 0; rb < conf.numRigidTypes; ++rb) {
+		RigidBodyType& t = conf.rigidBody[rb];
+		t.numParticles = new int[t.numPotGrids];
+		for (int i = 0; i < t.numPotGrids; ++i) t.numParticles[i] = 0;
+	}		
+
+	// Count the number of particles; Loop over particle types
+	for (int i = 0; i < conf.numParts; ++i) {
+
+		// Loop over rigid body grid names associated with particle type
+		const std::vector<String>& gridNames = conf.partRigidBodyGrid[i];
+		for (int j = 0; j < gridNames.size(); ++j) {
+
+			// Loop over RB types
+			for (int rb = 0; rb < conf.numRigidTypes; ++rb) {
+				RigidBodyType& t = conf.rigidBody[rb];
+				const std::vector<String>& keys = t.potentialGridKeys;
+
+				// Loop over potential grids
+				for(int k = 0; k < keys.size(); k++) {
+					// printf("    checking grid keys ");
+					if (gridNames[j] == keys[k])
+						t.numParticles[k] += conf.numPartsOfType[i];
+				}
+			}
+		}
+	}
+
+	// Allocate each particles array
+	for (int rb = 0; rb < conf.numRigidTypes; ++rb) {
+		RigidBodyType& t = conf.rigidBody[rb];
+		t.particles = new int*[t.numPotGrids];
+		for (int i = 0; i < t.numPotGrids; ++i) {
+			t.particles[i] = new int[t.numParticles[i]];
+			t.numParticles[i] = 0; // now use this as a counter 
+		}
+	}
+
+	// Set the number of particles; Loop over particle types
+	for (int i = 0; i < conf.numParts; ++i) {
+		int tmp[conf.numPartsOfType[i]]; // temporary array holding particles of type i
+		int currId = 0;
+		for (int j = 0; j < conf.num; ++j) {
+			if (conf.type[j] == i)
+				tmp[currId++] = j;
+		}
+		
+		// Loop over rigid body grid names associated with particle type
+		const std::vector<String>& gridNames = conf.partRigidBodyGrid[i];
+		for (int j = 0; j < gridNames.size(); ++j) {
+
+			// Loop over RB types
+			for (int rb = 0; rb < conf.numRigidTypes; ++rb) {
+				RigidBodyType& t = conf.rigidBody[rb];
+				const std::vector<String>& keys = t.potentialGridKeys;
+
+				// Loop over potential grids
+				for(int k = 0; k < keys.size(); k++) {
+					// printf("    checking grid keys ");
+					if (gridNames[j] == keys[k]) {
+						memcpy( &(t.particles[k][t.numParticles[k]]), tmp, sizeof(int)*currId );
+						t.numParticles[k] += currId;
+					}
+				}
+			}
+		}
+	}
+
+	// Initialize device data for RB force pairs after std::vector is done growing
+
+	// for (int i = 0; i < forcePairs.size(); i++)
+	// 	forcePairs[i].initialize();
+			
+}
+
+
+void RigidBodyController::updateForces(Vector3* pos_d, Vector3* force_d, int s) {
 	if (s <= 1)
 		gpuErrchk( cudaProfilerStart() );
 
@@ -181,6 +264,12 @@ void RigidBodyController::updateForces(int s) {
 		}
 	}
 
+	// Grid–particle forces
+	for (int i = 0; i < rigidBodyByType.size(); i++) {
+		callGridParticleForceKernel( pos_d, force_d, conf.rigidBody[i], rigidBodyByType[i], s );
+	}
+
+	// Grid–Grid forces
 	if (forcePairs.size() > 0) {
 		
 		for (int i=0; i < forcePairs.size(); i++)
@@ -204,7 +293,7 @@ void RigidBodyController::updateForces(int s) {
 	}
 }
 void RigidBodyController::integrate(int step) {
-	// tell RBs to integrate
+ 	// tell RBs to integrate
 	for (int i = 0; i < rigidBodyByType.size(); i++) {
 		for (int j = 0; j < rigidBodyByType[i].size(); j++) {
 			RigidBody& rb = rigidBodyByType[i][j];
@@ -353,6 +442,69 @@ void RigidBodyForcePair::callGridForceKernel(int pairId, int s) {
 		lastRbGridID = i;
 	}
 }
+void RigidBodyController::callGridParticleForceKernel(Vector3* pos_d, Vector3* force_d,
+				const RigidBodyType& t, std::vector<RigidBody>& rbs, int s) {
+	// get the force/torque on a rigid body, and forces on particles
+	
+	// RBTODO: consolidate CUDA stream management
+	for (int i = 0; i < t.numPotGrids; ++i) {
+		if (t.numParticles[i] == 0) continue;
+
+		for (int j = 0; j < rbs.size(); ++j) {
+			// const int nb = 500;
+			/*
+			  r: postion of particle in real space
+			  B: grid Basis
+			  o: grid origin
+			  R: rigid body orientation
+			  c: rigid body center
+
+			  B': R.B 
+			  c': R.o + c
+			*/
+			// Matrix3 B1 = getBasis1(i);
+			Vector3 c =  rbs[j].getOrientation()*t.potentialGrids[i].getOrigin() + rbs[j].getPosition();
+			Matrix3 B = (rbs[j].getOrientation()*t.potentialGrids[i].getBasis()).inverse();
+		
+			// RBTODO: get energy
+			const int nb = (t.numParticles[i]/NUMTHREADS)+1;
+
+			// RBTODO: IMPORTANT: Improve this
+			Vector3 forces[nb];
+			Vector3 torques[nb];
+			for (int k=0; k < nb; ++k) {
+				forces[k] = Vector3(0.0f);
+				torques[k] = Vector3(0.0f);
+			}
+			Vector3* forces_d;
+			Vector3* torques_d;			
+			gpuErrchk(cudaMalloc(&forces_d, sizeof(Vector3)*nb));
+			gpuErrchk(cudaMalloc(&torques_d, sizeof(Vector3)*nb));
+			gpuErrchk(cudaMemcpy(forces_d, forces, sizeof(Vector3)*nb, cudaMemcpyHostToDevice));
+			gpuErrchk(cudaMemcpy(torques_d, torques, sizeof(Vector3)*nb, cudaMemcpyHostToDevice));
+			
+			computePartGridForce<<< nb, NUMTHREADS, NUMTHREADS*2*sizeof(Vector3) >>>(
+				pos_d, force_d, t.numParticles[i], t.particles[i],
+				t.rawPotentialGrids_d[i],
+				B, c, forces_d, torques_d);
+
+			gpuErrchk(cudaMemcpy(forces, forces_d, sizeof(Vector3)*nb, cudaMemcpyDeviceToHost));
+			gpuErrchk(cudaMemcpy(torques, torques_d, sizeof(Vector3)*nb, cudaMemcpyDeviceToHost));
+
+			Vector3 f = Vector3(0.0f);
+			Vector3 t = Vector3(0.0f);
+			for (int k = 0; k < nb; ++k) {
+				f = f + forces[k];
+				t = t + torques[j];
+			}
+			
+			t = -t - (rbs[j].getPosition()-c).cross( -f ); 
+			rbs[j].addForce( -f );
+			rbs[j].addTorque( t );
+		}
+	}
+}
+
 void RigidBodyForcePair::retrieveForcesForGrid(const int i) {
 	// i: grid ID (less than numGrids)
 	const cudaStream_t &s = stream[streamID[i]];
diff --git a/RigidBodyController.h b/RigidBodyController.h
index f04251f606ea6350abeffa54f2c10a9c2d4898cc..8aed324cd00d4ea7605a9264a00b625cfc44179e 100644
--- a/RigidBodyController.h
+++ b/RigidBodyController.h
@@ -94,11 +94,13 @@ public:
 	RigidBodyController(const Configuration& c, const char* outArg);
 
 	void integrate(int step);
-	void updateForces(int s);
+	void updateForces(Vector3* pos_d, Vector3* force_d, int s);
+	void callGridParticleForceKernel(Vector3* pos_d, Vector3* force_d, const RigidBodyType& t, std::vector<RigidBody>& rbs, int s);
     
 private:
 	void copyGridsToDevice();
 	void initializeForcePairs();
+	void initializeParticleLists();
 
 	void print(int step);
 	void printLegend(std::ofstream &file);
diff --git a/RigidBodyType.cu b/RigidBodyType.cu
index b8ea109855c6dc2cdfc80ddf98b4287acbcb232b..c3f600d9d0be96174900453ee3b465e1a29f9ed7 100644
--- a/RigidBodyType.cu
+++ b/RigidBodyType.cu
@@ -18,6 +18,14 @@ void RigidBodyType::clear() {
 	potentialGridKeys.clear();
 	densityGridKeys.clear();
 	pmfKeys.clear();
+
+	if (numParticles > 0) {
+		for (int i=0; i < numParticles[i]; ++i) {
+			delete[] particles[i];
+		}
+		delete[] numParticles;
+		delete[] particles;
+	}
 	
 	if (numPotGrids > 0) delete[] rawPotentialGrids;
 	if (numDenGrids > 0) delete[] rawDensityGrids;
@@ -26,44 +34,6 @@ void RigidBodyType::clear() {
 }
 
 
-// void RigidBodyType::copy(const RigidBodyType& src) {
-// 	this = new RigidBodyType(src.name);
-// 	num = src.num;
-// 	// if (src.pmf != NULL) pmf = new BaseGrid(*src.pmf);
-// 	if (src.reservoir != NULL) reservoir = new Reservoir(*src.reservoir);
-
-// 	numPotentialGrid = src.numPotentialGrid;
-// 																// TODO: fix this: BaseGrid*[]
-// 	for (int i=0; i < numPotentialGrid; i++) {
-		
-// 	}	
-	
-// 	numDensityGrid = src.numDensityGrid;
-// }
-
-// RigidBodyType& RigidBodyType::operator=(const RigidBodyType& src) {
-// 	clear();
-// 	copy(src);
-// 	return *this;
-// }
-
-
-// KeyGrid RigidBodyType::createKeyGrid(String s) {
-// 	// tokenize and return
-// 	int numTokens = s.tokenCount();
-// 	if (numTokens != 2) {
-// 		printf("ERROR: could not add Grid.\n"); // TODO improve this message
-// 		exit(1);
-// 	}
-// 	String* token = new String[numTokens];
-// 	s.tokenize(token);
-// 	KeyGrid g;
-// 	g.key = token[0];
-// 	g.grid = * new BaseGrid(token[1]);
-// 	return g;
-// }
-
-
 // void RigidBodyType::setDampingCoeffs(float timestep, float tmp_mass, Vector3 tmp_inertia, float tmp_transDamping, float tmp_rotDamping) {
 void RigidBodyType::setDampingCoeffs(float timestep) { /* MUST ONLY BE CALLED ONCE!!! */
 	/*–––––––––––––––––––––––––––––––––––––––––––––––––––––––.
diff --git a/RigidBodyType.h b/RigidBodyType.h
index 44a813ded4ee4f6112a91f898b7ef88658a4eef7..4d9849dea3fe999636d92417581c55348a1cb724 100644
--- a/RigidBodyType.h
+++ b/RigidBodyType.h
@@ -40,7 +40,7 @@ RigidBodyType(const String& name = "") :
 	name(name), num(0),
 	reservoir(NULL), mass(1.0f), inertia(), transDamping(),
 	rotDamping(), initPos(), initRot(Matrix3(1.0f)),
-	numPotGrids(0), numDenGrids(0), numPmfs(0) { }
+		numPotGrids(0), numDenGrids(0), numPmfs(0), numParticles(0) { }
 	
 	/* RigidBodyType(const RigidBodyType& src) { copy(src); } */
 	~RigidBodyType() { clear(); }
@@ -56,7 +56,8 @@ RigidBodyType(const String& name = "") :
 
 	void updateRaw();
 	void setDampingCoeffs(float timestep);
-	
+
+	// TODO: privatize
 public:
 
 	
@@ -91,9 +92,12 @@ public:
 	std::vector<float> densityGridScale;
 	std::vector<float> pmfScale;
 
+	int* numParticles;		  /* particles affected by potential grids */
+	int** particles;		 	
 	
 	// RBTODO: clear std::vectors after initialization, (but keep offsets)
 	// duplicates of std::vector grids for device
+public:
 	int numPotGrids;
 	int numDenGrids;
 	int numPmfs;
@@ -105,6 +109,7 @@ public:
 	Vector3* rawPotentialOrigins;
 	Vector3* rawDensityOrigins;		
 
+	
 	// device pointers
 	RigidBodyGrid** rawPotentialGrids_d;
 	RigidBodyGrid** rawDensityGrids_d;