File: InteractionContainer.cpp

package info (click to toggle)
yade 2019.01a-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 16,568 kB
  • sloc: cpp: 56,330; python: 30,148; ansic: 6,463; sh: 123; makefile: 56
file content (156 lines) | stat: -rw-r--r-- 5,085 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 2008 © Sergei Dorofeenko <sega@users.berlios.de>
// 2009,2010 © Václav Šmilauer <eudoxos@arcig.cz>

#include "InteractionContainer.hpp"
#include "Scene.hpp"

#ifdef YADE_OPENMP
	#include<omp.h>
#endif
CREATE_LOGGER(InteractionContainer);
// begin internal functions

bool InteractionContainer::insert(const shared_ptr<Interaction>& i){
	assert(bodies);
	boost::mutex::scoped_lock lock(drawloopmutex);
	
	Body::id_t id1=i->getId1();
	Body::id_t id2=i->getId2();
	
	if (id1>id2) swap(id1,id2); 
	
	assert((Body::id_t)bodies->size()>id1); // the bodies must exist already
	assert((Body::id_t)bodies->size()>id2); 
	
	const shared_ptr<Body>& b1=(*bodies)[id1];
	const shared_ptr<Body>& b2=(*bodies)[id2];
	
	if(!b1->intrs.insert(Body::MapId2IntrT::value_type(id2,i)).second) return false; // already exists
	if(!b2->intrs.insert(Body::MapId2IntrT::value_type(id1,i)).second) return false; 
	
	linIntrs.resize(++currSize); // currSize updated
	linIntrs[currSize-1]=i; // assign last element
	i->linIx=currSize-1; // store the index back-reference in the interaction (so that it knows how to erase/move itself)
	
	const shared_ptr<Scene>& scene=Omega::instance().getScene(); 
	i->iterBorn=scene->iter;
	
	return true;
}

void InteractionContainer::clear(){
	assert(bodies);
	boost::mutex::scoped_lock lock(drawloopmutex);
	FOREACH(const shared_ptr<Body>& b, *bodies) {
		if (b) b->intrs.clear();
	}
	linIntrs.clear();
	currSize=0;
	dirty=true;
}

bool InteractionContainer::erase(Body::id_t id1,Body::id_t id2, int linPos){
	assert(bodies);
	boost::mutex::scoped_lock lock(drawloopmutex);
	if (id1>id2) swap(id1,id2);
	if(id2>=(Body::id_t)bodies->size()) return false;
	
	const shared_ptr<Body>& b1((*bodies)[id1]);
	const shared_ptr<Body>& b2((*bodies)[id2]);
	int linIx=-1;
	if(!b1) linIx=linPos;
	else {
		Body::MapId2IntrT::iterator I(b1->intrs.find(id2));
		if(I==b1->intrs.end()) linIx=linPos;
		else {
			linIx=I->second->linIx;
			assert(linIx==linPos);
			//erase from body, we also erase from linIntrs below
			b1->intrs.erase(I);
			if (b2) { 
				Body::MapId2IntrT::iterator I2(b2->intrs.find(id1));
				if (not(I2==b2->intrs.end())) { 
					b2->intrs.erase(I2); 
				}
			}
		}
	}
	if(linIx<0) {
		LOG_ERROR("InteractionContainer::erase: attempt to delete interaction with a deleted body (the definition of linPos in the call to erase() should fix the problem) for  ##"+boost::lexical_cast<string>(id1)+"+"+boost::lexical_cast<string>(id2));
		return false;}
	// iid is not the last element; we have to move last one to its place
	if (linIx<(int)currSize-1) {
		linIntrs[linIx]=linIntrs[currSize-1];
		linIntrs[linIx]->linIx=linIx; // update the back-reference inside the interaction
	}
	// in either case, last element can be removed now
	linIntrs.resize(--currSize); // currSize updated
	return true;
}

const shared_ptr<Interaction>& InteractionContainer::find(Body::id_t id1,Body::id_t id2){
	assert(bodies);
	if (id1>id2) swap(id1,id2); 
	// those checks could be perhaps asserts, but pyInteractionContainer has no access to the body container...
	if(id2>=(Body::id_t)bodies->size()){ empty=shared_ptr<Interaction>(); return empty; }
	const shared_ptr<Body>& b1((*bodies)[id1]);
	if(!b1) { empty=shared_ptr<Interaction>(); return empty; }
	Body::MapId2IntrT::iterator I(b1->intrs.find(id2));
	if (I!=b1->intrs.end()) return I->second;
	else { empty=shared_ptr<Interaction>(); return empty; }
}

bool InteractionContainer::insert(Body::id_t id1,Body::id_t id2)
{
	shared_ptr<Interaction> i(new Interaction(id1,id2) );
	return insert(i);	
}

void InteractionContainer::requestErase(Body::id_t id1, Body::id_t id2){
	const shared_ptr<Interaction> I=find(id1,id2); if(!I) return;
	I->reset();
}

void InteractionContainer::requestErase(const shared_ptr<Interaction>& I){
	I->reset();
}

void InteractionContainer::requestErase(Interaction* I){
	I->reset();
}

void InteractionContainer::eraseNonReal(){
	FOREACH(const shared_ptr<Interaction>& i, *this) if(!i->isReal()) this->erase(i->getId1(),i->getId2(),i->linIx);
}

// compare interaction based on their first id
struct compPtrInteraction{
	bool operator() (const shared_ptr<Interaction>& i1, const shared_ptr<Interaction>& i2) const {
		return (*i1)<(*i2);
	}
};

void InteractionContainer::preSave(InteractionContainer&){
	for(const shared_ptr<Interaction>& I : *this) {
		if(I->geom || I->phys) interaction.push_back(I);
		// since requestErase'd interactions have no interaction physics/geom, they are not saved
	}
	if(serializeSorted) std::sort(interaction.begin(),interaction.end(),compPtrInteraction());
}
void InteractionContainer::postSave(InteractionContainer&){ interaction.clear(); }

void InteractionContainer::preLoad(InteractionContainer&){ interaction.clear(); }

void InteractionContainer::postLoad__calledFromScene(const shared_ptr<BodyContainer>& bb){
	bodies=&bb->body;
	clear();
	FOREACH(const shared_ptr<Interaction>& I, interaction){ 
		Body::id_t id1=I->getId1(), id2=I->getId2();
		if (!(*bodies)[id1] || !(*bodies)[id2]) {
			return;
		} else {
			insert(I);
		}
	}
	interaction.clear();
}