diff --git a/lectures/pybind_lecture/pyexample.cpp b/lectures/pybind_lecture/pyexample.cpp index 13cb323..3602add 100644 --- a/lectures/pybind_lecture/pyexample.cpp +++ b/lectures/pybind_lecture/pyexample.cpp @@ -1,85 +1,85 @@ #include #include #include #include /* ------------------------------------------ */ // simple function /* ------------------------------------------ */ int add(int i, int j) { return i + j; } /* ------------------------------------------ */ // simple function with default arguments /* ------------------------------------------ */ int add_with_defaults(int i = 1, int j = 2) { return i + j; } /* ------------------------------------------ */ // global variables /* ------------------------------------------ */ std::string yopla = "yopla"; int global_variable = 12; void print_var() { std::cout << global_variable << std::endl; } /* ------------------------------------------ */ // class /* ------------------------------------------ */ struct Animal { Animal(const std::string &name) : name(name){}; virtual void scream() { std::cout << name << ": AAAAAA" << std::endl; } std::string name; void setName(const std::string &name) { this->name = name; } std::string getName() { return this->name; } }; /* ------------------------------------------ */ struct Dog : Animal { Dog(const std::string &name) : Animal(name) {} void scream() override { std::cout << "ouaff" << std::endl; } bool hasNiche() { return true; } void overloadedFoo(int a){}; void overloadedFoo(const std::string a) const {}; }; /* ------------------------------------------ */ enum ParticleType { atom, planet, pingpongball, material }; /* ------------------------------------------ */ /* ------------------------------------------ */ // function fabricating objects /* ------------------------------------------ */ -autostd::unique_ptr makeAnimalUnique() { +std::unique_ptr makeAnimalUnique() { return std::make_unique("puppy"); } /* ------------------------------------------ */ // memory management /* ------------------------------------------ */ Animal *animal_data = new Animal("toto"); Animal *get_animal() { return animal_data; } struct AnimalShared { std::string name; }; std::shared_ptr get_shared_ptr() { return std::make_shared(); } std::vector> vec_animal_shared; void register_animal_shared(std::shared_ptr ptr) { vec_animal_shared.push_back(ptr); }; template void apply(Func F) { std::vector v{1., 2., 3., 4.}; for (auto &val : v) F(val); } void _raise() { throw std::runtime_error("toto"); } #include "pyexample_pybind.cpp" diff --git a/lectures/pybind_lecture/test.py b/lectures/pybind_lecture/test.py index a2db4a5..1ac87a2 100644 --- a/lectures/pybind_lecture/test.py +++ b/lectures/pybind_lecture/test.py @@ -1,121 +1,121 @@ #!/bin/env python3 import pyexample help(pyexample) help(pyexample.add) print(pyexample.add(1, 2)) help(pyexample.add_withparams) print(pyexample.add_withparams(j=2, i=1)) help(pyexample.add_withdefaults) print(pyexample.add_withdefaults()) print(pyexample.yopla) print(pyexample.global_variable) pyexample.global_variable = 1 print(pyexample.global_variable) pyexample.print_var() -# conclusion ? +# conclusion ? not copied by reference print(pyexample.global_variable_rw) pyexample.global_variable_rw.fset(2) # this do not work !!! # pyexample.global_variable_rw = 2 pyexample.print_var() help(pyexample.Animal) print(pyexample.Animal) a = pyexample.Animal('kitty') b = pyexample.Animal() a.python_extension() print(a) print(b) a.scream() print(a.name) a.name = "new" print(a.name) a.new_member = 'toto' print(dir(a)) print(a.__dict__) dog = pyexample.Dog('poppy') dog.scream() help(dog.overloadedFoo) # automatic upcasting to true type (overhead) d = pyexample.makeAnimalUnique() print(type(d)) d.scream() print(pyexample.ParticleType) print(pyexample.ParticleType.__members__) # Python and C++ use fundamentally different ways of managing the # memory and lifetime of objects managed by them. This can lead to # issues when creating bindings for functions that return a # non-trivial type. Just by looking at the type information, it is not # clear whether Python should take charge of the returned value and # eventually free its resources, or if this is handled on the C++ # side. For this reason, pybind11 provides a several return value # policy annotations that can be passed to the module::def() and # class_::def() functions. The default policy is # return_value_policy::automatic. # segfault because del on python object calls delete on c++ pointer print("segfault") a = pyexample.get_animal() print(a) del a a = pyexample.get_animal() print(a) # solution: copy a = pyexample.get_animal_copy() print(a) a.name = "test" del a a = pyexample.get_animal_copy() print(a) # solution: by reference (no ownership) # memory management made by C++ only a = pyexample.get_animal_reference() print(a) a.name = "test" del a a = pyexample.get_animal_reference() print(a) # Code with invalid return value policies might access uninitialized # memory or free data structures multiple times, which can lead to # hard-to-debug non-determinism and segmentation faults, hence it is # worth spending the time to understand all the different options in # the table of return value policy. # As an alternative to elaborate call policies and lifetime management # logic, consider using smart pointers (see the section on Custom # smart pointers for details). Smart pointers can tell whether an # object is still referenced from C++ or Python, which generally # eliminates the kinds of inconsistencies that can lead to crashes or # undefined behavior. For functions returning smart pointers, it is # not necessary to specify a return value policy. a = pyexample.get_shared_ptr() a.name = "test" print(a) pyexample.register_animal_shared(a) pyexample.apply(lambda x: print(x*2)) # https://pybind11.readthedocs.io/en/stable/advanced/exceptions.html # automatic management of standard exceptions try: pyexample._raise() except Exception as e: print(e) # https://pybind11.readthedocs.io/en/stable/advanced/cast/index.html# diff --git a/work/week14/particle-pybind/starting_point/CMakeLists.txt b/work/week14/particle-pybind/starting_point/CMakeLists.txt index 5299fee..d10c10d 100644 --- a/work/week14/particle-pybind/starting_point/CMakeLists.txt +++ b/work/week14/particle-pybind/starting_point/CMakeLists.txt @@ -1,79 +1,103 @@ cmake_minimum_required (VERSION 3.1) project (Particles) cmake_policy(VERSION 3.3) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_CXX_STANDARD 14) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") +################################################################ +# pybind11 +################################################################ + +find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) + +add_library(pypart MODULE + material_points_factory.cc + particles_factory_interface.cc + ping_pong_balls_factory.cc + planets_factory.cc + csv_writer.cc + compute_temperature.cc) +target_link_libraries(pypart PRIVATE pybind11::module) +set_target_properties(pypart PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +file( + COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.py + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ + ) + + ################################################################ # FFTW ################################################################ -find_package(FFTW) +set(FFTW_LIBRARY_PATH CACHE PATH "library where to search FFTW") +find_library (FFTW_LIBRARY fftw3 /usr/include/ ${FFTW_LIBRARY_PATH}) ################################################################ # libpart ################################################################ add_library(part SHARED compute_boundary.cc compute_verlet_integration.cc particle.cc planet.cc compute_gravity.cc csv_reader.cc particles_factory_interface.cc planets_factory.cc compute_contact.cc compute_kinetic_energy.cc csv_writer.cc system.cc compute_energy.cc compute_potential_energy.cc ping_pong_ball.cc material_point.cc system_evolution.cc ping_pong_balls_factory.cc compute_interaction.cc compute_temperature.cc material_points_factory.cc ) target_link_libraries(part ${FFTW_LIBRARIES}) add_executable(particles main.cc) target_link_libraries(particles part) ################################################################ # Google test ################################################################ include(GoogleTest) enable_testing() find_package(GTest) if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) add_executable(test_kepler test_kepler.cc) add_executable(test_fft test_fft.cc) target_link_libraries(test_kepler part ${GTEST_BOTH_LIBRARIES} pthread) target_link_libraries(test_fft part ${GTEST_BOTH_LIBRARIES} ${FFTW_LIBRARIES} pthread) gtest_discover_tests(test_kepler) gtest_discover_tests(test_fft) endif() ################################################################ # Doxygen ################################################################ find_package(Doxygen) if (DOXYGEN_FOUND) # to set other options, read: https://cmake.org/cmake/help/v3.9/module/FindDoxygen.html doxygen_add_docs( doxygen ${PROJECT_SOURCE_DIR} COMMENT "Generate html pages" ) add_custom_target(doc DEPENDS doxygen) endif(DOXYGEN_FOUND) diff --git a/work/week14/particle-pybind/starting_point/compute_temperature.cc b/work/week14/particle-pybind/starting_point/compute_temperature.cc index fce0d52..c40f81b 100644 --- a/work/week14/particle-pybind/starting_point/compute_temperature.cc +++ b/work/week14/particle-pybind/starting_point/compute_temperature.cc @@ -1,11 +1,13 @@ #include "compute_temperature.hh" #include "fft.hh" #include "material_point.hh" #include /* -------------------------------------------------------------------------- */ void ComputeTemperature::compute(System& system) { } /* -------------------------------------------------------------------------- */ + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/csv_writer.cc b/work/week14/particle-pybind/starting_point/csv_writer.cc index 6bbfd6d..190fe08 100644 --- a/work/week14/particle-pybind/starting_point/csv_writer.cc +++ b/work/week14/particle-pybind/starting_point/csv_writer.cc @@ -1,30 +1,32 @@ #include "csv_writer.hh" #include #include /* -------------------------------------------------------------------------- */ CsvWriter::CsvWriter(const std::string& filename) : filename(filename) {} /* -------------------------------------------------------------------------- */ void CsvWriter::write(System& system) { this->compute(system); } /* -------------------------------------------------------------------------- */ void CsvWriter::compute(System& system) { std::ofstream os(filename.c_str()); if (os.is_open() == false) { std::cerr << "cannot open file " << filename << std::endl << "check that the dumps folder exists" << std::endl; std::exit(1); } UInt nb_particles = system.getNbParticles(); for (UInt p = 0; p < nb_particles; ++p) { os << system.getParticle(p) << std::endl; } os.close(); } + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/material_points_factory.cc b/work/week14/particle-pybind/starting_point/material_points_factory.cc index f895ac2..903b135 100644 --- a/work/week14/particle-pybind/starting_point/material_points_factory.cc +++ b/work/week14/particle-pybind/starting_point/material_points_factory.cc @@ -1,59 +1,61 @@ #include "material_points_factory.hh" #include "compute_temperature.hh" #include "csv_reader.hh" #include "csv_writer.hh" #include "material_point.hh" #include #include /* -------------------------------------------------------------------------- */ std::unique_ptr MaterialPointsFactory::createParticle() { return std::make_unique(); } /* -------------------------------------------------------------------------- */ void MaterialPointsFactory::createDefaultComputes(Real timestep) { auto compute_temp = std::make_shared(); compute_temp->getConductivity() = 1.; compute_temp->getL() = 2.; compute_temp->getCapacity() = 1.; compute_temp->getDensity() = 1.; compute_temp->getDeltat() = timestep; this->system_evolution->addCompute(compute_temp); } /* -------------------------------------------------------------------------- */ SystemEvolution& MaterialPointsFactory::createSimulation(const std::string& fname, Real timestep) { this->system_evolution = std::make_unique(std::make_unique()); CsvReader reader(fname); reader.read(this->system_evolution->getSystem()); // check if it is a square number auto N = this->system_evolution->getSystem().getNbParticles(); int side = std::sqrt(N); if (side * side != N) throw std::runtime_error("number of particles is not square"); this->createComputes(timestep); return *system_evolution; } /* -------------------------------------------------------------------------- */ ParticlesFactoryInterface& MaterialPointsFactory::getInstance() { if (not ParticlesFactoryInterface::factory) ParticlesFactoryInterface::factory = new MaterialPointsFactory; return *factory; } /* -------------------------------------------------------------------------- */ + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/particles_factory_interface.cc b/work/week14/particle-pybind/starting_point/particles_factory_interface.cc index 088deeb..1485b3d 100644 --- a/work/week14/particle-pybind/starting_point/particles_factory_interface.cc +++ b/work/week14/particle-pybind/starting_point/particles_factory_interface.cc @@ -1,11 +1,13 @@ #include "particles_factory_interface.hh" #include "planets_factory.hh" /* -------------------------------------------------------------------------- */ ParticlesFactoryInterface& ParticlesFactoryInterface::getInstance() { return *factory; } /* -------------------------------------------------------------------------- */ ParticlesFactoryInterface* ParticlesFactoryInterface::factory = nullptr; + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/ping_pong_balls_factory.cc b/work/week14/particle-pybind/starting_point/ping_pong_balls_factory.cc index cf830de..5261dfb 100644 --- a/work/week14/particle-pybind/starting_point/ping_pong_balls_factory.cc +++ b/work/week14/particle-pybind/starting_point/ping_pong_balls_factory.cc @@ -1,45 +1,47 @@ #include "ping_pong_balls_factory.hh" #include "compute_contact.hh" #include "compute_verlet_integration.hh" #include "csv_reader.hh" #include "csv_writer.hh" #include "ping_pong_ball.hh" #include #include /* -------------------------------------------------------------------------- */ std::unique_ptr PingPongBallsFactory::createParticle() { return std::make_unique(); } /* -------------------------------------------------------------------------- */ SystemEvolution& PingPongBallsFactory::createSimulation(const std::string& fname, Real timestep) { this->system_evolution = std::make_unique(std::make_unique()); CsvReader reader(fname); reader.read(this->system_evolution->getSystem()); auto contact = std::make_shared(); auto verlet = std::make_shared(timestep); contact->setPenalty(1.); verlet->addInteraction(contact); this->system_evolution->addCompute(verlet); return *system_evolution; } /* -------------------------------------------------------------------------- */ ParticlesFactoryInterface& PingPongBallsFactory::getInstance() { if (not ParticlesFactoryInterface::factory) ParticlesFactoryInterface::factory = new PingPongBallsFactory; return *factory; } /* -------------------------------------------------------------------------- */ + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/planets_factory.cc b/work/week14/particle-pybind/starting_point/planets_factory.cc index 78abecb..617509f 100644 --- a/work/week14/particle-pybind/starting_point/planets_factory.cc +++ b/work/week14/particle-pybind/starting_point/planets_factory.cc @@ -1,47 +1,49 @@ #include "planets_factory.hh" #include "compute_gravity.hh" #include "compute_verlet_integration.hh" #include "csv_reader.hh" #include "csv_writer.hh" #include "planet.hh" #include /* -------------------------------------------------------------------------- */ std::unique_ptr PlanetsFactory::createParticle() { return std::make_unique(); } /* -------------------------------------------------------------------------- */ SystemEvolution& PlanetsFactory::createSimulation(const std::string& fname, Real timestep) { this->system_evolution = std::make_unique(std::make_unique()); CsvReader reader(fname); reader.read(this->system_evolution->getSystem()); auto gravity = std::make_shared(); auto verlet = std::make_shared(timestep); verlet->addInteraction(gravity); this->system_evolution->addCompute(verlet); return *this->system_evolution; } /* -------------------------------------------------------------------------- */ ParticlesFactoryInterface& PlanetsFactory::getInstance() { if (not ParticlesFactoryInterface::factory) ParticlesFactoryInterface::factory = new PlanetsFactory; return *factory; } /* -------------------------------------------------------------------------- */ + +#include "pypart.cpp" \ No newline at end of file diff --git a/work/week14/particle-pybind/starting_point/pypart.cpp b/work/week14/particle-pybind/starting_point/pypart.cpp new file mode 100644 index 0000000..e456e3d --- /dev/null +++ b/work/week14/particle-pybind/starting_point/pypart.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +namespace py = pybind11; + +PYBIND11_MODULE(MaterialPointsFactory, m) { + +} + +PYBIND11_MODULE(ParticlesFactoryInterface, m) { + +} + +PYBIND11_MODULE(PingPongBallsFactory, m) { + +} + +PYBIND11_MODULE(PlanetsFactory, m) { + +} + +PYBIND11_MODULE(CsvWriter, m) { + +} + +PYBIND11_MODULE(ComputeTemperature, m) { + +} \ No newline at end of file