Skip to content

Commit ac7bda6

Browse files
committed
Merge remote-tracking branch 'upstream/master' into stiffnessmassmatrix
2 parents 677458f + 4c9945b commit ac7bda6

20 files changed

Lines changed: 509 additions & 66 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
matrix:
2121
os: [ubuntu-20.04, macos-10.15, windows-2019]
2222
sofa_branch: [master]
23-
python_version: ['3.9']
23+
python_version: ['3.8']
2424

2525
steps:
2626
- name: Setup SOFA and environment

Plugin/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux)
6868
endif()
6969

7070
if (CMAKE_SYSTEM_NAME STREQUAL Windows )
71-
target_include_directories(${PROJECT_NAME} PUBLIC "${pybind11_INCLUDE_DIR}")
72-
7371
# https://github.com/boostorg/system/issues/32
7472
target_compile_definitions(${PROJECT_NAME} PUBLIC "-DHAVE_SNPRINTF")
7573
endif()

Plugin/src/SofaPython3/DataHelper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ size_t getSize(BaseData* self)
294294

295295
py::buffer_info toBufferInfo(BaseData& m)
296296
{
297-
scoped_read_access guard(&m);
297+
m.updateIfDirty();
298298

299299
const AbstractTypeInfo& nfo { *m.getValueTypeInfo() };
300300
auto itemNfo = nfo.BaseType();

Plugin/src/SofaPython3/DataHelper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,9 @@ void copyScalar(BaseData* a, const AbstractTypeInfo& nfo, pybind11::array_t<T, p
221221
void* ptr = a->beginEditVoidPtr();
222222

223223
auto r = src.unchecked();
224-
for (ssize_t i = 0; i < r.shape(0); i++)
224+
for (pybind11::ssize_t i = 0; i < r.shape(0); i++)
225225
{
226-
for (ssize_t j = 0; j < r.shape(1); j++)
226+
for (pybind11::ssize_t j = 0; j < r.shape(1); j++)
227227
{
228228
nfo.setScalarValue( ptr, i*r.shape(1)+j, r(i,j) );
229229
}

Plugin/src/SofaPython3/PythonEnvironment.cpp

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ class PythonEnvironmentData
103103

104104
std::set<std::string> addedPath;
105105

106-
py::module m_sofamodule ;
106+
py::module m_sofaModule ;
107+
py::module m_sofaRuntimeModule ;
107108
private:
108109
std::vector<wchar_t*> m_argv;
109110
};
@@ -180,27 +181,26 @@ void PythonEnvironment::Init()
180181
}
181182

182183
PyEval_InitThreads();
183-
gil lock;
184184

185185
// Required for sys.path, used in addPythonModulePath().
186-
PyRun_SimpleString("import sys");
186+
executePython([]{ PyRun_SimpleString("import sys");});
187187

188188
// Force C locale.
189-
PyRun_SimpleString("import locale");
190-
PyRun_SimpleString("locale.setlocale(locale.LC_ALL, 'C')");
189+
executePython([]{ PyRun_SimpleString("import locale");});
190+
executePython([]{ PyRun_SimpleString("locale.setlocale(locale.LC_ALL, 'C')");});
191191

192192
// Workaround: try to import numpy and to launch numpy.finfo to cache data;
193193
// this prevents a deadlock when calling numpy.finfo from a worker thread.
194-
PyRun_SimpleString("try:\n\timport numpy;numpy.finfo(float)\nexcept:\n\tpass");
194+
executePython([]{ PyRun_SimpleString("try:\n\timport numpy;numpy.finfo(float)\nexcept:\n\tpass");});
195195

196196
// Workaround: try to import scipy from the main thread this prevents a deadlock when importing
197197
// scipy from a worker thread when we use the SofaScene asynchronous loading
198-
PyRun_SimpleString("try:\n\tfrom scipy import misc, optimize\nexcept:\n\tpass\n");
198+
executePython([]{ PyRun_SimpleString("try:\n\tfrom scipy import misc, optimize\nexcept:\n\tpass\n");});
199199

200200
// If the script directory is not available (e.g. if the interpreter is invoked interactively
201201
// or if the script is read from standard input), path[0] is the empty string,
202202
// which directs Python to search modules in the current directory first.
203-
PyRun_SimpleString(std::string("sys.path.insert(0,\"\")").c_str());
203+
executePython([]{ PyRun_SimpleString(std::string("sys.path.insert(0,\"\")").c_str());});
204204

205205
// Add the paths to the plugins' python modules to sys.path. Those paths
206206
// are read from all the files in 'etc/sofa/python.d'
@@ -237,11 +237,12 @@ void PythonEnvironment::Init()
237237
// Lastly, we (try to) add modules from the root of SOFA
238238
addPythonModulePathsFromDirectory( Utils::getSofaPathPrefix() );
239239

240-
getStaticData()->m_sofamodule = py::module::import("Sofa");
241-
PyRun_SimpleString("import SofaRuntime");
240+
executePython([]{ getStaticData()->m_sofaModule = py::module::import("Sofa"); });
241+
executePython([]{ getStaticData()->m_sofaRuntimeModule = py::module::import("SofaRuntime"); });
242+
executePython([]{ PyRun_SimpleString("import SofaRuntime");});
242243

243244
// python livecoding related
244-
PyRun_SimpleString("from Sofa.livecoding import onReimpAFile");
245+
executePython([]{ PyRun_SimpleString("from Sofa.livecoding import onReimpAFile");});
245246

246247
// general sofa-python stuff
247248

@@ -311,16 +312,14 @@ void PythonEnvironment::Release()
311312
void PythonEnvironment::addPythonModulePath(const std::string& path)
312313
{
313314
PythonEnvironmentData* data = getStaticData() ;
314-
if ( data->addedPath.find(path)==data->addedPath.end()) {
315+
if ( data->addedPath.find(path)==data->addedPath.end())
316+
{
315317
// note not to insert at first 0 place
316318
// an empty string must be at first so modules can be found in the current directory first.
317319

318-
{
319-
gil lock;
320-
PyRun_SimpleString(std::string("sys.path.insert(1,\""+path+"\")").c_str());
321-
}
320+
executePython([&]{ PyRun_SimpleString(std::string("sys.path.insert(1,\""+path+"\")").c_str());});
322321

323-
msg_info("SofaPython3") << "Added '" + path + "' to sys.path";
322+
msg_info("SofaPython3")<< "Added '" + path + "' to sys.path";
324323
data->addedPath.insert(path);
325324
}
326325
}
@@ -508,22 +507,15 @@ std::string PythonEnvironment::getStackAsString()
508507

509508
std::string PythonEnvironment::getPythonCallingPointString()
510509
{
511-
return py::cast<std::string>(getStaticData()->m_sofamodule.attr("getPythonCallingPointAsString")());
510+
gil lock;
511+
return py::cast<std::string>(getStaticData()->m_sofaModule.attr("getPythonCallingPointAsString")());
512512
}
513513

514514
sofa::helper::logging::FileInfo::SPtr PythonEnvironment::getPythonCallingPointAsFileInfo()
515515
{
516-
PyObject* pDict = PyModule_GetDict(PyImport_AddModule("SofaRuntime"));
517-
PyObject* res = PyDict_GetItemString(pDict, "getPythonCallingPoint");
518-
if(res && PySequence_Check(res) ){
519-
PyObject* filename = PySequence_GetItem(res, 0) ;
520-
PyObject* number = PySequence_GetItem(res, 1) ;
521-
std::string tmp=PyBytes_AsString(filename);
522-
auto lineno = PyLong_AsLong(number);
523-
Py_DECREF(res) ;
524-
return SOFA_FILE_INFO_COPIED_FROM(tmp, lineno);
525-
}
526-
return SOFA_FILE_INFO_COPIED_FROM("undefined", -1);
516+
gil lock;
517+
py::tuple cp = getStaticData()->m_sofaRuntimeModule.attr("getPythonCallingPoint")();
518+
return SOFA_FILE_INFO_COPIED_FROM(py::cast<std::string>(cp[0]), py::cast<int>(cp[1]));
527519
}
528520

529521
void PythonEnvironment::setArguments(const std::string& filename, const std::vector<std::string>& arguments)
@@ -546,9 +538,8 @@ void PythonEnvironment::setArguments(const std::string& filename, const std::vec
546538

547539
void PythonEnvironment::SceneLoaderListerner::rightBeforeLoadingScene()
548540
{
549-
gil lock;
550541
// unload python modules to force importing their eventual modifications
551-
PyRun_SimpleString("SofaRuntime.unloadModules()");
542+
executePython([]{ PyRun_SimpleString("SofaRuntime.unloadModules()");});
552543
}
553544

554545
void PythonEnvironment::setAutomaticModuleReload( bool b )
@@ -561,8 +552,7 @@ void PythonEnvironment::setAutomaticModuleReload( bool b )
561552

562553
void PythonEnvironment::excludeModuleFromReload( const std::string& moduleName )
563554
{
564-
gil lock;
565-
PyRun_SimpleString( std::string( "try: SofaRuntime.__SofaPythonEnvironment_modulesExcludedFromReload.append('" + moduleName + "')\nexcept:pass" ).c_str() );
555+
executePython([&]{ PyRun_SimpleString( std::string( "try: SofaRuntime.__SofaPythonEnvironment_modulesExcludedFromReload.append('" + moduleName + "')\nexcept:pass" ).c_str() );});
566556
}
567557

568558
static const bool debug_gil = false;

Plugin/src/SofaPython3/SceneLoaderPY3.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ void SceneLoaderPY3::loadSceneWithArguments(const char *filename,
106106

107107
py::object createScene = module.attr("createScene");
108108
createScene( PythonFactory::toPython(root_out.get()) );
109+
110+
root_out->setInstanciationSourceFileName(filename);
111+
root_out->setInstanciationSourceFilePos(0);
109112
}catch(py::error_already_set& e)
110113
{
111114
msg_error() << "Unable to completely load the scene from file '"<< filename << "'." << msgendl

bindings/Modules/Bindings.ModulesConfig.cmake.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ find_package(SofaPython3 QUIET REQUIRED COMPONENTS Plugin Bindings.Sofa)
99
find_package(SofaBaseTopology QUIET REQUIRED)
1010
# Required by Bindings.Modules.SofaDeformable
1111
find_package(SofaDeformable QUIET REQUIRED)
12+
# Required by Bindings.Modules.SofaLinearSolver
13+
find_package(Sofa.Component.LinearSolver.Iterative REQUIRED)
1214

1315
# If we are importing this config file and the target is not yet there this is indicating that
1416
# target is an imported one. So we include it

bindings/Modules/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
project(Bindings.Modules)
22

3-
set(MODULEBINDINGS_MODULE_LIST SofaBaseTopology SofaDeformable)
3+
set(MODULEBINDINGS_MODULE_LIST SofaBaseTopology SofaDeformable SofaLinearSolver)
44

55
find_package(Sofa.GL QUIET)
66
if(Sofa.GL_FOUND)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/******************************************************************************
2+
* SOFA, Simulation Open-Framework Architecture *
3+
* (c) 2021 INRIA, USTL, UJF, CNRS, MGH *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify it *
6+
* under the terms of the GNU Lesser General Public License as published by *
7+
* the Free Software Foundation; either version 2.1 of the License, or (at *
8+
* your option) any later version. *
9+
* *
10+
* This program is distributed in the hope that it will be useful, but WITHOUT *
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13+
* for more details. *
14+
* *
15+
* You should have received a copy of the GNU Lesser General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
*******************************************************************************
18+
* Contact information: contact@sofa-framework.org *
19+
******************************************************************************/
20+
#include <SofaPython3/SofaLinearSolver/Binding_LinearSolver.h>
21+
#include <SofaPython3/SofaLinearSolver/Binding_LinearSolver_doc.h>
22+
#include <pybind11/pybind11.h>
23+
24+
#include <SofaPython3/Sofa/Core/Binding_Base.h>
25+
#include <SofaPython3/PythonFactory.h>
26+
27+
#include <sofa/component/linearsolver/iterative/MatrixLinearSolver.h>
28+
#include <pybind11/eigen.h>
29+
30+
namespace py { using namespace pybind11; }
31+
32+
namespace sofapython3 {
33+
34+
using EigenSparseMatrix = Eigen::SparseMatrix<SReal, Eigen::RowMajor>;
35+
using EigenMatrixMap = Eigen::Map<Eigen::SparseMatrix<SReal, Eigen::RowMajor> >;
36+
using Vector = Eigen::Matrix<SReal,Eigen::Dynamic, 1>;
37+
using EigenVectorMap = Eigen::Map<Vector>;
38+
39+
template<class TBlock>
40+
EigenSparseMatrix toEigen(sofa::linearalgebra::CompressedRowSparseMatrix<TBlock>& matrix)
41+
{
42+
sofa::linearalgebra::CompressedRowSparseMatrix<typename TBlock::Real> filtered;
43+
filtered.copyNonZeros(matrix);
44+
filtered.compress();
45+
return EigenMatrixMap(filtered.rows(), filtered.cols(), filtered.getColsValue().size(),
46+
(EigenMatrixMap::StorageIndex*)filtered.rowBegin.data(), (EigenMatrixMap::StorageIndex*)filtered.colsIndex.data(), filtered.colsValue.data());
47+
}
48+
49+
template<>
50+
EigenSparseMatrix toEigen<SReal>(sofa::linearalgebra::CompressedRowSparseMatrix<SReal>& matrix)
51+
{
52+
return EigenMatrixMap(matrix.rows(), matrix.cols(), matrix.getColsValue().size(),
53+
(EigenMatrixMap::StorageIndex*)matrix.rowBegin.data(), (EigenMatrixMap::StorageIndex*)matrix.colsIndex.data(), matrix.colsValue.data());
54+
}
55+
56+
template<class TBlock>
57+
void bindLinearSolvers(py::module &m)
58+
{
59+
using CRS = sofa::linearalgebra::CompressedRowSparseMatrix<TBlock>;
60+
using CRSLinearSolver = sofa::component::linearsolver::MatrixLinearSolver<CRS, sofa::linearalgebra::FullVector<SReal> >;
61+
using Real = typename CRS::Real;
62+
63+
const std::string typeName = CRSLinearSolver::GetClass()->className + CRSLinearSolver::GetCustomTemplateName();
64+
65+
py::class_<CRSLinearSolver,
66+
sofa::core::objectmodel::BaseObject,
67+
sofapython3::py_shared_ptr<CRSLinearSolver> > c(m, typeName.c_str(), sofapython3::doc::linearsolver::linearSolverClass);
68+
69+
c.def("A", [](CRSLinearSolver& self) -> EigenSparseMatrix
70+
{
71+
if (CRS* matrix = self.getSystemMatrix())
72+
{
73+
return toEigen(*matrix);
74+
}
75+
return {};
76+
}, sofapython3::doc::linearsolver::linearSolver_A);
77+
78+
c.def("b", [](CRSLinearSolver& self) -> Vector
79+
{
80+
if (auto* vector = self.getSystemRHVector())
81+
{
82+
return EigenVectorMap(vector->ptr(), vector->size());
83+
}
84+
return {};
85+
}, sofapython3::doc::linearsolver::linearSolver_b);
86+
87+
c.def("x", [](CRSLinearSolver& self) -> Vector
88+
{
89+
if (auto* vector = self.getSystemLHVector())
90+
{
91+
return EigenVectorMap(vector->ptr(), vector->size());
92+
}
93+
return {};
94+
}, sofapython3::doc::linearsolver::linearSolver_x);
95+
96+
97+
/// register the binding in the downcasting subsystem
98+
PythonFactory::registerType<CRSLinearSolver>([](sofa::core::objectmodel::Base* object)
99+
{
100+
return py::cast(dynamic_cast<CRSLinearSolver*>(object));
101+
});
102+
}
103+
104+
void moduleAddLinearSolver(py::module &m)
105+
{
106+
bindLinearSolvers<SReal>(m);
107+
bindLinearSolvers<sofa::type::Mat<3, 3, SReal> >(m);
108+
}
109+
110+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/******************************************************************************
2+
* SOFA, Simulation Open-Framework Architecture *
3+
* (c) 2021 INRIA, USTL, UJF, CNRS, MGH *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify it *
6+
* under the terms of the GNU Lesser General Public License as published by *
7+
* the Free Software Foundation; either version 2.1 of the License, or (at *
8+
* your option) any later version. *
9+
* *
10+
* This program is distributed in the hope that it will be useful, but WITHOUT *
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13+
* for more details. *
14+
* *
15+
* You should have received a copy of the GNU Lesser General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
*******************************************************************************
18+
* Contact information: contact@sofa-framework.org *
19+
******************************************************************************/
20+
21+
#pragma once
22+
23+
#include <pybind11/pybind11.h>
24+
25+
namespace sofapython3
26+
{
27+
28+
void moduleAddLinearSolver(pybind11::module &m);
29+
30+
} /// namespace sofapython3
31+

0 commit comments

Comments
 (0)