Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F79110928
compute_python.cc
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, Aug 24, 19:36
Size
11 KB
Mime Type
text/x-c++
Expires
Mon, Aug 26, 19:36 (2 d)
Engine
blob
Format
Raw Data
Handle
20152387
Attached To
rLIBMULTISCALE LibMultiScale
compute_python.cc
View Options
/**
* @file compute_python.cc
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Tue Jul 22 14:47:56 2014
*
* @brief This compute allows to use Python to produce computed values as input
* to LM
*
* @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/>.
*
*/
/* -------------------------------------------------------------------------- */
#define TIMER
#include "compute_python.hh"
#include "communicator.hh"
#include "compute_compatibility.hh"
#include "factory_multiscale.hh"
#include "lib_dd.hh"
#include "lib_md.hh"
#include "lm_common.hh"
#include "lm_parser.hh"
#include "units.hh"
#include <Eigen/Dense>
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
namespace
py
=
pybind11
;
template
<
typename
T
>
void
appendGeneralVariables
(
py
::
object
&
kwargs
,
const
std
::
string
&
name
,
T
&
value
)
{
py
::
object
pyvalue
=
py
::
cast
(
value
);
kwargs
.
attr
(
"__setitem__"
)(
name
,
pyvalue
);
}
/* -------------------------------------------------------------------------- */
template
<>
void
appendGeneralVariables
<
IntegrationSchemeStage
>
(
py
::
object
&
kwargs
,
const
std
::
string
&
name
,
IntegrationSchemeStage
&
value
)
{
std
::
stringstream
sstr
;
sstr
<<
value
;
std
::
string
str
=
sstr
.
str
();
appendGeneralVariables
<
std
::
string
>
(
kwargs
,
name
,
str
);
}
/* -------------------------------------------------------------------------- */
auto
split_string
(
const
std
::
string
&
str
,
char
separator
)
{
std
::
istringstream
iss
(
str
);
std
::
vector
<
std
::
string
>
res
;
while
(
!
iss
.
eof
())
{
std
::
string
buf
;
std
::
getline
(
iss
,
buf
,
separator
);
res
.
push_back
(
buf
);
}
return
res
;
}
auto
make_dict
(
std
::
vector
<
std
::
string
>
ids
,
py
::
object
obj
)
{
py
::
object
key
=
obj
;
std
::
for_each
(
ids
.
rbegin
(),
ids
.
rend
(),
[
&
key
](
auto
&
val
)
{
py
::
dict
new_key
;
new_key
.
attr
(
"__setitem__"
)(
val
,
key
);
key
=
new_key
;
});
return
key
;
}
/* -------------------------------------------------------------------------- */
template
<
typename
Cont
>
void
appendGeneralArray
(
py
::
object
&
kwargs
,
Cont
&
cont
,
bool
gather_flag
,
CommGroup
&
group
,
bool
gather_root_proc
)
{
const
UInt
Dim
=
cont
.
getDim
();
ContainerArray
<
Real
>
*
vdata_ptr
=
nullptr
;
if
(
gather_flag
)
{
LM_TOIMPLEMENT
;
// vdata_ptr = &cont.gatherAllData(gather_root_proc);
}
else
{
ContainerArray
<
Real
>
&
tmp
=
dynamic_cast
<
ContainerArray
<
Real
>
&>
(
cont
);
vdata_ptr
=
&
tmp
;
}
if
(
gather_flag
)
{
UInt
my_rank
=
group
.
getMyRank
();
if
(
my_rank
!=
gather_root_proc
)
{
// this->setDim(0);
return
;
}
}
LM_ASSERT
(
vdata_ptr
,
"null pointer detected: abort"
);
ContainerArray
<
Real
>
&
vdata
=
*
vdata_ptr
;
UInt
sz
=
vdata
.
size
()
/
Dim
;
Eigen
::
Map
<
Eigen
::
Array
<
Real
,
Eigen
::
Dynamic
,
Eigen
::
Dynamic
,
Eigen
::
RowMajor
>>
python_input
(
&
vdata
[
0
],
sz
,
Dim
);
py
::
object
pyvalue
=
py
::
cast
(
python_input
);
auto
id
=
cont
.
getID
();
DUMP
(
"adding the compute "
<<
id
,
DBG_INFO
);
auto
split_id
=
split_string
(
id
,
':'
);
kwargs
.
attr
(
"update"
)(
make_dict
(
split_id
,
pyvalue
));
// py::dict pyThisNameComputed;
// for (UInt i = 0; i < cont.name_computed.size(); ++i) {
// pyThisNameComputed.attr("__setitem__")(cont.name_computed[i], i);
// }
// py::object pyNameComputed = make_dict(split_id, pyThisNameComputed);
// py::dict updater;
// updater.attr("__setitem__")("name_computed", pyNameComputed);
// kwargs.attr("update")(updater);
}
/* -------------------------------------------------------------------------- */
ComputePython
::
ComputePython
(
const
std
::
string
&
name
)
:
LMObject
(
name
)
{
gather_root_proc
=
0
;
gather_flag
=
false
;
// pModule = new py::object;
// pCompute = new py::none;
kwargs
=
new
py
::
dict
;
this
->
createInput
(
"input"
);
};
/* -------------------------------------------------------------------------- */
ComputePython
::~
ComputePython
()
{
if
(
Py_IsInitialized
())
{
delete
kwargs
;
// delete pModule;
// delete pCompute;
}
}
/* -------------------------------------------------------------------------- */
void
ComputePython
::
init
()
{
this
->
createArrayOutputs
(
this
->
output_list
);
if
(
!
this
->
isConnected
(
"input"
))
this
->
removeInput
(
"input"
);
if
(
filename
!=
""
)
{
try
{
auto
pModule
=
py
::
module
::
import
(
filename
.
c_str
());
LM_TOIMPLEMENT
;
//*pCompute = pModule.attr("compute");
}
catch
(
py
::
error_already_set
&
e
)
{
DUMP
(
std
::
endl
<<
"Python error while loading "
<<
filename
<<
":"
<<
std
::
endl
<<
e
.
what
()
<<
std
::
endl
<<
std
::
endl
,
DBG_MESSAGE
);
LM_FATAL
(
"Failed to load "
<<
filename
);
}
}
else
if
(
pComputes
.
size
()
==
0
)
{
LM_FATAL
(
"No compute function was set: use FILENAME or FUNC keywords"
);
}
units_dict
=
decltype
(
units_dict
){{
"mvv2e"
,
code_unit_system
.
mvv2e
},
{
"f_m2v_t"
,
code_unit_system
.
f_m2v_t
},
{
"ft_m2v"
,
code_unit_system
.
ft_m2v
},
{
"mv_t2f"
,
code_unit_system
.
mv_t2f
},
{
"kT2e"
,
code_unit_system
.
kT2e
},
{
"kT2fd"
,
code_unit_system
.
kT2fd
},
{
"m_tt2f_d"
,
code_unit_system
.
m_tt2f_d
},
{
"e_dd2m_tt"
,
code_unit_system
.
e_dd2m_tt
},
{
"e2fd"
,
code_unit_system
.
e2fd
},
{
"e_m2dd_tt"
,
code_unit_system
.
e_m2dd_tt
},
{
"fd2e"
,
code_unit_system
.
fd2e
}};
kwargs
->
attr
(
"__setitem__"
)(
"units"
,
units_dict
);
try
{
}
catch
(
py
::
error_already_set
&
e
)
{
DUMP
(
std
::
endl
<<
"Python error in "
<<
filename
<<
":"
<<
std
::
endl
<<
e
.
what
()
<<
std
::
endl
<<
std
::
endl
,
DBG_MESSAGE
);
PyErr_Print
();
LM_FATAL
(
"Cannot find entry point: compute()"
);
}
kwargs
->
attr
(
"__setitem__"
)(
"constants"
,
Parser
::
getAlgebraicVariables
());
}
/* -------------------------------------------------------------------------- */
void
ComputePython
::
appendGeneralInfo
(
CommGroup
&
group
)
{
UInt
my_rank
=
group
.
getMyRank
();
for
(
UInt
comp
=
0
;
comp
<
compute_list
.
size
();
++
comp
)
{
LMID
id
=
compute_list
[
comp
];
auto
&
my_compute
=
FilterManager
::
getManager
().
getCastedObject
<
ComputeInterface
>
(
id
);
my_compute
.
build
();
appendGeneralArray
(
*
kwargs
,
my_compute
.
getArray
(),
this
->
gather_flag
,
group
,
this
->
gather_root_proc
);
}
if
(
this
->
gather_flag
&&
(
my_rank
!=
gather_root_proc
))
return
;
appendGeneralVariables
(
*
kwargs
,
"step"
,
current_step
);
appendGeneralVariables
(
*
kwargs
,
"current_stage"
,
current_stage
);
appendGeneralVariables
(
*
kwargs
,
"compute_name"
,
this
->
getID
());
appendGeneralVariables
(
*
kwargs
,
"rank"
,
lm_my_proc_id
);
}
/* -------------------------------------------------------------------------- */
void
ComputePython
::
callPythonRoutine
(
std
::
shared_ptr
<
py
::
object
>
&
pCompute
)
{
STARTTIMER
(
this
->
getID
());
// py::array_t<Real> pValue = (*pCompute)(***kwargs);
py
::
object
pValue
=
(
*
pCompute
)(
***
kwargs
);
std
::
map
<
std
::
string
,
py
::
object
>
results
;
try
{
results
=
pValue
.
cast
<
std
::
map
<
std
::
string
,
py
::
object
>>
();
}
catch
(...)
{
py
::
object
res
=
pValue
;
results
[
"output"
]
=
res
;
}
using
EigenArray
=
ContainerArray
<
Real
>::
EigenArray
;
for
(
auto
&&
pair
:
results
)
{
auto
&
key
=
pair
.
first
;
auto
vec
=
pair
.
second
.
cast
<
EigenArray
>
();
auto
&
output
=
this
->
getOutput
(
key
).
get
(
false
).
cast
<
ContainerArray
<
Real
>>
();
output
=
vec
;
DUMP
(
"compute python "
<<
this
->
getID
()
<<
" computed "
<<
this
->
getArray
().
size
()
<<
" values"
,
DBG_INFO
);
}
STOPTIMER
(
this
->
getID
());
}
/* --------------------------------------------------------------------------
*/
void
ComputePython
::
compute_no_arg
()
{
this
->
clear
();
// import_array();
this
->
setCommGroup
(
Communicator
::
getCommunicator
().
getObject
(
"all"
));
CommGroup
&
group
=
this
->
getCommGroup
();
this
->
appendGeneralInfo
(
group
);
for
(
auto
&&
key_val
:
this
->
pComputes
)
{
auto
&
pCompute
=
key_val
.
second
;
auto
name
=
key_val
.
first
;
this
->
callPythonRoutine
(
pCompute
);
}
}
/* ----------------------------------------------------------------------- */
void
ComputePython
::
compute_with_arg
(
ContainerArray
<
Real
>
&
cont
)
{
this
->
clear
();
this
->
copyContainerInfo
(
cont
);
// import_array();
CommGroup
&
group
=
this
->
getCommGroup
();
appendGeneralArray
(
*
kwargs
,
cont
,
this
->
gather_flag
,
group
,
this
->
gather_root_proc
);
this
->
appendGeneralInfo
(
group
);
for
(
auto
&&
key_val
:
this
->
pComputes
)
{
auto
&
pCompute
=
key_val
.
second
;
auto
name
=
key_val
.
first
;
this
->
callPythonRoutine
(
pCompute
);
}
}
/* ----------------------------------------------------------------------- */
/* LMDESC PYTHON
This computes an array of reals based on a python script
*/
/* LMEXAMPLE
COMPUTE disp EXTRACT INPUT md FIELD displacement \\\\
COMPUTE disp2 PYTHON INPUT disp FILENAME script \\\\
with a python script stored in a file script.py with the content such
as:\\\\
import numpy as np\\ \\
def compute(**kwargs):\\
~~vec = np.copy(kwargs["disp"])\\
~~vec *= 2. \\
~~return vec
*/
void
ComputePython
::
declareParams
()
{
ComputeInterface
::
declareParams
();
/* LMKEYWORD FILENAME
Specify the name of the python script to use
*/
this
->
parseKeyword
(
"FILENAME"
,
filename
,
""
);
/* LMKEYWORD OUTPUTS
Specify the name of the outputs which will be produced
*/
this
->
parseKeyword
(
"FUNC"
,
pComputes
,
std
::
map
<
std
::
string
,
std
::
shared_ptr
<
py
::
object
>>
());
/* LMKEYWORD GATHER_ROOT
Specify the processor where to gather data before inputing to python
script
*/
this
->
parseKeyword
(
"GATHER_ROOT"
,
gather_root_proc
,
0u
);
/* LMKEYWORD GATHER
Specify the processor where to gather data before inputing to python
script
*/
this
->
parseTag
(
"GATHER"
,
gather_flag
,
false
);
/* LMKEYWORD ADD_COMPUTE
Add computes to input to the kwargs of the python script
*/
this
->
parseKeyword
(
"ADD_COMPUTE"
,
compute_list
,
std
::
vector
<
std
::
string
>
{});
}
/* --------------------------------------------------------------------------
*/
void
ComputePython
::
compute_make_call
()
{
DUMP
(
this
->
getID
()
<<
": Compute"
,
DBG_INFO
);
if
(
this
->
isConnected
(
"input"
))
call_compute
(
*
this
,
[
&
](
auto
&
...
args
)
{
this
->
compute_with_arg
(
args
...);
},
this
->
getInput
(
"input"
));
else
call_compute
(
*
this
,
[
&
]()
{
this
->
compute_no_arg
();
});
}
__END_LIBMULTISCALE__
Event Timeline
Log In to Comment