Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F90483565
contact_manager0.hh
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Nov 2, 02:04
Size
34 KB
Mime Type
text/x-c++
Expires
Mon, Nov 4, 02:04 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
20129435
Attached To
rAKA akantu
contact_manager0.hh
View Options
/**
* @file contact_manager0.hh
*
* @author Alejandro M. Aragón <alejandro.aragon@epfl.ch>
*
* @date creation: Tue May 13 2014
* @date last modification: Tue May 13 2014
*
* @brief zeroth level of contact (simplest implementation)
*
* @section LICENSE
*
* Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* Akantu is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Akantu is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Akantu. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#ifndef __AKANTU_CONTACT_MANAGER_0_HH__
#define __AKANTU_CONTACT_MANAGER_0_HH__
#include <unordered_set>
//#include "aka_common.hh"
#include "model_manager.hh"
#define DEBUG_MANAGER 1
__BEGIN_AKANTU__
template
<
class
pair_type
>
class
PairComp
{
public
:
bool
operator
()(
pair_type
const
&
a
,
pair_type
const
&
b
)
{
return
a
.
first
->
first
<
b
.
first
->
first
||
(
!
(
b
.
first
->
first
<
a
.
first
->
first
)
&&
a
.
second
->
first
<
b
.
second
->
first
);
}
};
template
<
class
Bounding_policy
,
Discretization_type
DT
,
Consider_acceleration
accel
=
Consider_t
,
template
<
class
>
class
Cost_policy
=
Cost_functor
>
class
Contact0_model_manager
:
public
Model_manager
<
SolidMechanicsModel
>
,
public
Kinematic_traits
<
accel
>
{
using
Kinematic_traits
<
accel
>::
resolve_time
;
typedef
Real
time_type
;
typedef
ctimer
chronograph_type
;
// model type
typedef
SolidMechanicsModel
model_type
;
typedef
model_type
*
model_pointer
;
typedef
model_type
&
model_reference
;
// geometric types
typedef
Bounding_policy
volume_type
;
typedef
typename
volume_type
::
point_type
point_type
;
typedef
typename
point_type
::
value_type
value_type
;
typedef
typename
volume_type
::
aabb_type
aabb_type
;
// element type
typedef
ModelElement
<
model_type
>
element_type
;
// Bounding volume hierarchy related types
typedef
Cost_policy
<
volume_type
>
cost_functor
;
typedef
DataTree
<
volume_type
,
element_type
,
Cost_policy
>
tree_type
;
typedef
typename
tree_type
::
leaves_data_iterator
leaves_data_iterator
;
typedef
typename
tree_type
::
leaf_iterator
tree_leaf_iterator
;
typedef
typename
tree_type
::
iterator
tree_iterator
;
typedef
typename
tree_type
::
const_iterator
const_tree_iterator
;
typedef
std
::
list
<
tree_type
*>
forest_container
;
typedef
typename
forest_container
::
iterator
forest_iterator
;
typedef
typename
forest_container
::
const_iterator
const_forest_iterator
;
// data structure for detailed check
typedef
std
::
pair
<
leaves_data_iterator
,
leaves_data_iterator
>
check_type
;
// typedef std::unordered_set<check_type, PairComp2<check_type> > check_container;
typedef
std
::
set
<
check_type
,
PairComp
<
check_type
>
>
check_container
;
typedef
typename
check_container
::
iterator
check_iterator
;
// kinematic types
typedef
point_type
velocity_type
;
typedef
std
::
list
<
velocity_type
>
velocity_container
;
typedef
typename
velocity_container
::
iterator
velocity_iterator
;
typedef
unsigned
long
mask_size
;
// timer type
typedef
std
::
priority_queue
<
time_type
,
std
::
vector
<
time_type
>
,
std
::
greater
<
time_type
>
>
timer_type
;
// tuple type
typedef
std
::
tuple
<
time_type
,
tree_iterator
,
tree_iterator
>
tuple_type
;
struct
Tuple_compare
{
bool
operator
()(
const
tuple_type
&
t1
,
const
tuple_type
&
t2
)
const
{
return
std
::
get
<
0
>
(
t1
)
>
std
::
get
<
0
>
(
t2
);
}
};
typedef
typename
std
::
priority_queue
<
tuple_type
,
std
::
vector
<
tuple_type
>
,
Tuple_compare
>
hierarchy_timer
;
//! Structure used to do a postorder update of tree hierarchies
struct
Updater
{
tree_type
&
t_
;
//!< Reference to hierarchy
Updater
(
tree_type
&
t
)
:
t_
(
t
)
{}
void
operator
()(
tree_iterator
it
)
{
if
(
!
it
.
is_leaf
())
{
volume_type
&
v
=
*
it
;
volume_type
&
lv
=
*
it
.
left
();
volume_type
&
rv
=
*
it
.
right
();
v
=
lv
+
rv
;
assert
(
lv
.
last_time_
==
rv
.
last_time_
);
v
.
last_time_
=
lv
.
last_time_
;
v
.
velocity_
=
0.5
*
(
lv
.
velocity_
+
rv
.
velocity_
);
v
.
acceleration_
=
0.5
*
(
lv
.
acceleration_
+
rv
.
acceleration_
);
}
}
};
struct
Printer
{
void
operator
()(
tree_iterator
it
)
{
cout
<<*
it
<<
", "
;
}
};
class
Time_exception
:
public
std
::
exception
{
virtual
const
char
*
what
()
const
throw
()
{
return
"*** EXCEPTION *** Zero time increment."
;
}
};
struct
Continuator
:
public
std
::
exception
{
tuple_type
best_
;
Continuator
(
const
tuple_type
&
b
)
:
best_
(
b
)
{}
virtual
const
char
*
what
()
const
throw
()
{
return
"*** EXCEPTION *** Continue."
;
}
};
template
<
bool
flag
>
struct
Bool2Type
{
enum
{
value
=
flag
};
};
private
:
forest_container
forest_
;
//!< Bounding volume hierarchies
hierarchy_timer
timer_
;
//!< Priority queue of times
mask_size
masks_
;
//!< Variable used for static objects
tree_iterator
null_
;
time_type
last_
;
//!< Keep time of last detection engine reset
check_container
detailed_
;
bool
detect_
;
//! Data structure that holds contact data
struct
ContactData
{
typedef
SolidMechanicsModel
model_type
;
typedef
ModelElement
<
model_type
>
element_type
;
typedef
std
::
set
<
UInt
>
node_set
;
struct
Comparator
{
template
<
class
iterator
>
bool
operator
()(
iterator
const
&
a
,
iterator
const
&
b
)
{
return
a
->
first
<
b
->
first
;
}
};
typedef
std
::
set
<
leaves_data_iterator
,
Comparator
>
elem_set
;
leaves_data_iterator
left_
;
leaves_data_iterator
right_
;
mutable
elem_set
ssurface_
;
mutable
elem_set
msurface_
;
mutable
node_set
slaves_
;
mutable
tree_type
*
stree_
;
mutable
tree_type
*
mtree_
;
ContactData
(
leaves_data_iterator
l
,
leaves_data_iterator
r
)
:
left_
(
l
),
right_
(
r
),
ssurface_
(),
msurface_
(),
slaves_
(),
stree_
(
nullptr
),
mtree_
(
nullptr
)
{}
template
<
class
neighbor_type
>
void
initialize
(
neighbor_type
&
ln
,
neighbor_type
&
rn
)
const
{
stree_
=
ln
.
tree_
;
mtree_
=
rn
.
tree_
;
// insert slave and master elements
for
(
auto
it
=
ln
.
elems_
.
begin
();
it
!=
ln
.
elems_
.
end
();
++
it
)
ssurface_
.
insert
(
*
it
);
for
(
auto
it
=
rn
.
elems_
.
begin
();
it
!=
rn
.
elems_
.
end
();
++
it
)
msurface_
.
insert
(
*
it
);
}
bool
operator
<
(
const
ContactData
&
cd
)
const
{
return
this
->
left_
->
first
<
cd
.
left_
->
first
||
(
!
(
cd
.
left_
->
first
<
this
->
left_
->
first
)
&&
this
->
right_
->
first
<
cd
.
right_
->
first
);
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ContactData
&
cd
)
{
os
<<
"Contact data info:"
<<
endl
;
os
<<
" "
<<
cd
.
slaves_
.
size
()
<<
" slave nodes"
;
// for (std::set<UInt>::const_iterator it = cd.slaves_.begin(); it!=cd.slaves_.end(); ++it)
// os<<" "<<*it<<endl;
// os<<" "<<*it;
return
os
;
}
};
std
::
set
<
ContactData
>
contact_
;
typedef
typename
std
::
set
<
ContactData
>::
iterator
contact_iterator
;
public
:
//! Default constructor
Contact0_model_manager
()
:
Model_manager
(),
forest_
(),
timer_
(),
masks_
(),
null_
(
tree_iterator
(
nullptr
)),
last_
(),
detect_
(
true
)
{}
//! Destructor
~
Contact0_model_manager
()
{
// delete trees
for
(
forest_iterator
it
=
forest_
.
begin
();
it
!=
forest_
.
end
();
++
it
)
delete
*
it
;
}
virtual
void
add_model
(
model_pointer
m
,
Kinematic_type
k
=
dynamic_object_t
)
{
m
->
initializeUpdateResidualData
();
models_
.
push_back
(
m
);
if
(
models_
.
size
()
>
8
*
sizeof
(
mask_size
))
{
cout
<<
"*** ERROR *** Type used for masks is too small to handle all models."
<<
endl
;
cout
<<
"Aborting..."
<<
endl
;
exit
(
1
);
}
// create tree
tree_type
*
tp
=
construct_tree_bottom_up
<
tree_type
,
model_type
,
element_type
>
(
*
m
);
forest_
.
push_back
(
tp
);
#ifdef DEBUG_MANAGER
// cout<<"tree "<<*tp<<endl;
// print_mathematica(*tp);
#endif
// mask model as dynamic or static
masks_
|=
(
k
<<
(
models_
.
size
()
-
1
));
}
void
update_forest
(
time_type
t
)
{
int
k
=
0
;
for
(
forest_iterator
fit
=
forest_
.
begin
();
fit
!=
forest_
.
end
();
++
fit
)
{
// check if the object is dynamic to update
if
(
!
(
masks_
&
(
1
<<
k
++
)))
continue
;
// loop over leaves
for
(
leaves_data_iterator
lit
=
(
*
fit
)
->
leaves_data_begin
();
lit
!=
(
*
fit
)
->
leaves_data_end
();
++
lit
)
{
Real
t_old
=
lit
->
first
->
last_time_
;
std
::
vector
<
const
Real
*>
c
=
lit
->
second
.
coordinates
();
volume_type
v
=
Volume_creator
<
volume_type
>::
create
(
c
);
// get positions
const
point_type
&
p0
=
lit
->
first
->
center
();
const
point_type
&
p1
=
v
.
center
();
// get velocities
const
point_type
&
v0
=
lit
->
first
->
velocity_
;
const
point_type
&
v1
=
v
.
velocity_
;
// new velocity and acceleration
v
.
velocity_
=
1
/
(
t
-
t_old
)
*
(
p1
-
p0
);
v
.
acceleration_
=
1
/
(
t
-
t_old
)
*
(
v1
-
v0
);
v
.
last_time_
=
t
;
// set new volume
*
lit
->
first
=
v
;
}
tree_type
&
t
=
**
fit
;
Updater
u
(
t
);
postorder
(
t
.
root
(),
u
);
}
}
void
reset
()
{
// clear queue
while
(
!
timer_
.
empty
())
timer_
.
pop
();
timer_
.
push
(
std
::
make_tuple
(
last_
,
null_
,
null_
));
timer_
.
push
(
std
::
make_tuple
(
inf
,
null_
,
null_
));
}
template
<
class
queue_type
>
void
print_queue
(
queue_type
copy
)
{
cout
<<
"Printing queue values:"
;
while
(
!
copy
.
empty
())
{
const
tuple_type
&
tuple
=
copy
.
top
();
cout
<<
" "
<<
std
::
get
<
0
>
(
tuple
);
copy
.
pop
();
}
cout
<<
endl
;
}
/*! \param t - Current elapsed time
* \param Dt - Time step
*/
void
intersect
(
time_type
t
,
time_type
Dt
)
{
#ifdef DEBUG_MANAGER
cout
<<
"t = "
<<
t
<<
endl
;
// cout<<"t = "<<t<<", Dt = "<<Dt<<", timer:";
// hierarchy_timer copy = timer_;
// while (!copy.empty()) {
// const tuple_type& tuple = copy.top();
// cout<<" "<<std::get<0>(tuple);
// copy.pop();
// }
// cout<<endl;
#endif
static
time_type
Dt1
=
Dt
;
// reset if first enter the function
if
(
t
==
last_
||
t
==
Dt1
)
{
Dt
=
Dt1
;
reset
();
}
const
tuple_type
&
tuple
=
timer_
.
top
();
time_type
top
=
std
::
get
<
0
>
(
tuple
);
// update hierarchies and get positions
// note that the updating starts before the next intetersection check
if
(
models_
.
size
()
>
1
&&
top
<=
t
+
3
*
Dt1
)
{
update_forest
(
t
);
//#ifdef DEBUG_MANAGER
// cout<<"Updating forest"<<endl;
//#endif
}
// check if detection is shut off
if
(
t
+
Dt
<
top
)
return
;
if
(
detect_
)
{
// get iterators from priority element
tree_iterator
it1
=
std
::
get
<
1
>
(
tuple
);
tree_iterator
it2
=
std
::
get
<
2
>
(
tuple
);
// remove time from timer
timer_
.
pop
();
// check for intersection becase:
// 1. there are enough models
// 2. intersection happens before the next increment
if
(
models_
.
size
()
>
1
&&
top
<=
t
+
Dt1
)
{
// if first step, add next time to timer and return because there
// is not enough information for the computation of intersection times
if
(
t
<=
last_
+
(
accel
==
Consider_t
?
2
:
1
)
*
Dt
)
{
// remove time from timer
timer_
.
push
(
std
::
make_tuple
(
t
,
null_
,
null_
));
#ifdef DEBUG_MANAGER
cout
<<
"Early out"
<<
endl
;
#endif
return
;
}
// check if iterators are null to compute O(n^2) collision times
if
(
it1
==
null_
||
it2
==
null_
)
{
// do O(n^2) operation to obtain next time of intersections
for
(
forest_iterator
it1
=
forest_
.
begin
();
it1
!=
--
forest_
.
end
();
++
it1
)
{
forest_iterator
it2
=
it1
;
for
(
++
it2
;
it2
!=
forest_
.
end
();
++
it2
)
{
// get collision time
#ifdef DEBUG_MANAGER
cout
<<
"Calling check_collision in O(n^2) branch"
<<
endl
;
#endif
time_type
tstar
=
resolve_time
((
*
it1
)
->
root
(),
(
*
it2
)
->
root
());
if
(
tstar
!=
inf
)
timer_
.
push
(
std
::
make_tuple
(
t
+
tstar
,
(
*
it1
)
->
root
(),
(
*
it2
)
->
root
()));
#ifdef DEBUG_MANAGER
else
cout
<<
"*** INFO *** Objects do not intersect:
\n
"
<<*
(
*
it1
)
->
root
()
<<
"
\n
"
<<*
(
*
it2
)
->
root
()
<<
endl
;
#endif
}
// inner hierarchy loop
}
// outer hierarchy loop
}
// else use collision information previously computed (avoids O(n^2) operation above)
else
{
#ifdef DEBUG_MANAGER
cout
<<
"Calling check_collision in non-O(n^2) branch"
<<
endl
;
#endif
// temporary queue for tree traversal
hierarchy_timer
pq
;
pq
.
push
(
std
::
make_tuple
(
top
,
it1
,
it2
));
try
{
// enter infinite loop
while
(
!
pq
.
empty
())
{
#ifdef DEBUG_MANAGER
cout
<<
"______________________________________________"
<<
endl
;
cout
<<
"queue empty? -> "
<<
pq
.
empty
()
<<
endl
;
if
(
!
pq
.
empty
())
print_queue
(
pq
);
#endif
const
tuple_type
&
tuple
=
pq
.
top
();
time_type
tstar
=
std
::
get
<
0
>
(
tuple
);
tree_iterator
left
=
std
::
get
<
1
>
(
tuple
);
tree_iterator
right
=
std
::
get
<
2
>
(
tuple
);
#ifdef DEBUG_MANAGER
cout
<<
"Queue time "
<<
tstar
<<
", items: "
<<*
left
<<
", "
<<*
right
<<
endl
;
#endif
pq
.
pop
();
check_collision
(
t
,
left
,
right
,
pq
);
}
// infinite loop
}
catch
(
Continuator
&
e
)
{
cout
<<
"In continuator"
<<
endl
;
tuple_type
&
best
=
e
.
best_
;
time_type
&
best_time
=
std
::
get
<
0
>
(
best
);
best_time
+=
t
;
// clean hierarchy timer until best time
while
(
std
::
get
<
0
>
(
timer_
.
top
())
<=
best_time
)
timer_
.
pop
();
timer_
.
push
(
best
);
timer_
.
push
(
best
);
}
}
}
// if statement on enough models
// else do nothing as there are not enough models to carry out intersection
// or the check engine is shut down until the next time in timer
}
// detailed check
detailed_check
(
t
,
Dt
);
}
struct
Neighbor_finder
{
int
count_
;
element_type
*
el_
;
tree_type
*
tree_
;
class
Comparator
{
public
:
template
<
class
iterator
>
bool
operator
()(
iterator
const
&
a
,
iterator
const
&
b
)
{
return
a
->
first
<
b
->
first
;
}
};
std
::
set
<
leaves_data_iterator
,
Comparator
>
elems_
;
Neighbor_finder
()
:
count_
(),
el_
(
nullptr
),
tree_
(
nullptr
)
{}
UInt
size
()
const
{
return
elems_
.
size
();
}
template
<
class
container
>
void
add_slaves
(
container
&
c
)
{
for
(
auto
it
=
elems_
.
begin
();
it
!=
elems_
.
end
();
++
it
)
{
auto
elem
=
(
*
it
)
->
second
;
for
(
size_t
i
=
0
;
i
<
elem
.
numNodes
();
++
i
)
c
.
insert
(
elem
.
node
(
i
));
}
}
template
<
class
container
>
void
add_masters
(
container
&
c
)
{
for
(
auto
it
=
elems_
.
begin
();
it
!=
elems_
.
end
();
++
it
)
c
.
insert
(
&
(
*
it
)
->
second
);
}
bool
operator
()()
{
assert
(
el_
!=
nullptr
);
return
elems_
.
size
()
==
el_
->
numNodes
()
+
1
;
}
void
operator
()(
tree_iterator
it
)
{
assert
(
tree_
!=
nullptr
);
assert
(
el_
!=
nullptr
);
auto
eit
=
tree_
->
find_data
(
it
);
if
(
eit
!=
tree_
->
leaves_data_end
())
if
(
el_
->
shareNodes
(
eit
->
second
))
elems_
.
insert
(
eit
);
++
count_
;
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Neighbor_finder
&
nf
)
{
os
<<
"Neighbor finder info:"
<<
endl
;
os
<<
" found neighbors in "
<<
nf
.
count_
<<
" evaluations"
<<
endl
;
if
(
nf
.
el_
)
os
<<
" reference element "
<<*
nf
.
el_
<<
endl
;
cout
<<
" neighbors: "
<<
nf
.
size
()
<<
endl
;
for
(
auto
n:
nf
.
elems_
)
os
<<
'\t'
<<
n
->
second
<<
'\n'
;
return
os
;
}
};
void
detailed_check
(
time_type
t
,
time_type
Dt
)
{
constexpr
int
dim
=
point_type
::
dim
();
if
(
contact_
.
size
()
>
0
)
{
// loop over contact structures
for
(
contact_iterator
cit
=
contact_
.
begin
();
cit
!=
contact_
.
end
();
++
cit
)
{
ContactData
&
c
=
const_cast
<
ContactData
&>
(
*
cit
);
typedef
std
::
set
<
element_type
>
elem_list
;
typedef
std
::
pair
<
point_type
,
vector_type
>
closest_type
;
typedef
std
::
tuple
<
UInt
,
Real
,
element_type
,
closest_type
,
elem_list
>
test_type
;
std
::
map
<
UInt
,
test_type
>
map
;
std
::
set
<
UInt
>
checked
;
typename
ContactData
::
elem_set
snew
,
mnew
;
// loop over slave elements to determine slave nodes
for
(
auto
sit:
c
.
ssurface_
)
{
// get slave element
auto
sel
=
sit
->
second
;
auto
sbb
=
sel
.
template
boundingBox
<
dim
>
();
// loop over master elements
for
(
auto
mit:
c
.
msurface_
)
{
auto
mel
=
mit
->
second
;
// tighter check with AABBs
auto
mbb
=
mel
.
template
boundingBox
<
dim
>
();
if
(
!
(
sbb
&
mbb
))
continue
;
// loop over slave nodes
for
(
UInt
i
=
0
;
i
<
sel
.
numNodes
();
++
i
)
{
UInt
s
=
sel
.
node
(
i
);
// treat first element as slave
auto
coord
=
sel
.
coordinates
();
// create point
point_type
p
(
coord
[
i
]);
if
(
!
penetrates
(
p
,
mel
))
{
continue
;
}
else
{
// find node in contact data structure
auto
fslave
=
c
.
slaves_
.
find
(
s
);
// if not found, add it to container and search for new contact elements
if
(
fslave
==
c
.
slaves_
.
end
())
{
c
.
slaves_
.
insert
(
s
);
Neighbor_finder
sc
,
mc
;
sc
.
tree_
=
c
.
stree_
;
mc
.
tree_
=
c
.
mtree_
;
sc
.
el_
=
&
sit
->
second
;
mc
.
el_
=
&
mit
->
second
;
c
.
stree_
->
collect_neighbors
(
sit
->
first
,
sc
);
c
.
mtree_
->
collect_neighbors
(
mit
->
first
,
mc
);
for
(
auto
i:
sc
.
elems_
)
snew
.
insert
(
i
);
for
(
auto
i:
mc
.
elems_
)
mnew
.
insert
(
i
);
}
// compute closest point
closest_type
r
=
closest_point_to_element
(
p
,
mel
);
Real
nd
=
(
p
-
r
.
first
).
sq_norm
();
auto
elit
=
map
.
find
(
s
);
if
(
elit
==
map
.
end
())
{
map
[
s
]
=
test_type
(
i
,
nd
,
sel
,
r
,
elem_list
());
test_type
&
tuple
=
map
[
s
];
std
::
get
<
4
>
(
tuple
).
insert
(
mel
);
}
else
{
auto
tuple
=
map
[
s
];
Real
dist
=
std
::
get
<
1
>
(
tuple
);
element_type
sel
=
std
::
get
<
2
>
(
tuple
);
if
(
std
::
abs
(
nd
-
dist
)
<
1.0e-6
)
{
test_type
&
tuple
=
map
[
s
];
// edit closest point
elem_list
&
els
=
std
::
get
<
4
>
(
tuple
);
els
.
insert
(
mel
);
if
(
els
.
size
()
==
2
)
{
closest_type
&
p
=
std
::
get
<
3
>
(
tuple
);
p
=
commonPonit
<
point_type
>
(
els
);
}
}
else
if
(
nd
<
dist
)
{
map
[
s
]
=
test_type
(
i
,
nd
,
sel
,
r
,
elem_list
());
test_type
&
tuple
=
map
[
s
];
std
::
get
<
4
>
(
tuple
).
insert
(
mel
);
}
}
}
}
// loop over master elements
}
// loop over slave nodes
}
// loop over slave elements to determine slave nodes
// add new elements if found
if
(
!
snew
.
empty
()
||
!
mnew
.
empty
())
{
for
(
auto
s:
snew
)
c
.
ssurface_
.
insert
(
s
);
for
(
auto
m:
mnew
)
c
.
msurface_
.
insert
(
m
);
}
// loop over map to balance slave nodes with closest element
for
(
auto
it
=
map
.
begin
();
it
!=
map
.
end
();
++
it
)
{
UInt
id
=
std
::
get
<
0
>
(
it
->
second
);
element_type
sel
=
std
::
get
<
2
>
(
it
->
second
);
auto
cp
=
std
::
get
<
3
>
(
it
->
second
);
auto
mel
=
std
::
get
<
4
>
(
it
->
second
);
// process slave
auto
el
=
*
mel
.
begin
();
balance
<
point_type
>
(
Dt
,
id
,
cp
,
sel
,
const_cast
<
element_type
&>
(
el
));
}
}
// loop over contact structures
}
// contact_ > 0
// WORKING CODE FOR SINGLE PASS
// if (contact_.size() > 0) {
//
// // loop over contact structures
// for (auto c: contact_) {
//
// typedef std::tuple<UInt, Real, element_type, element_type> test_type;
//
// std::map<UInt, test_type > map;
// std::set<UInt> checked;
//
// typename ContactData::elem_set snew, mnew;
//
// cout<<"------------------------------------------------------------------"<<endl;
// cout<<"slaves -> "<<c.ssurface_.size()<<endl;
// cout<<"masters -> "<<c.msurface_.size()<<endl;
//
// // loop over slave elements to determine slave nodes
// for (auto sit:c.ssurface_) {
//
// // get slave element
// auto sel = sit->second;
// auto sbb = sel.template boundingBox<dim>();
//
// cout<<"sel -> "<<sel<<endl;
//
// // loop over master elements
// for (auto mit:c.msurface_) {
//
// auto mel = mit->second;
// cout<<"mel -> "<<mel<<endl;
//
// // tighter check with AABBs
// auto mbb = mel.template boundingBox<dim>();
// if (!(sbb & mbb)) {
// cout<<"AABBS"<<endl;
// continue;
// }
//
// // loop over slave nodes
// for (UInt i=0; i<sel.numNodes(); ++i) {
//
// UInt s = sel.node(i);
//
// cout<<"***NODE "<<s<<endl;
// cout<<"***MBB -> "<<mbb<<endl;
// cout<<"***MN -> "<<mel.normal()<<endl;
//
// // treat first element as slave
// auto coord = sel.coordinates();
//
// // create point
// point_type p(coord[i]);
//
// if (!penetrates(p,mel)) {
// cout<<">SLAVE GETOUT"<<endl;
// continue;
// } else {
//
//
// // find node in contact data structure
// auto fslave = c.slaves_.find(s);
// // if not found, add it to container and search for new contact elements
// if (fslave == c.slaves_.end()) {
// c.slaves_.insert(s);
//
// cout<<"type of sit -> "<<typeid(sit).name()<<endl;
//
// Neighbor_finder sc, mc;
// sc.tree_ = c.stree_;
// mc.tree_ = c.mtree_;
// sc.el_ = &sit->second;
// mc.el_ = &mit->second;
// c.stree_->collect_neighbors(sit->first, sc);
// c.mtree_->collect_neighbors(mit->first, mc);
//
// for (auto i:sc.elems_)
// snew.insert(i);
// for (auto i:mc.elems_)
// mnew.insert(i);
//
// for (auto i:sc.elems_)
// cout<<i->second;
// for (auto i:mc.elems_)
// cout<<i->second;
// }
//
// cout<<">SLAVE "<<s<<": "<<p<<", with id "<<i<<", belonging to "<<sel<<" PENETRATES"<<endl;
// cout<<"master element "<<mel<<", master bb -> "<<mbb<<endl;
//
// // compute closest point
// std::pair<point_type, vector_type> r = closest_point_to_element(p, mel);
//
// cout<<"r -> "<<r.first<<endl;
//
// Real nd = (p-r.first).sq_norm();
//
// auto elit = map.find(s);
// if (elit == map.end()) {
// cout<<"NO ELEMENT IN MAP"<<endl;
// map[s] = test_type(i, nd, sel, mel);
// }
// else {
// cout<<"ELEMENT IN MAP"<<endl;
// cout<<"stored info in map: ";
//
// auto tuple = map[s];
// UInt id = std::get<0>(tuple);
// Real dist = std::get<1>(tuple);
// element_type sel = std::get<2>(tuple);
// element_type mel = std::get<3>(tuple);
//
// cout<<"id "<<id<<", dist "<<dist<<"slave element "<<sel<<", master el "<<mel<<endl;
//
// cout<<"comparing new distance "<<nd<<" with stored value "<<dist<<endl;
// if (nd < dist) {
// cout<<"new distance smaller, inserting new element"<<endl;
// map[s] = test_type(i, nd, sel, mel);
// } else
// cout<<"new distance is bigger!"<<endl;
// }
//
// }
//
// } // loop over master elements
//
//
// } // loop over slave nodes
// } // loop over slave elements to determine slave nodes
//
// // add new elements if found
// if (!snew.empty() || !mnew.empty()) {
// for (auto s:snew)
// c.ssurface_.insert(s);
// for (auto m:mnew)
// c.msurface_.insert(m);
// }
//
//
// // loop over map to balance slave nodes with closest element
// for (auto it = map.begin(); it != map.end(); ++it) {
//
// UInt id = std::get<0>(it->second);
// element_type sel = std::get<2>(it->second);
// element_type mel = std::get<3>(it->second);
//
// cout<<"balance node with id -> "<<id<<" in slave element "<<sel<<endl;
// cout<<"master el -> "<<mel<<endl;
//
// // process slave
// balance<point_type>(Dt, id, sel, mel);
//
// }
// } // loop over contact structures
// } // contact_ > 0
}
template
<
class
contact_type
,
class
bbox_type
,
class
slave_container
>
void
solve_contact
(
time_type
Dt
,
contact_type
&
c1
,
contact_type
&
c2
,
const
bbox_type
&
bb
,
slave_container
&
slaves
)
{
// treat first element as slave
auto
coord
=
c1
.
coordinates
();
int
slave
=
0
;
for
(
const
double
*
c:
coord
)
{
// create point
point_type
p
(
c
);
// if point lies outside of collision zone, continue
if
(
!
(
bb
&
p
))
{
++
slave
;
continue
;
}
UInt
id
=
c1
.
node
(
slave
);
auto
it
=
slaves
.
find
(
id
);
if
(
it
!=
slaves
.
end
())
continue
;
slaves
.
insert
(
id
);
// else find closest distance from p to contacting element c2
std
::
pair
<
point_type
,
vector_type
>
r
=
closest_point_to_element
(
p
,
c2
);
const
point_type
&
q
=
r
.
first
;
const
vector_type
&
n
=
r
.
second
;
// get distance from current position
Real
delta
=
sqrt
((
q
-
p
).
sq_norm
());
auto
mass
=
c1
.
getMass
(
slave
)[
0
];
// compute force at slave node
vector_type
N
=
2
*
delta
*
mass
/
pow
(
Dt
,
2.
)
*
n
;
// compute forces in master element balancing linear and angular momenta
balance
(
Dt
,
slave
,
r
,
N
,
c1
,
c2
);
++
slave
;
}
}
private
:
template
<
class
iterator
>
void
traverse_right
(
iterator
it1
,
iterator
it2
,
hierarchy_timer
&
pq
)
{
#ifdef DEBUG_MANAGER
cout
<<
" traversing right hierarchy"
<<
endl
;
#endif
iterator
lit
=
it2
.
left
();
iterator
rit
=
it2
.
right
();
assert
(
lit
!=
null_
);
assert
(
rit
!=
null_
);
time_type
tstar1
=
resolve_time
(
it1
,
lit
);
if
(
tstar1
!=
inf
)
{
#ifdef DEBUG_MANAGER
cout
<<
" Adding queue time "
<<
tstar1
<<
endl
;
#endif
pq
.
push
(
std
::
make_tuple
(
tstar1
,
it1
,
lit
));
}
time_type
tstar2
=
resolve_time
(
it1
,
rit
);
if
(
tstar2
!=
inf
)
{
#ifdef DEBUG_MANAGER
cout
<<
" Adding queue time "
<<
tstar2
<<
endl
;
#endif
pq
.
push
(
std
::
make_tuple
(
tstar2
,
it1
,
rit
));
}
}
template
<
class
iterator
>
void
traverse_left
(
iterator
it1
,
iterator
it2
,
hierarchy_timer
&
pq
)
{
#ifdef DEBUG_MANAGER
cout
<<
" traversing left hierarchy"
<<
endl
;
#endif
iterator
lit
=
it1
.
left
();
iterator
rit
=
it1
.
right
();
assert
(
lit
!=
null_
);
assert
(
rit
!=
null_
);
time_type
tstar1
=
resolve_time
(
lit
,
it2
);
if
(
tstar1
!=
inf
)
{
#ifdef DEBUG_MANAGER
cout
<<
" Adding queue time "
<<
tstar1
<<
endl
;
#endif
pq
.
push
(
std
::
make_tuple
(
tstar1
,
lit
,
it2
));
}
time_type
tstar2
=
resolve_time
(
rit
,
it2
);
if
(
tstar2
!=
inf
)
{
#ifdef DEBUG_MANAGER
cout
<<
" Adding queue time "
<<
tstar2
<<
endl
;
#endif
pq
.
push
(
std
::
make_tuple
(
tstar2
,
rit
,
it2
));
}
}
template
<
class
iterator
>
void
check_collision
(
time_type
t
,
iterator
it1
,
iterator
it2
,
hierarchy_timer
&
pq
)
{
// if volumes are leaves, change the timer and time step
if
(
it1
.
is_leaf
()
&&
it2
.
is_leaf
())
{
cout
<<
"*** FOUND LEAVES ***"
<<
endl
;
// case where objects intersect
if
(
*
it1
&
*
it2
)
{
cout
<<
"*** BOUNDING SPHERE INTERSECTION ***"
<<
endl
;
// add leaves to carry out penetration tests
leaves_data_iterator
lit1
(
nullptr
),
lit2
(
nullptr
);
Neighbor_finder
lc
,
rc
;
for
(
forest_iterator
it
=
forest_
.
begin
();
it
!=
forest_
.
end
();
++
it
)
{
leaves_data_iterator
lit
=
(
*
it
)
->
find_data
(
it1
);
if
(
lit
!=
(
*
it
)
->
leaves_data_end
())
{
lit1
=
lit
;
lc
.
tree_
=
*
it
;
lc
.
el_
=
&
lit
->
second
;
(
*
it
)
->
collect_neighbors
(
lit
->
first
,
lc
);
}
lit
=
(
*
it
)
->
find_data
(
it2
);
if
(
lit
!=
(
*
it
)
->
leaves_data_end
())
{
lit2
=
lit
;
rc
.
tree_
=
*
it
;
rc
.
el_
=
&
lit
->
second
;
(
*
it
)
->
collect_neighbors
(
lit
->
first
,
rc
);
}
}
assert
(
lit1
!=
leaves_data_iterator
(
nullptr
));
assert
(
lit2
!=
leaves_data_iterator
(
nullptr
));
// check for new ContactData
auto
ins
=
contact_
.
insert
(
ContactData
(
lit1
,
lit2
));
if
(
ins
.
second
)
{
auto
cd
=
ins
.
first
;
cd
->
initialize
(
lc
,
rc
);
cout
<<
"*** INFO *** Adding contact data."
<<
endl
;
}
else
{
cout
<<
"*** WARNING *** Contact data not inserted."
<<
endl
;
}
// add to data structure for detailed check
detailed_
.
insert
(
std
::
make_pair
(
lit1
,
lit2
));
detect_
=
false
;
cout
<<
"***DETAILED SIZE -> "
<<
detailed_
.
size
()
<<
endl
;
}
else
cout
<<
"*** NO INTERSECTION BETWEEN BOUNDING SPHERES ***"
<<
endl
;
time_type
tstar
=
resolve_time
(
it1
,
it2
);
#ifdef DEBUG_MANAGER
if
(
tstar
==
inf
)
cout
<<
" Leaves found that DO NOT collide"
<<
endl
;
else
{
cout
<<
" Leaves found that collide at time "
<<
(
tstar
)
<<
endl
;
}
#endif
if
(
tstar
==
inf
)
{
cout
<<
" Leaves found that DO NOT collide"
<<
endl
;
}
throw
Continuator
(
std
::
make_tuple
(
tstar
,
it1
,
it2
));
}
// found left leaf, traverse right hierarchy
else
if
(
it1
.
is_leaf
()
&&
!
it2
.
is_leaf
())
{
#ifdef DEBUG_MANAGER
cout
<<
" s1 is leaf"
<<
endl
;
#endif
traverse_right
(
it1
,
it2
,
pq
);
}
// found right leaf, traverse left hierarchy
else
if
(
!
it1
.
is_leaf
()
&&
it2
.
is_leaf
())
{
#ifdef DEBUG_MANAGER
cout
<<
" s2 is leaf"
<<
endl
;
#endif
traverse_left
(
it1
,
it2
,
pq
);
}
// else non-leaf case found, check volume sizes
else
{
value_type
m1
=
it1
->
measure
();
value_type
m2
=
it2
->
measure
();
// volumes are equal to numerical error, traverse both hierarchies
if
(
equal
(
m1
,
m2
))
{
#ifdef DEBUG_MANAGER
cout
<<
" "
<<
m1
<<
" == "
<<
m2
<<
endl
;
#endif
traverse_right
(
it1
,
it2
,
pq
);
traverse_left
(
it1
,
it2
,
pq
);
}
// left volume is bigger, traverse right hierarchy
else
if
(
m1
>
m2
)
{
#ifdef DEBUG_MANAGER
cout
<<
" "
<<
m1
<<
" > "
<<
m2
<<
endl
;
#endif
traverse_left
(
it1
,
it2
,
pq
);
}
// right volume is bigger, traverse left hierarchy
else
if
(
m1
<
m2
)
{
#ifdef DEBUG_MANAGER
cout
<<
" "
<<
m1
<<
" < "
<<
m2
<<
endl
;
#endif
traverse_right
(
it1
,
it2
,
pq
);
}
}
// non-leaf case
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Contact0_model_manager
&
mm
)
{
os
<<
"Contact model manager info:"
<<
endl
;
os
<<
" models: "
<<
mm
.
models_
.
size
()
<<
endl
;
size_t
i
=
0
;
const_forest_iterator
tit
=
mm
.
forest_
.
begin
();
for
(
const_model_iterator
it
=
mm
.
models_
.
begin
();
it
!=
mm
.
models_
.
end
();
++
it
)
{
os
<<
"
\t
model "
<<++
i
<<
" memory address: "
<<*
it
<<
endl
;
os
<<
"
\t
model: "
<<**
it
<<
endl
;
os
<<
"
\t
tree: "
;
print_mathematica
(
**
tit
++
);
}
return
os
;
}
};
__END_AKANTU__
#endif
/* __AKANTU_CONTACT_MANAGER_0_HH__ */
Event Timeline
Log In to Comment