Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F64670074
component_libmultiscale.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
Tue, May 28, 14:18
Size
33 KB
Mime Type
text/x-c++
Expires
Thu, May 30, 14:18 (2 d)
Engine
blob
Format
Raw Data
Handle
17942040
Attached To
rLIBMULTISCALE LibMultiScale
component_libmultiscale.hh
View Options
/**
* @file component_libmultiscale.hh
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Mon Sep 08 23:40:22 2014
*
* @brief This describe the root objects to be combined into valid LM
* components
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale 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.
*
* LibMultiScale 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 LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
#define __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
/* -------------------------------------------------------------------------- */
#include "container.hh"
#include "lm_common.hh"
#include "lm_object.hh"
#include "static_dispatch.hh"
/* -------------------------------------------------------------------------- */
#include <cmath>
#include <limits>
#include <map>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <typeindex>
#include <typeinfo>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
namespace
detail
{
template
<
int
I
>
struct
foreach_tuple_impl
{
template
<
class
F
,
class
Tuple
>
static
void
doIt
(
F
&&
f
,
Tuple
&&
t
)
{
f
(
std
::
get
<
I
>
(
std
::
forward
<
Tuple
>
(
t
)));
foreach_tuple_impl
<
I
-
1
>::
doIt
(
f
,
t
);
}
};
template
<>
struct
foreach_tuple_impl
<-
1
>
{
template
<
class
F
,
class
Tuple
>
static
void
doIt
(
F
&&
,
Tuple
&&
)
{}
};
}
// namespace detail
template
<
class
F
,
class
Tuple
>
constexpr
decltype
(
auto
)
foreach_tuple
(
F
&&
f
,
Tuple
&&
t
)
{
detail
::
foreach_tuple_impl
<
std
::
tuple_size
<
std
::
remove_reference_t
<
std
::
remove_pointer_t
<
Tuple
>>>::
value
-
1
>::
doIt
(
std
::
forward
<
F
>
(
f
),
std
::
forward
<
Tuple
>
(
t
));
}
/* -------------------------------------------------------------------------- */
class
ContainerInterface
;
template
<
typename
T
>
class
ContainerArray
;
template
<
typename
Tuple
>
struct
getFirstArgument
{
// this is a non used case....
// static int get(Tuple &) { return 10; };
};
template
<
typename
T
>
struct
getFirstArgument
<
std
::
tuple
<
T
>>
{
static
auto
&
get
(
std
::
tuple
<
T
>
&
tuple
)
{
return
std
::
get
<
0
>
(
tuple
);
}
};
/* -------------------------------------------------------------------------- */
class
ReleasedObject
{
public
:
ReleasedObject
()
{
release
=
0
;
}
//! return actual release
UInt
getRelease
()
const
{
return
release
;
};
//! return actual release
void
setRelease
(
UInt
r
)
{
release
=
r
;
};
//! increment the release
void
incRelease
()
{
++
release
;
};
template
<
typename
Dependencies
>
void
acquireRelease
(
const
Dependencies
&
deps
)
{
for
(
auto
&
pair
:
deps
)
{
auto
*
ptr
=
pair
.
second
;
if
(
ptr
==
nullptr
)
LM_FATAL
(
pair
.
first
<<
": input was not created/computed/connected"
);
release
=
std
::
max
(
release
,
(
*
ptr
)
->
getRelease
());
}
}
template
<
typename
Dependencies
>
bool
checkDependency
(
const
Dependencies
&
deps
)
{
for
(
auto
&
pair
:
deps
)
{
if
(
pair
.
second
==
nullptr
)
return
true
;
try
{
if
(
!
pair
.
second
->
isAllocated
())
return
true
;
auto
&
dep
=
pair
.
second
->
get
();
if
(
release
<
dep
.
getRelease
())
return
true
;
}
catch
(...)
{
return
true
;
}
}
return
false
;
}
private
:
UInt
release
;
};
struct
ArgumentInterface
:
public
ReleasedObject
{
ArgumentInterface
(){};
virtual
~
ArgumentInterface
(){};
virtual
std
::
type_index
get_type_index
()
const
=
0
;
virtual
std
::
string
get_type_info
()
const
=
0
;
template
<
typename
T
>
T
&
cast
();
virtual
void
printself
(
std
::
ostream
&
os
)
const
=
0
;
virtual
void
_copyContainerInfo
(
ContainerInterface
&
c
)
=
0
;
virtual
void
setCommGroup
(
CommGroup
&
c
)
=
0
;
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ArgumentInterface
&
a
)
{
a
.
printself
(
os
);
return
os
;
}
template
<
typename
T1
>
std
::
enable_if_t
<
std
::
is_base_of
<
ContainerInterface
,
std
::
decay_t
<
T1
>>::
value
>
_copyContainerInfo_casted
(
T1
&
value
,
ContainerInterface
&
a
)
{
value
.
copyContainerInfo
(
a
);
}
template
<
typename
T1
>
std
::
enable_if_t
<!
std
::
is_base_of
<
ContainerInterface
,
std
::
decay_t
<
T1
>>::
value
>
_copyContainerInfo_casted
(
T1
&
,
ContainerInterface
&
)
{}
template
<
typename
T1
>
void
_copyContainerInfo_casted
(
std
::
shared_ptr
<
T1
>
value
,
ContainerInterface
&
a
)
{
T1
&
v
=
*
value
;
_copyContainerInfo_casted
<
T1
>
(
v
,
a
);
}
template
<
typename
T1
>
std
::
enable_if_t
<
std
::
is_base_of
<
LMObject
,
std
::
decay_t
<
T1
>>::
value
>
_setCommGroup
(
T1
&
value
,
CommGroup
&
c
)
{
value
.
setCommGroup
(
c
);
}
template
<
typename
T1
>
std
::
enable_if_t
<!
std
::
is_base_of
<
LMObject
,
std
::
decay_t
<
T1
>>::
value
>
_setCommGroup
(
T1
&
,
CommGroup
&
)
{}
template
<
typename
T1
>
void
_setCommGroup
(
std
::
shared_ptr
<
T1
>
value
,
CommGroup
&
comm_group
)
{
T1
&
v
=
*
value
;
_setCommGroup
(
v
,
comm_group
);
}
template
<
typename
T
>
struct
Argument
:
public
ArgumentInterface
{
void
_copyContainerInfo
(
ContainerInterface
&
c
)
override
{
_copyContainerInfo_casted
(
value
,
c
);
};
virtual
void
setCommGroup
(
CommGroup
&
c
)
override
{
_setCommGroup
(
value
,
c
);
};
Argument
(
Argument
&&
arg
)
=
default
;
Argument
(
T
&&
val
)
:
value
(
std
::
forward
<
T
>
(
val
))
{}
inline
void
printself
(
std
::
ostream
&
os
)
const
override
{
const
T
&
temp
=
this
->
value
;
os
<<
"("
<<
this
<<
")"
<<
this
->
get_type_info
()
<<
" : "
<<
" "
<<
&
temp
;
}
const
std
::
type_index
type_index
=
typeid
(
T
);
inline
std
::
type_index
get_type_index
()
const
override
{
return
type_index
;
};
inline
std
::
string
get_type_info
()
const
override
{
return
typeinfo
<
T
>
();
};
inline
virtual
T
&
get
()
{
return
value
;
};
T
value
;
};
template
<
typename
T
>
T
&
ArgumentInterface
::
cast
()
{
auto
ptr1
=
dynamic_cast
<
Argument
<
T
>
*>
(
this
);
auto
ptr2
=
dynamic_cast
<
Argument
<
T
&>
*>
(
this
);
auto
ptr3
=
dynamic_cast
<
Argument
<
std
::
shared_ptr
<
T
>>
*>
(
this
);
if
(
ptr1
==
nullptr
&&
ptr2
==
nullptr
&&
ptr3
==
nullptr
)
{
LM_FATAL
(
"cannot cast argument from "
<<
this
->
get_type_info
()
<<
" into "
<<
typeinfo
<
T
>
());
}
if
(
ptr1
)
return
ptr1
->
get
();
if
(
ptr2
)
return
ptr2
->
get
();
return
*
ptr3
->
get
();
}
class
Component
;
class
ArgumentContainer
{
public
:
ArgumentContainer
()
:
component
(
nullptr
),
ptr
(
nullptr
){};
ArgumentContainer
(
Component
&
component
)
:
component
(
&
component
),
ptr
(
nullptr
){};
ArgumentContainer
(
ArgumentContainer
&&
other
)
=
default
;
ArgumentInterface
*
operator
->
()
{
return
&
this
->
get
();
}
ArgumentInterface
&
operator
*
()
{
return
this
->
get
();
}
template
<
typename
T
>
ArgumentContainer
&
operator
=
(
Argument
<
T
>
&&
val
)
{
if
(
ptr_allocated
.
get
()
!=
nullptr
)
ptr_allocated
.
release
();
ptr_allocated
=
std
::
make_unique
<
Argument
<
T
>>
(
std
::
forward
<
decltype
(
val
)
>
(
val
));
ptr
=
ptr_allocated
.
get
();
return
*
this
;
}
UInt
getRelease
()
{
return
ptr
->
getRelease
();
}
void
setRelease
(
UInt
release
)
{
ptr
->
setRelease
(
release
);
}
ArgumentContainer
&
operator
=
(
ArgumentContainer
&&
arg
)
=
default
;
ArgumentContainer
&
operator
=
(
const
ArgumentContainer
&
arg
)
{
if
(
ptr_allocated
.
get
()
!=
nullptr
)
ptr_allocated
.
release
();
ptr
=
arg
.
ptr
;
return
*
this
;
}
inline
ArgumentInterface
&
get
(
bool
eval
=
true
);
inline
const
ArgumentInterface
&
get
()
const
;
inline
bool
isAllocated
();
private
:
Component
*
component
;
ArgumentInterface
*
ptr
;
std
::
unique_ptr
<
ArgumentInterface
>
ptr_allocated
;
public
:
class
UnallocatedPointer
:
public
std
::
exception
{};
};
template
<
typename
T
>
Argument
<
T
>
make_argument
(
T
&&
val
)
{
return
Argument
<
T
>
(
std
::
forward
<
T
>
(
val
));
}
/* --------------------------------------------------------------------- */
class
Component
:
public
ReleasedObject
,
public
virtual
LMObject
{
public
:
Component
()
:
me_as_argument
(
*
this
),
calculated_once
(
false
),
comm_group
(
nullptr
)
{
me_as_argument
=
make_argument
(
*
this
);
}
virtual
~
Component
(){};
//! set the communication group
virtual
void
setCommGroup
(
CommGroup
&
group
)
{
comm_group
=
&
group
;
};
template
<
typename
T
>
void
connect
(
const
std
::
string
&
input
,
Argument
<
T
>
&&
arg
);
inline
void
connect
(
const
std
::
string
&
input
,
ArgumentContainer
&
arg
);
template
<
typename
...
Args
>
inline
void
setInput
(
Args
&&
...
args
)
{
auto
tup
=
std
::
forward_as_tuple
(
args
...);
int
cpt
=
0
;
std
::
vector
<
std
::
string
>
keys
;
std
::
for_each
(
inputs
.
begin
(),
inputs
.
end
(),
[
&
keys
](
auto
key
)
{
keys
.
push_back
(
key
.
first
);
});
auto
f
=
[
&
](
auto
&
arg
)
{
auto
key
=
keys
[
cpt
];
auto
search
=
inputs
.
find
(
key
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
key
+
": input not existing"
);
}
if
(
this
->
inputs
[
key
]
==
nullptr
)
this
->
inputs
[
key
]
=
new
ArgumentContainer
();
*
this
->
inputs
[
key
]
=
make_argument
(
arg
);
++
cpt
;
};
apply
(
f
,
tup
);
}
inline
ArgumentContainer
*
allocInput
(
const
std
::
string
&
input
);
inline
void
createOutput
(
const
std
::
string
&
output
);
inline
void
createInput
(
const
std
::
string
&
input
);
inline
void
removeInput
(
const
std
::
string
&
input
);
inline
bool
isConnected
(
const
std
::
string
&
input
);
virtual
void
compute
();
template
<
typename
...
Args
>
void
buildManual
(
Args
&&
...
args
)
{
this
->
setInput
(
args
...);
this
->
compute_make_call
();
calculated_once
=
true
;
}
template
<
typename
T
>
std
::
enable_if_t
<
std
::
is_base_of
<
ContainerInterface
,
T
>::
value
>
_copyContainerInfo
(
T
&
a
)
{
for
(
auto
&
output
:
this
->
outputs
)
{
auto
&
o
=
output
.
second
.
get
(
false
);
o
.
_copyContainerInfo
(
a
);
}
}
template
<
typename
T
>
std
::
enable_if_t
<
not
std
::
is_base_of
<
ContainerInterface
,
T
>::
value
>
_copyContainerInfo
(
T
&
)
{}
virtual
void
compute_make_call
()
=
0
;
inline
ArgumentContainer
&
getInput
(
const
std
::
string
&
requested_input
=
""
)
{
std
::
string
input
=
requested_input
;
if
(
input
==
""
)
{
if
(
this
->
inputs
.
size
()
==
0
)
{
LM_FATAL
(
"There is no input for "
<<
this
->
getID
());
}
else
if
(
this
->
inputs
.
size
()
!=
1
)
{
std
::
string
mesg
=
this
->
getID
()
+
" has several inputs: need a name"
;
mesg
+=
"
\n\n
Possible names:
\n\n
"
;
for
(
auto
&&
pair
:
this
->
inputs
)
{
mesg
+=
"
\t
"
+
pair
.
first
+
"
\n
"
;
}
LM_FATAL
(
mesg
);
}
input
=
this
->
inputs
.
begin
()
->
first
;
}
else
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
input
+
": input not existing"
);
}
}
ArgumentContainer
*
arg_cont_input
=
inputs
[
input
];
if
(
arg_cont_input
==
nullptr
)
throw
UnconnectedInput
{
"For component '"
+
this
->
getID
()
+
"' input '"
+
input
+
"' is not connected"
};
return
*
arg_cont_input
;
}
inline
auto
&
getOutputs
()
{
return
outputs
;
}
inline
auto
&
getInputs
()
{
return
inputs
;
}
inline
ArgumentContainer
&
getOutput
(
const
std
::
string
&
output_name
=
""
)
{
auto
name
=
output_name
;
if
(
name
==
""
)
{
if
(
this
->
outputs
.
size
()
==
0
)
{
LM_FATAL
(
"There is no output for "
<<
this
->
getID
());
}
else
if
(
this
->
outputs
.
size
()
!=
1
)
{
std
::
string
mesg
=
this
->
getID
()
+
" has several outputs: need a name"
;
mesg
+=
"
\n\n
Possible names:
\n\n
"
;
for
(
auto
&&
pair
:
this
->
outputs
)
{
mesg
+=
"
\t
"
+
pair
.
first
+
"
\n
"
;
}
LM_FATAL
(
mesg
);
}
name
=
this
->
outputs
.
begin
()
->
first
;
}
auto
search
=
outputs
.
find
(
name
);
if
(
search
==
outputs
.
end
())
{
std
::
string
mesg
=
this
->
getID
()
+
":"
+
name
+
": output not existing"
;
mesg
+=
"
\n\n
Possible names:
\n\n
"
;
for
(
auto
&&
pair
:
this
->
outputs
)
{
mesg
+=
"
\t
"
+
pair
.
first
+
"
\n
"
;
}
LM_FATAL
(
mesg
);
}
return
outputs
[
name
];
};
template
<
typename
Cont
>
auto
&
getCastedOutput
(
const
std
::
string
&
output_name
,
bool
eval
=
true
)
{
auto
&
arg
=
this
->
getOutput
(
output_name
).
get
(
eval
);
return
arg
.
cast
<
Cont
>
();
}
template
<
typename
Cont
,
typename
...
T
>
auto
&
allocAndGetCastedOutput
(
const
std
::
string
&
output_name
,
T
&&
...
construction_parameters
)
{
using
type
=
typename
Cont
::
ContainerSubset
;
using
ptr_type
=
std
::
shared_ptr
<
type
>
;
try
{
this
->
getCastedOutput
<
ptr_type
>
(
output_name
,
false
);
}
catch
(
ArgumentContainer
::
UnallocatedPointer
&
e
)
{
this
->
getOutput
(
output_name
)
=
make_argument
(
std
::
make_shared
<
type
>
(
construction_parameters
...));
}
auto
&
output
=
*
getCastedOutput
<
ptr_type
>
(
output_name
,
false
);
return
output
;
}
inline
void
printself
(
std
::
ostream
&
os
)
const
;
void
clear_inputs
()
{
inputs
.
clear
();
}
struct
UnconnectedInput
:
public
std
::
runtime_error
{
using
std
::
runtime_error
::
runtime_error
;
};
struct
NotInCommGroup
:
public
std
::
runtime_error
{
using
std
::
runtime_error
::
runtime_error
;
};
ArgumentContainer
&
toArgContainer
()
{
return
me_as_argument
;
}
template
<
typename
T
=
Real
>
ContainerArray
<
T
>
&
getArray
(
const
std
::
string
&
output_name
=
""
)
{
return
this
->
getCastedOutput
<
ContainerArray
<
T
>>
(
output_name
,
false
);
}
template
<
typename
Names
>
void
createArrayOutputs
(
Names
&&
output_names
)
{
for
(
auto
&&
f
:
output_names
)
{
this
->
createArrayOutput
(
f
);
}
}
template
<
typename
T
=
Real
>
void
createArrayOutput
(
const
std
::
string
&
name
)
{
this
->
createOutput
(
name
);
this
->
getOutput
(
name
)
=
make_argument
(
ContainerArray
<
T
>
(
this
->
getID
()
+
":"
+
name
));
}
private
:
ArgumentContainer
me_as_argument
;
friend
class
ActionInterface
;
std
::
map
<
std
::
string
,
ArgumentContainer
*>
inputs
;
std
::
map
<
std
::
string
,
ArgumentContainer
>
outputs
;
std
::
map
<
std
::
string
,
std
::
unique_ptr
<
ArgumentContainer
>>
allocated_inputs
;
bool
calculated_once
;
CommGroup
*
comm_group
;
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Component
&
comp
)
{
comp
.
printself
(
os
);
return
os
;
}
void
Component
::
printself
(
std
::
ostream
&
os
)
const
{
for
(
auto
&
pair
:
this
->
inputs
)
{
os
<<
"input "
<<
pair
.
first
<<
":"
;
if
(
pair
.
second
!=
nullptr
)
os
<<
pair
.
second
->
get
()
<<
"
\n
"
;
else
os
<<
"not yet defined/computed
\n
"
;
}
for
(
auto
&
pair
:
this
->
outputs
)
{
os
<<
"output "
<<
pair
.
first
<<
":"
;
try
{
os
<<
pair
.
second
.
get
()
<<
"
\n
"
;
}
catch
(...)
{
os
<<
"not yet defined/computed
\n
"
;
}
}
}
void
Component
::
connect
(
const
std
::
string
&
input
,
ArgumentContainer
&
arg
)
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
typeinfo
<
decltype
(
*
this
)
>
()
+
":"
+
input
+
": input not existing"
);
}
inputs
[
input
]
=
&
arg
;
}
template
<
typename
T
>
void
Component
::
connect
(
const
std
::
string
&
input
,
Argument
<
T
>
&&
arg
)
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
typeinfo
<
decltype
(
*
this
)
>
()
+
":"
+
input
+
": input not existing"
);
}
if
(
inputs
[
input
]
==
nullptr
)
{
inputs
[
input
]
=
allocInput
(
input
);
}
*
inputs
[
input
]
=
std
::
move
(
arg
);
}
ArgumentContainer
*
Component
::
allocInput
(
const
std
::
string
&
input
)
{
allocated_inputs
[
input
]
=
std
::
make_unique
<
ArgumentContainer
>
();
return
allocated_inputs
[
input
].
get
();
}
void
Component
::
createOutput
(
const
std
::
string
&
output
)
{
outputs
[
output
]
=
ArgumentContainer
(
*
this
);
}
void
Component
::
createInput
(
const
std
::
string
&
input
)
{
inputs
[
input
]
=
nullptr
;
}
void
Component
::
removeInput
(
const
std
::
string
&
input
)
{
inputs
.
erase
(
input
);
}
bool
Component
::
isConnected
(
const
std
::
string
&
input
)
{
return
inputs
.
count
(
input
)
>
0
&&
inputs
[
input
]
!=
nullptr
;
}
/* --------------------------------------------------------------------- */
bool
ArgumentContainer
::
isAllocated
()
{
return
this
->
ptr
!=
nullptr
;
}
/* --------------------------------------------------------------------- */
ArgumentInterface
&
ArgumentContainer
::
get
(
bool
eval
)
{
if
(
this
->
component
!=
nullptr
&&
eval
)
{
this
->
component
->
compute
();
}
if
(
ptr
==
nullptr
)
throw
UnallocatedPointer
{};
return
*
ptr
;
}
/* --------------------------------------------------------------------- */
const
ArgumentInterface
&
ArgumentContainer
::
get
()
const
{
if
(
ptr
==
nullptr
)
LM_FATAL
(
"unallocated pointer"
);
return
*
ptr
;
}
/* --------------------------------------------------------------------- */
template
<
typename
type
>
inline
std
::
enable_if_t
<
not
std
::
is_abstract
<
type
>::
value
,
type
*>
cast_to_obj
(
ArgumentInterface
&
arg_gotten
)
{
if
(
auto
*
ref
=
dynamic_cast
<
Argument
<
type
>
*>
(
&
arg_gotten
))
{
return
&
(
ref
->
get
());
}
return
nullptr
;
}
template
<
typename
type
>
inline
std
::
enable_if_t
<
std
::
is_abstract
<
type
>::
value
,
type
*>
cast_to_obj
(
ArgumentInterface
&
)
{
return
nullptr
;
}
// template <typename possible_types, int n> struct _cpp_dynamic_cast {
// template <typename Functor, typename Arg>
// static void cast(Functor &func, Arg &arg) {
// using _type = std::remove_pointer_t<
// std::decay_t<std::tuple_element_t<n, possible_types>>>;
// // std::cout << "testing type " << demangle(typeid(_type).name()) <<
// // std::endl;
// ArgumentInterface &arg_gotten = arg->get();
// // std::cout << "with object " << arg_gotten << std::endl;
// if (cast_to_obj<_type>(arg_gotten, func)) {
// return;
// }
// if (cast_to_obj<_type &>(arg_gotten, func)) {
// return;
// }
// if (auto *ref =
// dynamic_cast<Argument<std::shared_ptr<_type>> *>(&arg_gotten)) {
// func(*(ref->get()));
// return;
// }
// _cpp_dynamic_cast<possible_types, n - 1>::cast(func, arg);
// }
// };
struct
ImpossibleCast
:
public
std
::
runtime_error
{
ImpossibleCast
(
ArgumentContainer
&
arg
)
:
std
::
runtime_error
(
"cannot cast component with type : "
+
arg
.
get
().
get_type_info
()),
arg
(
arg
)
{}
// std::cerr << typeid(Arg).name() << " " << arg << std::endl;
ArgumentContainer
&
arg
;
};
// template <typename possible_types>
// struct _cpp_dynamic_cast<possible_types, -1> {
// template <typename Functor, typename Arg>
// static void cast(Functor &, Arg &arg) {
// throw ImpossibleCast(*arg);
// }
// };
// template <typename possible_types, typename Functor, typename Arg>
// void cpp_dynamic_cast(Functor &func, Arg &arg) {
// constexpr size_t N = std::tuple_size<possible_types>::value;
// _cpp_dynamic_cast<possible_types, N - 1>::cast(func, arg);
// }
/* --------------------------------------------------------------------- */
// template <template <typename> class TransformClass, typename... T>
// struct apply_type_transform {};
// template <template <typename> class TransformClass, typename... Ts>
// struct apply_type_transform<TransformClass, std::tuple<Ts...>> {
// using type = std::tuple<typename TransformClass<Ts>::type...>;
// };
// template <template <typename> class TransformClass, typename... T>
// using apply_type_transform_t =
// typename apply_type_transform<TransformClass, T...>::type;
/* --------------------------------------------------------------------- */
template
<
class
,
class
>
struct
tuple_cat
;
template
<
class
...
First
,
class
...
Second
>
struct
tuple_cat
<
std
::
tuple
<
First
...
>
,
std
::
tuple
<
Second
...
>>
{
using
type
=
std
::
tuple
<
First
...,
Second
...
>
;
};
/* --------------------------------------------------------------------- */
template
<
typename
T
>
struct
_expand_type
{
using
types
=
std
::
tuple
<
T
>
;
};
/* --------------------------------------------------------------------- */
template
<
int
n
,
typename
T
>
struct
_expand_types
{
using
_type
=
std
::
decay_t
<
std
::
tuple_element_t
<
n
,
T
>>
;
using
type_head
=
typename
_expand_type
<
_type
>::
types
;
using
types_tail
=
typename
_expand_types
<
n
-
1
,
T
>::
types
;
using
types
=
typename
tuple_cat
<
type_head
,
types_tail
>::
type
;
};
template
<
typename
T
>
struct
_expand_types
<
0
,
T
>
{
using
_type
=
std
::
decay_t
<
std
::
tuple_element_t
<
0
,
T
>>
;
using
types
=
typename
_expand_type
<
_type
>::
types
;
};
template
<
typename
T
>
struct
expand_types
{
static
constexpr
int
n
=
std
::
tuple_size
<
T
>::
value
;
using
types
=
typename
_expand_types
<
n
-
1
,
T
>::
types
;
};
/* --------------------------------------------------------------------- */
template
<
int
n
,
typename
possible_types
>
struct
_get_possible_types
{
using
_types
=
std
::
tuple_element_t
<
n
,
possible_types
>
;
using
types_tail
=
std
::
tuple
<
typename
expand_types
<
_types
>::
types
>
;
using
types_head
=
typename
_get_possible_types
<
n
-
1
,
possible_types
>::
types
;
using
types
=
typename
tuple_cat
<
types_head
,
types_tail
>::
type
;
};
template
<
typename
T
>
struct
_get_possible_types
<
0
,
T
>
{
using
_types
=
std
::
tuple_element_t
<
0
,
T
>
;
using
types
=
std
::
tuple
<
typename
expand_types
<
_types
>::
types
>
;
};
template
<
typename
T
>
struct
get_possible_types
{
static
constexpr
int
n
=
std
::
tuple_size
<
T
>::
value
;
using
types
=
typename
_get_possible_types
<
n
-
1
,
T
>::
types
;
};
/* --------------------------------------------------------------------- */
// template <int n, typename tuple_type, typename tuple_type_casted>
// struct CallCast {
// template <typename Obj, typename Functor>
// static void call_compute(Obj &obj, Functor &functor, tuple_type args,
// tuple_type_casted args_casted) {
// auto possible_types =
// get_possible_types<typename Obj::get_possible_types>();
// auto argn = std::get<n>(args);
// // functor that will be called after the dynamic cast is resolved
// auto &&func_cast = [&](auto &&casted_object) {
// auto tup = std::forward_as_tuple(casted_object);
// auto new_args_casted = std::tuple_cat(tup, args_casted);
// CallCast<n - 1, decltype(args),
// decltype(new_args_casted)>::call_compute(
// obj, functor, args, new_args_casted);
// };
// using RawPossibleTypes =
// apply_type_transform_t<std::remove_pointer,
// decltype(possible_types)>;
// try {
// cpp_dynamic_cast<RawPossibleTypes>(func_cast, argn);
// } catch (ImpossibleCast &exception) {
// auto type_info = exception.arg.get().get_type_info();
// std::stringstream sstr;
// sstr << "Component " << obj.getID() << "(" << typeinfo<decltype(obj)>()
// << ")"
// << " argument " << n + 1 << " has invalid type " << type_info
// << std::endl
// << std::endl;
// sstr << "possible types are:" << std::endl;
// foreach_tuple(
// [&](auto &&t) {
// sstr << typeinfo<std::remove_pointer_t<
// std::remove_reference_t<decltype(t)>>>()
// << std::endl;
// },
// possible_types);
// std::string mesg = sstr.str();
// LM_FATAL(mesg);
// }
// }
// };
// // specialization for the end of recursion: all args have been dynamic casted
// // need to call the function
// template <typename tuple_type, typename tuple_type_formatted>
// struct CallCast<-1, tuple_type, tuple_type_formatted> {
// template <typename Obj, typename Functor>
// static void call_compute(Obj &obj, Functor &functor, tuple_type,
// tuple_type_formatted args_formatted) {
// apply([&](auto &... args) { functor(args...); }, args_formatted);
// }
// };
/* --------------------------------------------------------------------- */
struct
MD
{};
struct
CONTINUUM
{};
struct
DD
{};
struct
COMPONENT
{};
struct
ARRAY
{};
struct
MESH
{};
struct
POINT
{};
/* --------------------------------------------------------------------- */
struct
Caster
{
template
<
typename
type
,
typename
Arg
>
type
*
cast
(
Arg
&&
arg
)
{
using
_type
=
std
::
remove_pointer_t
<
std
::
decay_t
<
type
>>
;
ArgumentInterface
&
arg_gotten
=
arg
->
get
();
if
(
auto
*
ptr
=
cast_to_obj
<
_type
>
(
arg_gotten
))
{
return
ptr
;
}
// if (auto *ptr = cast_to_obj<_type &>(arg_gotten)) {
// return ptr;
// }
if
(
auto
*
ref
=
dynamic_cast
<
Argument
<
std
::
shared_ptr
<
_type
>>
*>
(
&
arg_gotten
))
{
return
ref
->
get
().
get
();
}
return
nullptr
;
}
};
template
<
typename
Obj
,
typename
Functor
,
typename
...
Args
>
void
call_compute
(
Obj
&
obj
,
Functor
func
,
Args
&
...
args
)
{
auto
&&
functor_to_call
=
[
&
](
auto
&
...
args
)
{
func
(
args
...);
auto
&&
tuple_args
=
std
::
forward_as_tuple
(
args
...);
constexpr
int
nb_arguments
=
std
::
tuple_size
<
std
::
decay_t
<
decltype
(
tuple_args
)
>>::
value
;
if
(
nb_arguments
!=
1
)
return
;
// if a single argument, try to copyContainerInfo
auto
&&
a
=
std
::
get
<
0
>
(
tuple_args
);
obj
.
_copyContainerInfo
(
a
);
};
using
possible_types
=
typename
get_possible_types
<
typename
Obj
::
possible_types
>::
types
;
// possible_types *a = 2.34;
try
{
_static_dispatch
<
possible_types
,
Caster
>
(
functor_to_call
,
args
...);
}
catch
(
std
::
bad_cast
&
)
{
// catch (ImpossibleCast &exception) {
LM_TOIMPLEMENT
;
// auto type_info = exception.arg.get().get_type_info();
// std::stringstream sstr;
// sstr << "Component " << obj.getID() << "(" << typeinfo<decltype(obj)>()
// << ")"
// << " argument " << n + 1 << " has invalid type " << type_info
// << std::endl
// << std::endl;
// sstr << "possible types are:" << std::endl;
// foreach_tuple(
// [&](auto &&t) {
// sstr << typeinfo<std::remove_pointer_t<
// std::remove_reference_t<decltype(t)>>>()
// << std::endl;
// },
// possible_types);
// std::string mesg = sstr.str();
// LM_FATAL(mesg);
}
}
/* --------------------------------------------------------------------- */
template
<
typename
Output
,
typename
Component
>
class
SingleOutputComponent
:
public
Component
{
public
:
using
Component
::
Component
;
SingleOutputComponent
(
const
LMID
&
name
)
:
LMObject
(
name
),
Component
(
name
)
{}
operator
Output
&
()
{
return
this
->
getOutputs
().
begin
()
->
second
.
get
().
template
cast
<
Output
>
();
}
auto
begin
()
{
return
(
*
this
)
->
begin
();
}
auto
end
()
{
return
(
*
this
)
->
end
();
}
Output
*
operator
->
()
{
return
&
static_cast
<
Output
&>
(
*
this
);
}
Output
&
operator
*
()
{
return
*
this
;
}
};
template
<
typename
T
>
struct
casted_component
{
template
<
typename
CastT
>
using
cast
=
SingleOutputComponent
<
CastT
,
T
>
;
};
/* --------------------------------------------------------------------- */
#include <boost/preprocessor.hpp>
// ************ Should boost this ***********************************
// #include "atom_model_list.hh"
// #include "continuum_model_list.hh"
// #include "dd_model_list.hh"
// ******************************************************************
template
<
UInt
Dim
>
class
RefPoint
;
template
<
UInt
Dim
>
class
RefPointData
;
template
<
UInt
Dim
>
class
RefGenericElem
;
template
<
typename
T
>
class
ContainerArray
;
class
ComputeInterface
;
template
<
typename
ContNode
,
typename
ContElem
>
class
ContainerMesh
;
template
<
UInt
Dim
>
using
ContainerGenericMesh
=
ContainerMesh
<
ContainerArray
<
RefPointData
<
Dim
>>
,
ContainerArray
<
RefGenericElem
<
Dim
>>>
;
// possible containers of MD
#ifdef LIBMULTISCALE_MD1D
class
ContainerMD1D
;
class
RefMD1D
;
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
template
<
UInt
Dim
>
class
ContainerLammps
;
template
<
UInt
Dim
>
class
RefLammps
;
#endif
using
md_containers
=
std
::
tuple
<
#ifdef LIBMULTISCALE_MD1D
ContainerMD1D
,
ContainerArray
<
RefMD1D
>
#endif
#if defined(LIBMULTISCALE_LAMMPS_PLUGIN) && defined(LIBMULTISCALE_MD1D)
,
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
ContainerLammps
<
2
>
,
ContainerLammps
<
3
>
,
ContainerArray
<
RefLammps
<
2
>>
,
ContainerArray
<
RefLammps
<
3
>>
#endif
>
;
template
<>
struct
_expand_type
<
MD
>
{
using
types
=
md_containers
;
};
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
class
ContainerNodesParaDiS
;
class
ContainerElemsParaDiS
;
class
RefNodeParaDiS
;
class
RefElemParaDiS
;
#endif
template
<
UInt
Dim
>
class
RefGenericDDElem
;
template
<
UInt
Dim
>
class
RefGenericDDNode
;
template
<
UInt
Dim
>
using
ContainerGenericDDMesh
=
ContainerMesh
<
ContainerArray
<
RefGenericDDNode
<
Dim
>>
,
ContainerArray
<
RefGenericDDElem
<
Dim
>>>
;
// possible containers of DD
using
dd_containers
=
std
::
tuple
<
ContainerGenericDDMesh
<
2u
>
,
ContainerGenericDDMesh
<
3u
>
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
,
ContainerMesh
<
ContainerNodesParaDiS
,
ContainerElemsParaDiS
>
,
ContainerMesh
<
ContainerArray
<
RefNodeParaDiS
>
,
ContainerArray
<
RefElemParaDiS
>>
#endif
>
;
template
<>
struct
_expand_type
<
DD
>
{
using
types
=
dd_containers
;
};
// possible containers of CONTINUUM
#ifdef LIBMULTISCALE_MECA1D
class
ContainerElemsMeca1D
;
class
ContainerNodesMeca1D
;
class
RefNodeMeca1D
;
class
RefElemMeca1D
;
#endif
#ifdef LIBMULTISCALE_AKANTU_PLUGIN
template
<
UInt
Dim
>
class
ContainerElemsAkantu
;
template
<
UInt
Dim
>
class
ContainerNodesAkantu
;
template
<
UInt
Dim
>
class
RefNodeAkantu
;
template
<
UInt
Dim
>
class
RefElemAkantu
;
#endif
using
continuum_containers
=
std
::
tuple
<
#ifdef LIBMULTISCALE_MECA1D
ContainerMesh
<
ContainerNodesMeca1D
,
ContainerElemsMeca1D
>
,
ContainerMesh
<
ContainerArray
<
RefNodeMeca1D
>
,
ContainerArray
<
RefElemMeca1D
>>
#endif
#if defined(LIBMULTISCALE_MECA1D) && defined(LIBMULTISCALE_AKANTU_PLUGIN)
,
#endif
#ifdef LIBMULTISCALE_AKANTU_PLUGIN
ContainerMesh
<
ContainerNodesAkantu
<
1
>
,
ContainerElemsAkantu
<
1
>>
,
ContainerMesh
<
ContainerArray
<
RefNodeAkantu
<
1
>>
,
ContainerArray
<
RefElemAkantu
<
1
>>>
,
ContainerMesh
<
ContainerNodesAkantu
<
2
>
,
ContainerElemsAkantu
<
2
>>
,
ContainerMesh
<
ContainerArray
<
RefNodeAkantu
<
2
>>
,
ContainerArray
<
RefElemAkantu
<
2
>>>
,
ContainerMesh
<
ContainerNodesAkantu
<
3
>
,
ContainerElemsAkantu
<
3
>>
,
ContainerMesh
<
ContainerArray
<
RefNodeAkantu
<
3
>>
,
ContainerArray
<
RefElemAkantu
<
3
>>>
#endif
>
;
template
<>
struct
_expand_type
<
CONTINUUM
>
{
using
types
=
continuum_containers
;
};
// possible containers of points
using
point_containers
=
std
::
tuple
<
ContainerArray
<
RefPointData
<
1u
>>
,
ContainerArray
<
RefPointData
<
2u
>>
,
ContainerArray
<
RefPointData
<
3u
>>>
;
template
<>
struct
_expand_type
<
POINT
>
{
using
types
=
point_containers
;
};
// possible containers of meshes
using
mesh_containers
=
std
::
tuple
<
ContainerGenericMesh
<
1u
>
,
ContainerGenericMesh
<
2u
>
,
ContainerGenericMesh
<
3u
>>
;
template
<>
struct
_expand_type
<
MESH
>
{
using
types
=
mesh_containers
;
};
// possible computes as input
template
<>
struct
_expand_type
<
COMPONENT
>
{
using
types
=
std
::
tuple
<
Component
>
;
};
template
<>
struct
_expand_type
<
ARRAY
>
{
using
types
=
std
::
tuple
<
ContainerArray
<
Real
>>
;
};
/* --------------------------------------------------------------------- */
template
<
typename
T
,
typename
Tuple
>
struct
has_type
;
template
<
typename
T
>
struct
has_type
<
T
,
std
::
tuple
<>>
:
std
::
false_type
{};
template
<
typename
T
,
typename
U
,
typename
...
Ts
>
struct
has_type
<
T
,
std
::
tuple
<
U
,
Ts
...
>>
:
has_type
<
T
,
std
::
tuple
<
Ts
...
>>
{};
template
<
typename
T
,
typename
...
Ts
>
struct
has_type
<
T
,
std
::
tuple
<
T
,
Ts
...
>>
:
std
::
true_type
{};
/* --------------------------------------------------------------------- */
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_md
:
std
::
enable_if
<
has_type
<
T
,
md_containers
>::
value
,
RetT
>
{
};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_md
=
typename
_enable_if_md
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_mesh
:
std
::
enable_if
<
has_type
<
T
,
mesh_containers
>::
value
or
has_type
<
T
,
continuum_containers
>::
value
or
has_type
<
T
,
dd_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_mesh
=
typename
_enable_if_mesh
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_continuum
:
std
::
enable_if
<
has_type
<
T
,
continuum_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_continuum
=
typename
_enable_if_continuum
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_point
:
std
::
enable_if
<
has_type
<
T
,
md_containers
>::
value
or
has_type
<
T
,
point_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_point
=
typename
_enable_if_point
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_dd
:
std
::
enable_if
<
has_type
<
T
,
dd_containers
>::
value
,
RetT
>
{
};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_dd
=
typename
_enable_if_dd
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_component
:
std
::
enable_if
<
std
::
is_same
<
T
,
Component
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_component
=
typename
_enable_if_component
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_not_component
:
std
::
enable_if
<
not
std
::
is_same
<
T
,
Component
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_not_component
=
typename
_enable_if_not_component
<
T
,
RetT
>::
type
;
/* --------------------------------------------------------------------- */
#define DECLARE_INPUT(...) \
using possible_types = std::tuple<std::tuple<__VA_ARGS__>>
#define DECLARE_MULTIPLE_INPUT(...) \
using possible_types = std::tuple<__VA_ARGS__>
/* --------------------------------------------------------------------- */
__END_LIBMULTISCALE__
#endif
/* __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ */
Event Timeline
Log In to Comment