File: InteractionContainer.cpp

package info (click to toggle)
yade 2026.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 34,448 kB
  • sloc: cpp: 97,645; python: 52,173; sh: 677; makefile: 162
file content (201 lines) | stat: -rw-r--r-- 6,220 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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// 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

namespace yade { // Cannot have #include directive inside.

CREATE_LOGGER(InteractionContainer);
// begin internal functions


bool InteractionContainer::insert(const shared_ptr<Interaction>& i)
{
	assert(bodies);
	const std::lock_guard<std::mutex> 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;
}

bool InteractionContainer::insertInteractionMPI(shared_ptr<Interaction>& i)
{
	bool                           res  = true;
	const shared_ptr<Interaction>& iOld = find(Body::id_t(i->id1), Body::id_t(i->id2));
	if (not iOld) {
		int iterBorn = i->iterBorn;
		res          = insert(i); // if it doesn't exist, insert it
		i->iterBorn  = iterBorn;
	} else /*if (i->isReal())*/ {
		i->linIx                         = iOld->linIx; // else replace existing one (with special care to linIx, only valid locally)
		(*this)[i->linIx]                = i;
		(*bodies)[i->id1]->intrs[i->id2] = i;
		(*bodies)[i->id2]->intrs[i->id1] = i;
	}
	return res;
}

void InteractionContainer::clear()
{
	assert(bodies);
	const std::lock_guard<std::mutex> lock(drawloopmutex);
	for (const auto& 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);
	const std::lock_guard<std::mutex> 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()
{
	for (const auto& 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::updateSortedIntrs()
{
	this->sortedIntrs.resize(this->linIntrs.size());
	this->sortedIntrs = this->linIntrs;
	sort(this->sortedIntrs.begin(), this->sortedIntrs.end(), this->compareTwoInteractions);
}

void InteractionContainer::preSave(InteractionContainer&)
{
	for (const auto& 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();
	for (const auto& I : interaction) {
		Body::id_t id1 = I->getId1(), id2 = I->getId2();
		if (!(*bodies)[id1] || !(*bodies)[id2]) {
			return;
		} else {
			insert(I);
		}
	}
	interaction.clear();
}

} // namespace yade