diff --git a/examples/python/custom-material/bi-material.py b/examples/python/custom-material/bi-material.py index 37bf307b4..4d03347a4 100644 --- a/examples/python/custom-material/bi-material.py +++ b/examples/python/custom-material/bi-material.py @@ -1,184 +1,184 @@ from __future__ import print_function # ------------------------------------------------------------- # import akantu as aka import subprocess import numpy as np import time # ------------------------------------------------------------- # class LocalElastic: # declares all the internals def initMaterial(self, internals, params): self.E = params['E'] self.nu = params['nu'] self.rho = params['rho'] # print(self.__dict__) # First Lame coefficient self.lame_lambda = self.nu * self.E / ( (1. + self.nu) * (1. - 2. * self.nu)) # Second Lame coefficient (shear modulus) self.lame_mu = self.E / (2. * (1. + self.nu)) all_factor = internals['factor'] all_quad_coords = internals['quad_coordinates'] for elem_type in all_factor.keys(): factor = all_factor[elem_type] quad_coords = all_quad_coords[elem_type] factor[:] = 1. factor[quad_coords[:, 1] < 0.5] = .5 # declares all the internals @staticmethod def registerInternals(): return ['potential', 'factor'] # declares all the internals @staticmethod def registerInternalSizes(): return [1, 1] # declares all the parameters that could be parsed @staticmethod def registerParam(): return ['E', 'nu'] # declares all the parameters that are needed def getPushWaveSpeed(self, params): return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho) # compute small deformation tensor @staticmethod def computeEpsilon(grad_u): return 0.5 * (grad_u + np.einsum('aij->aji', grad_u)) # constitutive law def computeStress(self, grad_u, sigma, internals, params): n_quads = grad_u.shape[0] grad_u = grad_u.reshape((n_quads, 2, 2)) factor = internals['factor'].reshape(n_quads) epsilon = self.computeEpsilon(grad_u) sigma = sigma.reshape((n_quads, 2, 2)) trace = np.einsum('aii->a', grad_u) sigma[:, :, :] = ( np.einsum('a,ij->aij', trace, self.lame_lambda * np.eye(2)) + 2. * self.lame_mu * epsilon) # print(sigma.reshape((n_quads, 4))) # print(grad_u.reshape((n_quads, 4))) sigma[:, :, :] = np.einsum('aij, a->aij', sigma, factor) # constitutive law tangent modulii def computeTangentModuli(self, grad_u, tangent, internals, params): n_quads = tangent.shape[0] tangent = tangent.reshape(n_quads, 3, 3) factor = internals['factor'].reshape(n_quads) Miiii = self.lame_lambda + 2 * self.lame_mu Miijj = self.lame_lambda Mijij = self.lame_mu tangent[:, 0, 0] = Miiii tangent[:, 1, 1] = Miiii tangent[:, 0, 1] = Miijj tangent[:, 1, 0] = Miijj tangent[:, 2, 2] = Mijij tangent[:, :, :] = np.einsum('aij, a->aij', tangent, factor) # computes the energy density def getEnergyDensity(self, energy_type, energy_density, grad_u, stress, internals, params): nquads = stress.shape[0] stress = stress.reshape(nquads, 2, 2) grad_u = grad_u.reshape((nquads, 2, 2)) if energy_type != 'potential': raise RuntimeError('not known energy') epsilon = self.computeEpsilon(grad_u) energy_density[:, 0] = ( 0.5 * np.einsum('aij,aij->a', stress, epsilon)) # applies manually the boundary conditions def applyBC(model): nbNodes = model.getMesh().getNbNodes() position = model.getMesh().getNodes() displacement = model.getDisplacement() blocked_dofs = model.getBlockedDOFs() width = 1. height = 1. epsilon = 1e-8 for node in range(0, nbNodes): if((np.abs(position[node, 0]) < epsilon) or # left side (np.abs(position[node, 0] - width) < epsilon)): # right side blocked_dofs[node, 0] = True displacement[node, 0] = 0 * position[node, 0] + 0. if(np.abs(position[node, 1]) < epsilon): # lower side blocked_dofs[node, 1] = True displacement[node, 1] = - 1. if(np.abs(position[node, 1] - height) < epsilon): # upper side blocked_dofs[node, 1] = True displacement[node, 1] = 1. # main parameters spatial_dimension = 2 mesh_file = 'square.msh' # call gmsh to generate the mesh -ret = subprocess.call(['gmsh', '-2', 'square.geo', '-optimize', 'square.msh']) +ret = subprocess.call('gmsh -format msh2 -2 square.geo -optimize square.msh', shell=True) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') time.sleep(1) # read mesh mesh = aka.Mesh(spatial_dimension) mesh.read(mesh_file) # create the custom material mat = LocalElastic() aka.registerNewPythonMaterial(mat, "local_elastic") # parse input file aka.parseInput('material.dat') # init the SolidMechanicsModel model = aka.SolidMechanicsModel(mesh) model.initFull(_analysis_method=aka._static) # configure the solver solver = model.getNonLinearSolver() solver.set("max_iterations", 2) solver.set("threshold", 1e-3) solver.set("convergence_type", aka._scc_solution) # prepare the dumper model.setBaseName("bimaterial") model.addDumpFieldVector("displacement") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") model.addDumpField("factor") model.addDumpField("blocked_dofs") # Boundary conditions applyBC(model) # solve the problem model.solveStep() # dump paraview files model.dump() diff --git a/examples/python/dynamics/dynamics.py b/examples/python/dynamics/dynamics.py index c8be57fec..5b7e3ef84 100644 --- a/examples/python/dynamics/dynamics.py +++ b/examples/python/dynamics/dynamics.py @@ -1,129 +1,131 @@ #!/usr/bin/env python3 from __future__ import print_function ################################################################ import os import subprocess import numpy as np import akantu ################################################################ -class FixedValue: +class MyFixedValue(akantu.FixedValue): def __init__(self, value, axis): + super().__init__(value, axis) self.value = value - self.axis = axis + self.axis = int(axis) - def operator(self, node, flags, disp, coord): + def __call__(self, node, flags, disp, coord): # sets the displacement to the desired value in the desired axis disp[self.axis] = self.value # sets the blocked dofs vector to true in the desired axis flags[self.axis] = True ################################################################ def main(): spatial_dimension = 2 akantu.parseInput('material.dat') mesh_file = 'bar.msh' max_steps = 250 time_step = 1e-3 # if mesh was not created the calls gmsh to generate it if not os.path.isfile(mesh_file): - ret = subprocess.call('gmsh -2 bar.geo bar.msh', shell=True) + ret = subprocess.call('gmsh -format msh2 -2 bar.geo bar.msh', shell=True) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') ################################################################ # Initialization ################################################################ mesh = akantu.Mesh(spatial_dimension) mesh.read(mesh_file) model = akantu.SolidMechanicsModel(mesh) model.initFull(_analysis_method=akantu._explicit_lumped_mass) # model.initFull(_analysis_method=akantu._implicit_dynamic) model.setBaseName("waves") model.addDumpFieldVector("displacement") model.addDumpFieldVector("acceleration") model.addDumpFieldVector("velocity") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") model.addDumpField("blocked_dofs") ################################################################ # boundary conditions ################################################################ - model.applyDirichletBC(FixedValue(0, akantu._x), "XBlocked") - model.applyDirichletBC(FixedValue(0, akantu._y), "YBlocked") + model.applyBC(MyFixedValue(0, akantu._x), "XBlocked") + model.applyBC(MyFixedValue(0, akantu._y), "YBlocked") ################################################################ # initial conditions ################################################################ displacement = model.getDisplacement() nb_nodes = mesh.getNbNodes() position = mesh.getNodes() pulse_width = 1 A = 0.01 for i in range(0, nb_nodes): # Sinus * Gaussian x = position[i, 0] - 5. L = pulse_width k = 0.1 * 2 * np.pi * 3 / L displacement[i, 0] = A * \ np.sin(k * x) * np.exp(-(k * x) * (k * x) / (L * L)) + displacement[i, 1] = 0 ################################################################ # timestep value computation ################################################################ time_factor = 0.8 stable_time_step = model.getStableTimeStep() * time_factor print("Stable Time Step = {0}".format(stable_time_step)) print("Required Time Step = {0}".format(time_step)) time_step = stable_time_step * time_factor model.setTimeStep(time_step) ################################################################ # loop for evolution of motion dynamics ################################################################ model.assembleInternalForces() print("step,step * time_step,epot,ekin,epot + ekin") for step in range(0, max_steps + 1): model.solveStep() if step % 10 == 0: model.dump() epot = model.getEnergy('potential') ekin = model.getEnergy('kinetic') # output energy calculation to screen print("{0},{1},{2},{3},{4}".format(step, step * time_step, epot, ekin, (epot + ekin))) return ################################################################ if __name__ == "__main__": main() diff --git a/python/pybind11/py_aka_array.cc b/python/pybind11/py_aka_array.cc index 3c5ee7a13..a5b17996e 100644 --- a/python/pybind11/py_aka_array.cc +++ b/python/pybind11/py_aka_array.cc @@ -1,215 +1,203 @@ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; namespace _aka = akantu; namespace akantu { + template class ArrayProxy : public Array { protected: // deallocate the memory void deallocate() override final {} // allocate the memory void allocate(__attribute__((unused)) UInt size, __attribute__((unused)) UInt nb_component) override final {} // allocate and initialize the memory void allocate(__attribute__((unused)) UInt size, __attribute__((unused)) UInt nb_component, __attribute__((unused)) const T & value) override final {} public: ArrayProxy(T * data, UInt size, UInt nb_component) { this->values = data; this->size_ = size; this->nb_component = nb_component; } ArrayProxy(const Array & src) { this->values = src.storage(); this->size_ = src.size(); this->nb_component = src.getNbComponent(); } + ~ArrayProxy() { this->values = nullptr; } + void resize(__attribute__((unused)) UInt size, __attribute__((unused)) const T & val) override final { AKANTU_EXCEPTION("cannot resize a temporary array"); } void resize(__attribute__((unused)) UInt new_size) override final { AKANTU_EXCEPTION("cannot resize a temporary array"); } void reserve(__attribute__((unused)) UInt new_size) override final { AKANTU_EXCEPTION("cannot resize a temporary array"); } }; } // namespace akantu namespace pybind11 { namespace detail { + + template + using array_type = array_t; + /* ------------------------------------------------------------------------ */ template py::handle aka_array_cast(const _aka::Array & src, py::handle base = handle(), bool writeable = true) { - constexpr ssize_t elem_size = sizeof(T); array a; - a = array({src.size(), src.getNbComponent()}, - {elem_size * src.getNbComponent(), elem_size}, src.storage(), - base); + a = array_type({src.size(), src.getNbComponent()}, src.storage(), base); if (not writeable) array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; return a.release(); } template struct type_caster<_aka::Array> { protected: - using py_array = array_t; using type = _aka::Array; + type value; public: - PYBIND11_TYPE_CASTER(type, _("Array")); - - // static constexpr auto name = - // _("numpy.ndarray[") + npy_format_descriptor::name + - // _(", flags.writeable") + _(", flags.c_contiguous") + _("]"); + static PYBIND11_DESCR name() { return type_descr(_("Array")); }; /** * Conversion part 1 (Python->C++) */ bool load(handle src, bool convert) { - bool need_copy = not isinstance(src); + bool need_copy = not isinstance>(src); - auto && fits = [&](auto && a) { - auto && dims = copy_or_ref.ndim(); + auto && fits = [&](auto && aref) { + auto && dims = aref.ndim(); if (dims < 1 || dims > 2) return false; return true; }; if (not need_copy) { // We don't need a converting copy, but we also need to check whether // the strides are compatible with the Ref's stride requirements - py_array aref = reinterpret_borrow(src); + auto aref = py::cast>(src); if (not fits(aref)) { return false; } - copy_or_ref = std::move(aref); } else { if (not convert) { return false; } - auto copy = py_array::ensure(src); + auto copy = array_type::ensure(src); if (not copy) { return false; } if (not fits(copy)) { return false; } - copy_or_ref = std::move(py_array::ensure(src)); + copy_or_ref = std::move(array_type::ensure(src)); loader_life_support::add_patient(copy_or_ref); } - array_proxy.reset(new _aka::ArrayProxy> (copy_or_ref.mutable_data(), - copy_or_ref.shape(0), - copy_or_ref.shape(1))); + array_proxy = std::make_unique<_aka::ArrayProxy>( + copy_or_ref.mutable_data(), copy_or_ref.shape(0), + copy_or_ref.shape(1)); return true; } - // operator _aka::Array *() { return array_proxy.get(); } - // operator _aka::Array &() { return *array_proxy; } - // template - // using cast_op_type = pybind11::detail::cast_op_type<_T>; + operator _aka::Array *() { return array_proxy.get(); } + operator _aka::Array &() { return *array_proxy; } + template + using cast_op_type = pybind11::detail::cast_op_type<_T>; /** * Conversion part 2 (C++ -> Python) */ static handle cast(const _aka::Array & src, return_value_policy policy, handle parent) { switch (policy) { case return_value_policy::copy: return aka_array_cast(src); case return_value_policy::reference_internal: return aka_array_cast(src, parent); case return_value_policy::reference: case return_value_policy::automatic: case return_value_policy::automatic_reference: return aka_array_cast(src, none()); default: pybind11_fail("Invalid return_value_policy for ArrayProxy type"); } } protected: - std::unique_ptr<_aka::Array> array_proxy; - py_array copy_or_ref; + std::unique_ptr<_aka::ArrayProxy> array_proxy; + array_type copy_or_ref; }; /** * Type caster for Vector classes */ template