def distribution(number): "Get distribution of number on all processes" if not hasattr(distribution, "cpp_module"): cpp_code = """ namespace dolfin { std::vector<unsigned int> distribution(const MPI_Comm mpi_comm, int number) { // Variables to help in synchronization int num_processes = dolfin::MPI::size(mpi_comm); int this_process = dolfin::MPI::rank(mpi_comm); std::vector<uint> distribution(num_processes); for(uint i=0; i<num_processes; i++) { if(i==this_process) { distribution[i] = number; } dolfin::MPI::barrier(mpi_comm); dolfin::MPI::broadcast(mpi_comm, distribution, i); } return distribution; } } """ distribution.cpp_module = df.compile_extension_module( cpp_code, additional_system_headers=["dolfin/common/MPI.h"] ) cpp_module = distribution.cpp_module return cpp_module.distribution(df.mpi_comm_world(), number)
def __create_cell_dof_mapping(self, dofmap): """ Generate cell -> dof mapping for all cells of current partition. Note: in DG(0) space, there is one dof per element and no ghost cells. :param GenericDofMap dofmap: DG(0) dofmap """ if self.verb > 2: print0("Constructing cell -> dof mapping") timer = Timer("DD: Cell->dof construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<int>& local_cell_dof_map, const Mesh& mesh, const GenericDofMap& dofmap) { std::size_t local_dof_range_start = dofmap.ownership_range().first; int* cell_dof_data = local_cell_dof_map.data(); for (CellIterator c(mesh); !c.end(); ++c) *cell_dof_data++ = dofmap.cell_dofs(c->index())[0] - local_dof_range_start; } } ''' cell_mapping_module = compile_extension_module(code) cell_dof_array = IntArray(self.local_ndof0) cell_mapping_module.fill_in(cell_dof_array, self.mesh, dofmap) self._local_cell_dof_map = cell_dof_array.array() timer.stop()
def __create_cell_vol_mapping(self): """ Generate cell -> volume mapping for all cells of current partition. Note that keys are ordered by the associated DG(0) dof, not by the cell index in the mesh. This map is required for calculating various densities from total region integrals (like cell power densities from cell-integrated powers). """ if self.verb > 2: print0("Constructing cell -> volume mapping") timer = Timer("DD: Cell->vol construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<double>& cell_vols, const Mesh& mesh, const Array<int>& cell_dofs) { for (CellIterator c(mesh); !c.end(); ++c) cell_vols[cell_dofs[c->index()]] = c->volume(); } } ''' cell_mapping_module = compile_extension_module(code) cell_vol_array = DoubleArray(self.local_ndof0) cell_mapping_module.fill_in(cell_vol_array, self.mesh, self.local_cell_dof_map) self._local_cell_volumes = cell_vol_array.array() timer.stop()
def HiptmairMatrixSetup(mesh, N, M): path = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "..")) if __version__ == '1.6.0': gradient_code = open(os.path.join(path, 'DiscreteGradientSecond.cpp'), 'r').read() else: gradient_code = open(os.path.join(path, 'DiscreteGradient.cpp'), 'r').read() compiled_gradient_module = compile_extension_module(code=gradient_code) column = numpy.zeros(2*mesh.num_edges(), order="C") #, dtype="intc") row = numpy.zeros(2*mesh.num_edges(), order="C") #, dtype="intc") data = numpy.zeros(2*mesh.num_edges(), order="C") #, dtype="intc") dataX = numpy.zeros(2*mesh.num_edges(), order="C") dataY = numpy.zeros(2*mesh.num_edges(), order="C") dataZ = numpy.zeros(2*mesh.num_edges(), order="C") tic() c = compiled_gradient_module.ProlongationGradsecond(mesh, dataX,dataY,dataZ, data, row, column) end = toc() MO.StrTimePrint("Data for C and P created, time: ",end) # print row # print column # print data C = csr_matrix((data,(row,column)), shape=(N, M)).tocsr() Px = csr_matrix((dataX,(row,column)), shape=(N, M)).tocsr() Py = csr_matrix((dataY,(row,column)), shape=(N, M)).tocsr() Pz = csr_matrix((dataZ,(row,column)), shape=(N, M)).tocsr() return C, [Px,Py,Pz]
def test_compile_extension_module(): # This test should do basically the same as the docstring of the # compile_extension_module function in compilemodule.py. Remember # to update the docstring if the test is modified! from numpy import arange, exp code = """ namespace dolfin { void PETSc_exp(std::shared_ptr<dolfin::PETScVector> vec) { Vec x = vec->vec(); assert(x); VecExp(x); } } """ for module_name in [ "mypetscmodule_" + dolfin.__version__ + "_py-" + platform.python_version()[:3], "" ]: ext_module = compile_extension_module(\ code, module_name=module_name,\ additional_system_headers=["petscvec.h"]) vec = PETScVector(mpi_comm_world(), 10) np_vec = vec.array() np_vec[:] = arange(len(np_vec)) vec.set_local(np_vec) ext_module.PETSc_exp(vec) np_vec[:] = exp(np_vec) assert (np_vec == vec.array()).all()
def test_mpi_swig(): from dolfin import compile_extension_module create_transfer_matrix_code = r''' namespace dolfin { void find_exterior_points(MPI_Comm mpi_comm) {} }''' create_transfer_matrix = compile_extension_module( code=create_transfer_matrix_code)
def __init__(self, V, bnd, objects, vsources=None, isources=None, dt=None, int_bnd_ids=None, eps0=1): num_objects = len(objects) if int_bnd_ids == None: int_bnd_ids = [ objects[i].domain_args[1] for i in range(num_objects) ] if vsources == None: vsources = [] if isources == None: isources = [] self.dt = 1 else: assert dt != None self.dt = dt self.int_bnd_ids = int_bnd_ids self.vsources = vsources self.isources = isources self.objects = objects self.eps0 = eps0 self.groups = get_charge_sharing_sets(vsources, num_objects) self.V = V mesh = V.mesh() R = df.FunctionSpace(mesh, "Real", 0) self.mu = df.TestFunction(R) self.phi = df.TrialFunction(V) self.dss = df.Measure("ds", domain=mesh, subdomain_data=bnd) self.n = df.FacetNormal(mesh) thisdir = os.path.dirname(__file__) path = os.path.join(thisdir, 'addrow.cpp') code = open(path, 'r').read() self.compiled = df.compile_extension_module(code=code) # Rows in which to store charge and potential constraints rows_charge = [g[0] for g in self.groups] rows_potential = list(set(range(num_objects)) - set(rows_charge)) self.rows_charge = [objects[i].get_free_row() for i in rows_charge] self.rows_potential = [ objects[i].get_free_row() for i in rows_potential ]
def _clean_hdf5(self, fieldname, del_metadata): delete_from_hdf5_file = ''' namespace dolfin { #include <hdf5.h> void delete_from_hdf5_file(const MPI_Comm comm, const std::string hdf5_filename, const std::string dataset, const bool use_mpiio) { //const hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); // Open file existing file for append //hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, plist_id); hid_t hdf5_file_id = HDF5Interface::open_file(comm, hdf5_filename, "a", use_mpiio); H5Ldelete(hdf5_file_id, dataset.c_str(), H5P_DEFAULT); HDF5Interface::close_file(hdf5_file_id); } } ''' cpp_module = compile_extension_module( delete_from_hdf5_file, additional_system_headers=["dolfin/io/HDF5Interface.h"]) hdf5filename = os.path.join(self._pp.get_savedir(fieldname), fieldname + '.hdf5') if not os.path.isfile(hdf5filename): return for k, v in del_metadata.items(): if 'hdf5' not in v: continue else: cpp_module.delete_from_hdf5_file( mpi_comm_world(), hdf5filename, v['hdf5']['dataset'], MPI.size(mpi_comm_world()) > 1) hdf5tmpfilename = os.path.join(self._pp.get_savedir(fieldname), fieldname + '_tmp.hdf5') #import ipdb; ipdb.set_trace() MPI.barrier(mpi_comm_world()) if on_master_process(): # status, result = getstatusoutput("h5repack -V") status, result = -1, -1 if status != 0: cbc_warning( "Unable to run h5repack. Will not repack hdf5-files before replay, which may cause bloated hdf5-files." ) else: subprocess.call("h5repack %s %s" % (hdf5filename, hdf5tmpfilename), shell=True) os.remove(hdf5filename) os.rename(hdf5tmpfilename, hdf5filename) MPI.barrier(mpi_comm_world())
def compile_extension_module(cpp_code, **kwargs): if DOLFIN_VERSION_MAJOR >= 2018: headers = kwargs.get('additional_system_headers', []) headers = ["#include <Eigen/Core>", '#include <pybind11/pybind11.h>', # "using Array = Eigen::Ref<const Eigen::ArrayXi>;;"] +\ "using Array = Eigen::ArrayXi;"] +\ ['#include <' + h + '>' for h in headers if h != ''] cpp_code = '\n'.join(headers) + cpp_code return dolfin.compile_cpp_code(cpp_code) else: return dolfin.compile_extension_module(cpp_code, **kwargs)
def get_equation_module(for_distribution=False): """ Returns extension module that deals with the equation of motion. Will try to return from cache before recompiling. By default, dolfin will chose a cache directory using a digest of our code and some version numbers. This procedure enables dolfin to detect changes to our code and recompile on the fly. However, when we distribute FinMag we don't need or want on the fly recompilation and we'd rather have the resulting files placed in a directory known ahead of time. For this, call this function once with `for_distribution` set to True and ship FinMag including the directory build/equation. During normal use, our known cache directory is always checked before dolfin's temporary ones. Its existence bypasses on the fly recompilation. """ # __file__ will not be available during module init if this module is # compiled with cython. So the following line shouldn't be moved to the # module level. It is perfectly safe inside this function though. MODULE_DIR = path.dirname(path.abspath(__file__)) SOURCE_DIR = path.join(MODULE_DIR, "native") # Define our own cache base directory instead of the default one. This # helps in distributing only the compiled code without sources. CACHE_DIR = path.join(MODULE_DIR, "build") signature = "equation" if for_distribution else "" # dolfin will chose # Try to get the module from the known distribution location before # asking instant about its cache. This way a distributed copy of FinMag # should never attempt recompilation (which would fail without sources). equation_module = instant.import_module("equation", CACHE_DIR) if equation_module is not None: log.debug("Got equation extension module from distribution location.") else: with open(path.join(SOURCE_DIR, "equation.h"), "r") as header: code = header.read() equation_module = df.compile_extension_module( code=code, sources=["equation.cpp", "terms.cpp", "derivatives.cpp"], source_directory=SOURCE_DIR, # where the sources given above are include_dirs=[SOURCE_DIR, find_petsc(), find_slepc()], # where to look for header files # dolfin's compile_extension_module will pass on `module_name` to # instant's build_module as `signature`. That's the name of the # directory it will be cached in. So don't worry if instant's doc # says that passing a module name will disable caching. module_name=signature, cache_dir=CACHE_DIR, ) return equation_module
def BoundaryEdge(mesh): path = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "..")) # if __version__ == '1.6.0': gradient_code = open(os.path.join(path, 'DiscreteGradientSecond.cpp'), 'r').read() # else: # gradient_code = open(os.path.join(path, 'DiscreteGradient.cpp'), 'r').read() compiled_gradient_module = compile_extension_module(code=gradient_code) B = BoundaryMesh(mesh,"exterior",False) FaceBoundary = numpy.sort(B.entity_map(2).array().astype("float_","C")) EdgeBoundary = numpy.zeros(3*FaceBoundary.size, order="C") c = compiled_gradient_module.FaceToEdgeBoundary(mesh, FaceBoundary, FaceBoundary.size, EdgeBoundary) return EdgeBoundary #numpy.sort(EdgeBoundary)[::2].astype("float_","C")
def HiptmairMatrixSetupBoundary(mesh, N, M,dim): def boundary(x, on_boundary): return on_boundary # mesh.geometry().dim() path = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "..")) # if __version__ == '1.6.0': gradient_code = open(os.path.join(path, 'DiscreteGradientSecond.cpp'), 'r').read() # else: # gradient_code = open(os.path.join(path, 'DiscreteGradient.cpp'), 'r').read() compiled_gradient_module = compile_extension_module(code=gradient_code) tic() if dim == 3: EdgeBoundary = BoundaryEdge(mesh) EdgeBoundary = numpy.sort(EdgeBoundary)[::2].astype("float_","C") else: B = BoundaryMesh(mesh,"exterior",False) EdgeBoundary = numpy.sort(B.entity_map(1).array().astype("float_","C")) end = toc() MO.StrTimePrint("Compute edge boundary indices, time: ",end) row = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") #, dtype="intc") column = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") #, dtype="intc") data = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") #, dtype="intc") dataX = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") dataY = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") dataZ = numpy.zeros(2*(mesh.num_edges()-EdgeBoundary.size), order="C") # print 2*(mesh.num_edges()-EdgeBoundary.size) tic() # c = compiled_gradient_module.ProlongationGrad(mesh, EdgeBoundary, dataX,dataY,dataZ, data, row, column) c = compiled_gradient_module.ProlongationGradBoundary(mesh, EdgeBoundary, dataX,dataY,dataZ, data, row, column) # u, indices = numpy.unique(row, return_index=True) # indices = numpy.concatenate((indices,indices+1),axis=1) # # print VertexBoundary # print row # # print numpy.concatenate((indices,indices+1),axis=1) # # print data # row = row[indices] # column = column[indices] # data = data[indices] # print row end = toc() MO.StrTimePrint("Data for C and P created, time: ",end) C = coo_matrix((data,(row,column)), shape=(N, M)).tocsr() Px = coo_matrix((dataX,(row,column)), shape=(N, M)).tocsr() Py = coo_matrix((dataY,(row,column)), shape=(N, M)).tocsr() Pz = coo_matrix((dataZ,(row,column)), shape=(N, M)).tocsr() del dataX, dataY, dataZ, row,column, mesh, EdgeBoundary return C, [Px,Py,Pz]
def compile_extension_module(cpp_code, **kwargs): if DOLFIN_VERSION_MAJOR >= 2018: headers = kwargs.get("additional_system_headers", []) headers = [ "#include <Eigen/Core>", "#include <pybind11/pybind11.h>", # "using Array = Eigen::Ref<const Eigen::ArrayXi>;;"] +\ "using Array = Eigen::ArrayXi;", ] + ["#include <" + h + ">" for h in headers if h != ""] cpp_code = "\n".join(headers) + cpp_code return dolfin.compile_cpp_code(cpp_code) else: return dolfin.compile_extension_module(cpp_code, **kwargs)
def broadcast(array, from_process): "Broadcast array to all processes" if not hasattr(broadcast, "cpp_module"): cpp_code = """ namespace dolfin { std::vector<double> broadcast(const MPI_Comm mpi_comm, const Array<double>& inarray, int from_process) { int this_process = dolfin::MPI::rank(mpi_comm); std::vector<double> outvector(inarray.size()); if(this_process == from_process) { for(int i=0; i<inarray.size(); i++) { outvector[i] = inarray[i]; } } dolfin::MPI::barrier(mpi_comm); dolfin::MPI::broadcast(mpi_comm, outvector, from_process); return outvector; } } """ cpp_module = df.compile_extension_module( cpp_code, additional_system_headers=["dolfin/common/MPI.h"], ) broadcast.cpp_module = cpp_module cpp_module = broadcast.cpp_module if df.MPI.rank(df.mpi_comm_world()) == from_process: array = np.array(array, dtype=np.float) shape = array.shape shape = np.array(shape, dtype=np.float_) else: array = np.array([], dtype=np.float) shape = np.array([], dtype=np.float_) shape = cpp_module.broadcast(df.mpi_comm_world(), shape, from_process) array = array.flatten() out_array = cpp_module.broadcast(df.mpi_comm_world(), array, from_process) if len(shape) > 1: out_array = out_array.reshape(*shape) return out_array
def test_pesc_swig(): from dolfin import compile_extension_module create_matrix_code = r''' namespace dolfin { std::shared_ptr<PETScMatrix> create_matrix(void) { Mat I; std::shared_ptr<PETScMatrix> ptr = std::make_shared<PETScMatrix>(I); return ptr; } } ''' create_matrix = compile_extension_module(code=create_matrix_code)
def __init__(self, *args, **kwargs): # Adds the missing argument (the value on the boundary) before calling # the parent constructor. The value must be zero to set the # corresponding elements in the load vector to zero. args = list(args) args.insert(1, df.Constant(0.0)) monitor = False self.compiled_apply = kwargs.pop('compiled_apply', False) if self.compiled_apply: code = open('apply.cpp', 'r').read() self.compiled_apply = df.compile_extension_module(code=code) df.DirichletBC.__init__(self, *args, **kwargs)
def get_set_vector(setvector, set_indices, getvector, get_indices, temp_array=None): """Equivalent of setvector[set_indices] = getvector[get_indices] for global indices (MPI-blocking). Pass temp_array to avoid initiation of array on call. """ #if dolfin_version() == "1.4.0": # setvector[set_indices] = getvector[get_indices] # return if not hasattr(get_set_vector, "cppmodule"): code = """ void get_set_vector(std::shared_ptr<GenericVector> set_vector, const Array<dolfin::la_index> & set_indices, std::shared_ptr<const GenericVector> get_vector, const Array<dolfin::la_index> & get_indices, const Array<double> & temp_array) { std::size_t N = set_indices.size(); // Perform a const_cast (unable to pass non-const Array through from python layer) Array<double> & temp_array2 = const_cast<Array<double> &>(temp_array); // Get and set using the non-const temp_array2 get_vector->get(temp_array2.data(), N, get_indices.data()); set_vector->set(temp_array2.data(), N, set_indices.data()); // Apply vector (MPI-part) set_vector->apply("insert"); } """ # Very minor change required for dolfin 1.4.0 #if dolfin_version() == "1.4.0": if LooseVersion(dolfin_version()) <= LooseVersion("1.4.0"): code = code.replace("get_vector->get", "get_vector->get_local") cbc_log(20, "Compiling get_set_vector.cppmodule") get_set_vector.cppmodule = compile_extension_module(code) assert len(set_indices) == len(get_indices) if temp_array is None: temp_array = zeros(len(set_indices), dtype=float_) assert len(temp_array) == len(set_indices) get_set_vector.cppmodule.get_set_vector(setvector, set_indices, getvector, get_indices, temp_array)
def test_slepc_swig(): from dolfin import compile_extension_module create_eps_code = r''' #include <slepc.h> namespace dolfin { std::shared_ptr<EPS> create_matrix(MPI_Comm comm) { EPS eps; EPSCreate(comm, &eps); std::shared_ptr<EPS> ptr = std::make_shared<EPS>(eps); return ptr; } } ''' create_matrix = compile_extension_module(code=create_eps_code)
def terms_module(): MODULE_DIR = path.dirname(path.abspath(__file__)) SOURCE_DIR = path.join(MODULE_DIR, "..", "native") with open(path.join(SOURCE_DIR, "terms.h"), "r") as header: code = header.read() extension_module = df.compile_extension_module( code=code, source_directory=SOURCE_DIR, sources=["terms.cpp"], # declare dm_x, dm_y and dm_z as input/output parameters # they will turn up in Python as return values additional_declarations="%apply double& INOUT { double& dm_x, double& dm_y, double& dm_z };", include_dirs=[SOURCE_DIR, eqn.find_petsc(), eqn.find_slepc()],) return extension_module
def __init__(self): cpp_link_code = ''' #include <hdf5.h> void link_dataset(const MPI_Comm comm, const std::string hdf5_filename, const std::string link_from, const std::string link_to, bool use_mpiio) { hid_t hdf5_file_id = HDF5Interface::open_file(comm, hdf5_filename, "a", use_mpiio); herr_t status = H5Lcreate_hard(hdf5_file_id, link_from.c_str(), H5L_SAME_LOC, link_to.c_str(), H5P_DEFAULT, H5P_DEFAULT); dolfin_assert(status != HDF5_FAIL); HDF5Interface::close_file(hdf5_file_id); } ''' self.cpp_link_module = compile_extension_module(cpp_link_code, additional_system_headers=["dolfin/io/HDF5Interface.h"])
def __create_cell_layers_mapping(self): """ Generate a cell -> axial layer mapping for all cells of current partition. Note that keys are ordered by the associated DG(0) dof, not by the cell index in the mesh. """ if self.verb > 2: print0("Constructing cell -> layer mapping") timer = Timer("DD: Cell->layer construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<int>& local_cell_layers, const Mesh& mesh, const Array<int>& cell_dofs, const Array<double>& layer_boundaries) { std::size_t num_layers = layer_boundaries.size() - 1; unsigned int layer; for (CellIterator c(mesh); !c.end(); ++c) { double midz = c->midpoint().z(); for (layer = 0; layer < num_layers; layer++) if (layer_boundaries[layer] <= midz && midz <= layer_boundaries[layer+1]) break; int dof = cell_dofs[c->index()]; local_cell_layers[dof] = layer; } } } ''' cell_mapping_module = compile_extension_module(code) cell_layers_array = IntArray(self.local_ndof0) cell_mapping_module.fill_in(cell_layers_array, self.mesh, self.local_cell_dof_map, self.core.layer_boundaries) self._local_cell_layers = cell_layers_array.array() timer.stop()
def test_pass_array_int(): import numpy code = """ int test_int_array(const Array<int>& int_arr) { int ret = 0; for (int i = 0; i < int_arr.size(); i++) { ret += int_arr[i]; } return ret; } """ module = compile_extension_module(code=code, source_directory='.', sources=[], include_dirs=["."]) arr = numpy.array([1, 2, 4, 8], dtype=numpy.intc) ans = module.test_int_array(arr) assert ans == arr.sum() == 15
def gather(array, on_process=0, flatten=False): "Gather array from all processes on a single process" if not hasattr(gather, "cpp_module"): cpp_code = """ namespace dolfin { std::vector<double> gather(const MPI_Comm mpi_comm, const Array<double>& inarray, int on_process) { int this_process = dolfin::MPI::rank(mpi_comm); std::vector<double> outvector(dolfin::MPI::size(mpi_comm)*dolfin::MPI::sum(mpi_comm, inarray.size())); std::vector<double> invector(inarray.size()); for(int i=0; i<inarray.size(); i++) { invector[i] = inarray[i]; } dolfin::MPI::gather(mpi_comm, invector, outvector, on_process); return outvector; } } """ gather.cpp_module = df.compile_extension_module( cpp_code, additional_system_headers=["dolfin/common/MPI.h"], ) cpp_module = gather.cpp_module array = np.array(array, dtype=np.float) out_array = cpp_module.gather(df.mpi_comm_world(), array, on_process) if flatten: return out_array dist = distribution(len(array)) cumsum = [0] + [sum(dist[:i + 1]) for i in range(len(dist))] out_array = [[out_array[cumsum[i]:cumsum[i + 1]]] for i in range(len(cumsum) - 1)] return out_array
def test_pass_array_double(): import numpy code = """ double test_double_array(const Array<double>& arr) { double ret = 0; for (int i = 0; i < arr.size(); i++) { ret += arr[i]; } return ret; } """ module = compile_extension_module(code=code, source_directory='.', sources=[], include_dirs=["."]) arr = numpy.array([1, 2, 4, 8], dtype=float) ans = module.test_double_array(arr) assert abs(arr.sum() - 15) < 1e-15 assert abs(ans - 15) < 1e-15
def dmt_number_entities(mesh, tdim): 'Number (global) mesh entities of topological dimension.' folder = abspath(join(inspect.getfile(inspect.currentframe()), '../cpp')) code = open(join(folder, 'dmt.cpp'), 'r').read() compiled_module = compile_extension_module(code=code) return compiled_module.dmt_number_entities(mesh, tdim)
import os abspath = os.path.dirname( os.path.abspath(__file__) ) source_directory = os.path.join(abspath,"cpp_rand") header_file = open(os.path.join(source_directory,"PRNG.h"), "r") code = header_file.read() header_file.close() cpp_sources = ["PRNG.cpp"] include_dirs = [".", source_directory] for ss in ['PROFILE_INSTALL_DIR', 'PETSC_DIR', 'SLEPC_DIR']: if ss in os.environ.keys(): include_dirs.append(os.environ[ss]+'/include') cpp_module = dl.compile_extension_module( code=code, source_directory=source_directory, sources=cpp_sources, include_dirs=include_dirs) class Random(cpp_module.Random): """ This class handles parallel generation of random numbers in hippylib. """ def __init__(self,myid=0, nproc=1, blocksize=1000000, seed=1): """ Create a parallel random number number generator. INPUTS: - :code:`myid`: id of the calling process. - :code:`nproc`: number of processor in the communicator.
def decorated_assemble(*args, **kwargs): tensor = kwargs.get('tensor') if isinstance(tensor, (VectorView, MatrixView)): form = _create_dolfin_form(args[0], kwargs.pop("form_compiler_parameters", None)) spaces = form.function_spaces for i in range(len(spaces)): dim = spaces[i].dofmap().max_cell_dimension() tensor.resize_work_array(i, dim) else: form = args[0] return assemble_function(form, *args[1:], **kwargs) return decorated_assemble # Find absolute path of this module path = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__))) # Load MatrixView code = open(path+"/MatrixView.h").read() module = compile_extension_module(code, cppargs='-g -O2') MatrixView = _store_args_decorator(module.MatrixView) # Load VectorView code = open(path+"/VectorView.h").read() module = compile_extension_module(code, cppargs='-g -O2') VectorView = _store_args_decorator(module.VectorView) # Provide assemble function assemble = _assemble_decorator(assemble)
__author__ = "Miroslav Kuchta <*****@*****.**>" __date__ = "2014-04-05" __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" import inspect from dolfin import TensorFunctionSpace, VectorFunctionSpace, FunctionSpace,\ Function, interpolate, compile_extension_module, GenericFunction, assemble, \ TrialFunction, TestFunction, dx, Matrix, dot, div from fenicstools import SetMatrixValue from os.path import abspath, join folder = abspath(join(inspect.getfile(inspect.currentframe()), '../fem')) code = open(join(folder, 'cr_divergence.cpp'), 'r').read() compiled_cr_module = compile_extension_module(code=code) def gauss_divergence(u, mesh=None): ''' This function uses Gauss divergence theorem to compute divergence of u inside the cell by integrating normal fluxes across the cell boundary. If u is a vector or tensor field the result of computation is diverence of u in the cell center = DG0 scalar/vector function. For scalar fields, the result is grad(u) = DG0 vector function. The fluxes are computed by midpoint rule and as such the computed divergence is exact for linear fields. ''' # Require u to be GenericFunction assert isinstance(u, GenericFunction)
#! /usr/bin/env python import os from dolfin import compile_extension_module # compile the extension modules fv = {} for d in [2, 3]: dir = os.path.dirname(os.path.realpath(__file__)) header_file = open('{0}/include/fvm_{1}d.hh'.format(dir,d)) code = '\n'.join(header_file.readlines()) fv[d] = compile_extension_module(code) # wrapper around the different implementations def advance(c, c0, u, dt): Q = c.function_space() d = Q.mesh().topology().dim() return fv[d].advance(c.vector(), c0.vector(), Q, u, dt)
import os abspath = os.path.dirname(os.path.abspath(__file__)) source_directory = os.path.join(abspath, "cpp_rand") header_file = open(os.path.join(source_directory, "PRNG.h"), "r") code = header_file.read() header_file.close() cpp_sources = ["PRNG.cpp"] include_dirs = [".", source_directory] for ss in ['PROFILE_INSTALL_DIR', 'PETSC_DIR', 'SLEPC_DIR']: if ss in os.environ.keys(): include_dirs.append(os.environ[ss] + '/include') cpp_module = dl.compile_extension_module(code=code, source_directory=source_directory, sources=cpp_sources, include_dirs=include_dirs) class Random(cpp_module.Random): """ This class handles parallel generation of random numbers in hippylib. """ def __init__(self, myid=0, nproc=1, blocksize=1000000, seed=1): """ Create a parallel random number number generator. INPUTS: - :code:`myid`: id of the calling process. - :code:`nproc`: number of processor in the communicator.
def test_compile_extension_module_kwargs(): # This test check that instant_kwargs of compile_extension_module # are taken into account when computing signature m2 = compile_extension_module('', cppargs='-O2') m0 = compile_extension_module('', cppargs='') assert not m2.__file__ == m0.__file__
def _compile_module(): fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) fem_code = open(os.path.join(fem_folder, 'interpolation.cpp'), 'r').read() #fem_code = open(os.path.join(fem_folder, 'interpolation_nonmatching2.cpp'), 'r').read() return compile_extension_module(code=fem_code)
__author__ = "Mikael Mortensen <*****@*****.**>" __date__ = "2013-12-13" __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" import os, inspect from dolfin import info, compile_extension_module, Function, FunctionSpace, assemble, TrialFunction, TestFunction, dx, Matrix fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) gradient_code = open(os.path.join(fem_folder, 'gradient_weight.cpp'), 'r').read() compiled_gradient_module = compile_extension_module(code=gradient_code) def weighted_gradient_matrix(mesh, i, family='CG', degree=1, constrained_domain=None): """Compute weighted gradient matrix The matrix allows you to compute the gradient of a P1 Function through a simple matrix vector product CG family: p_ is the pressure solution on CG1 dPdX = weighted_gradient_matrix(mesh, 0, 'CG', degree) V = FunctionSpace(mesh, 'CG', degree) dpdx = Function(V) dpdx.vector()[:] = dPdX * p_.vector() The space for dpdx must be continuous Lagrange of some order CR family: p_ is the pressure solution on CR dPdX = weighted_gradient_matrix(mesh, 0, 'CR', 1) V = FunctionSpace(mesh, 'CR', 1) dpdx = Function(V)
def compile_module(): fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) memory_code = open(os.path.join(fem_folder, 'getMemoryUsage.cpp'), 'r').read() return compile_extension_module(code=memory_code)
# pylama:ignore=E731 from math import pi, sin, cos, sqrt, tan import numpy as np from dolfin import Mesh, MeshEditor, DynamicMeshEditor, RectangleMesh, \ UnitSquareMesh, Point, UnitCubeMesh, BoxMesh, compile_extension_module from mshr import Circle, UnitSphereMesh, generate_mesh, Polygon from paramchecker import evaluate, ParamChecker, clip, flatten np.seterr(divide='ignore', invalid='ignore') np.set_printoptions(precision=5, suppress=True) # compile c++ code with open("cpp/buildmesh.cpp", "r") as f: code = f.read() builder = compile_extension_module(code=code) # , source_directory="cpp" # include_dirs=["."]) def CircleMesh(p, r, s): """ mshr has no CircleMesh. """ return generate_mesh(Circle(p, r, max(int(4 * pi / s), 4)), int(2 / s)) class GenericDomain(ParamChecker): """ Abstract superclass of all domains used for eigenvalue calculations. Parameters are set using eval(params) method. Mesh can be obtained from get() method, or by calling an object.
#include <petscvec.h> #include <dolfin/la/PETScVector.h> namespace dolfin { void PETScVector_pow(PETScVector& x, double p) { dolfin_assert(x.vec()); PetscErrorCode ierr = VecPow(x.vec(), p); if (ierr != 0) x.petsc_error(ierr, "utils.py", "VecPow"); } } """ # Power inplace PETScVector_ipow = compile_extension_module(pow_wrapper_code).PETScVector_pow # Power def pow(*args): try: return __builtin__.pow(*args) except TypeError: assert len(args) == 2 and isinstance(args[0], PETScVector) x = PETScVector(args[0]) PETScVector_ipow(x, args[1]) return x pow.__doc__ = __builtin__.pow.__doc__ + "\n\n" + PETScVector_ipow.__doc__ def mkdir_p(name): """$ mkdir -p name"""
import os, inspect from dolfin import compile_extension_module, Function, FunctionSpace, assemble,\ TrialFunction, TestFunction, dx, PETScMatrix, VectorFunctionSpace, dot fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) i_code = open(os.path.join(fem_folder, 'cr_interpolation.cpp'), 'r').read() compiled_i_module = compile_extension_module(code=i_code) def cg1_cr_interpolation_matrix(mesh, constrained_domain=None): ''' Compute matrix that allows fast interpolation of CG1 function to Couzeix-Raviart space. ''' CG1 = VectorFunctionSpace(mesh, 'CG', 1, constrained_domain=constrained_domain) CR = VectorFunctionSpace(mesh, 'CR', 1, constrained_domain=constrained_domain) # Get the matrix with approximate sparsity as the interpolation matrix u = TrialFunction(CG1) v = TestFunction(CR) I = PETScMatrix() assemble(dot(u, v)*dx, tensor=I) # Fill the interpolation matrix d = mesh.geometry().dim() compiled_i_module.compute_cg1_cr_interpolation_matrix(I, d) return I
def multiphenics_compile_extension_module(*args, **kwargs): # Remove extension from files files = [os.path.splitext(f)[0] for f in args] # Make sure that there are no duplicate files assert len(files) == len( set(files) ), "There seems to be duplicate files. Make sure to include in the list only *.cpp files, not *.h ones." # Process additional declarations if "additional_declarations" in kwargs: additional_declarations = kwargs["additional_declarations"] assert isinstance(additional_declarations, dict) assert "pre" in additional_declarations assert "post" in additional_declarations # Store pre additional declarations in a format compatible with dolfin signature kwargs["additional_declarations"] = additional_declarations["pre"] # Store post additional declaration in global variable if isinstance(additional_declarations["post"], bytes): additional_declarations["post"] = additional_declarations[ "post"].decode("utf8") extended_write_interfacefile.additional_declarations__post = additional_declarations[ "post"] # Extract folders multiphenics_root = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), "../..")) multiphenics_folder = os.path.join(multiphenics_root, "multiphenics") # Extract files multiphenics_headers = [ os.path.join(multiphenics_folder, f + ".h") for f in files ] multiphenics_sources = [ os.path.join(multiphenics_folder, f + ".cpp") for f in files ] assert len(multiphenics_headers) == len(multiphenics_sources) # Make sure that there are no files missing for (extension, typename, multiphenics_list_to_check) in zip( ["h", "cpp"], ["headers", "sources"], [multiphenics_headers, multiphenics_sources]): all_multiphenics_files = set( glob.glob( os.path.join(multiphenics_folder, "[!python]*", "*." + extension))) sorted_multiphenics_files = set(multiphenics_list_to_check) if len(sorted_multiphenics_files) > len(all_multiphenics_files): raise AssertionError( "Input " + typename + " list contains more files than ones present in the library. The files " + str(sorted_multiphenics_files - all_multiphenics_files) + " seem not to exist.") elif len(sorted_multiphenics_files) < len(all_multiphenics_files): raise AssertionError("Input " + typename + " list is not complete. The files " + str(all_multiphenics_files - sorted_multiphenics_files) + " are missing.") else: assert sorted_multiphenics_files == all_multiphenics_files, "Input " + typename + " list contains different files than ones present in the library. The files " + str( sorted_multiphenics_files - all_multiphenics_files) + " seem not to exist." # Read in the code multiphenics_code = replace_multiphenics_namespace("\n".join( [open(h).read() for h in multiphenics_headers])) # Make sure to force recompilation if multiphenics_last_edit = max( # 1. dolfin has changed os.path.getmtime(dolfin.__file__), # 2. any block header file has changed # (make would be smarter, forcing recompilation only if headers included in current sources have changed) max([os.path.getmtime(h) for h in multiphenics_headers]), # 3. source files have been changed max([os.path.getmtime(s) for s in multiphenics_sources])) # Mimic the module name assignment as done in # dolfin/compilemodules/compilemodule.py, # but forcing recompilation if library code # has been modified multiphenics_module_signature = hashlib.sha1(( repr(multiphenics_code) + # Standard dolfin dolfin.__version__ + str(_interface_version) + ffc.ufc_signature() + sys.version + repr(canonicalize_metadata(kwargs)) + # Customization str(multiphenics_last_edit)).encode("utf-8")).hexdigest() multiphenics_module_name = "multiphenics_" + multiphenics_module_signature # Instant requires source files to be relative to the source directory multiphenics_headers = [ os.path.relpath(s, multiphenics_folder) for s in multiphenics_headers ] multiphenics_sources = [ os.path.relpath(s, multiphenics_folder) for s in multiphenics_sources ] # Patch Instant patch_instant() # Set include dirs multiphenics_include_dirs = list() if "PETSC_DIR" in os.environ: multiphenics_include_dirs.append(os.environ["PETSC_DIR"] + "/include") if "SLEPC_DIR" in os.environ: multiphenics_include_dirs.append(os.environ["SLEPC_DIR"] + "/include") # Call DOLFIN's compile_extension_module cpp = compile_extension_module(code=multiphenics_code, source_directory=multiphenics_folder, local_headers=multiphenics_headers, sources=multiphenics_sources, include_dirs=multiphenics_include_dirs, module_name=multiphenics_module_name, **kwargs) # Restore original Instant configuration undo_patch_instant() # Return compiled module return cpp
__author__ = "Mikael Mortensen <*****@*****.**>" __date__ = "2013-12-13" __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" import os, inspect from dolfin import Function, compile_extension_module fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) fem_code = open(os.path.join(fem_folder, 'interpolation.cpp'), 'r').read() #fem_code = open(os.path.join(fem_folder, 'interpolation_nonmatching2.cpp'), 'r').read() compiled_fem_module = compile_extension_module(code=fem_code) def interpolate_nonmatching_mesh(u0, V): """Interpolate from GenericFunction u0 to FunctionSpace V. The FunctionSpace V can have a different mesh than that of u0, if u0 has a mesh. """ u = Function(V) compiled_fem_module.interpolate_nonmatching_mesh(u0, u) return u
def get_compile_cpp_code(): return compile_extension_module(**inst_params)
return "superlu_dist"; #elif PETSC_HAVE_PASTIX return "pastix"; #else throw std::logic_error("No suitable solver for parallel LU found"); #endif } } """ if has_pybind11(): cpp_code = "".join([ """ #include <petscksp.h> #include <dolfin/common/MPI.h> #include <pybind11/pybind11.h> """, cpp_code, """ PYBIND11_MODULE(SIGNATURE, m) { m.def("get_default_linear_solver", &get_default_linear_solver); } """ ]) get_default_linear_solver = compile_cpp_code( cpp_code).get_default_linear_solver else: get_default_linear_solver = compile_extension_module( cpp_code, additional_system_headers=["petscksp.h", "dolfin/common/MPI.h" ]).get_default_linear_solver
__author__ = "Mikael Mortensen <*****@*****.**>" __date__ = "2014-01-08" __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" import os, inspect from dolfin import compile_extension_module fem_folder = os.path.abspath(os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) memory_code = open(os.path.join(fem_folder, 'common.cpp'), 'r').read() compiled_module = compile_extension_module(code=memory_code) def getMemoryUsage(rss=True): return compiled_module.getMemoryUsage(rss) def SetMatrixValue(A, val): compiled_module.SetMatrixValue(A, val)
__author__ = "Mikael Mortensen <*****@*****.**>" __date__ = "2013-12-13" __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" import os, inspect from dolfin import Function, compile_extension_module fem_folder = os.path.abspath( os.path.join(inspect.getfile(inspect.currentframe()), "../fem")) fem_code = open(os.path.join(fem_folder, 'interpolation.cpp'), 'r').read() #fem_code = open(os.path.join(fem_folder, 'interpolation_nonmatching2.cpp'), 'r').read() compiled_fem_module = compile_extension_module(code=fem_code) def interpolate_nonmatching_mesh(u0, V): """Interpolate from GenericFunction u0 to FunctionSpace V. The FunctionSpace V can have a different mesh than that of u0, if u0 has a mesh. """ u = Function(V) compiled_fem_module.interpolate(u0, u) return u
sdir = os.path.join(abspath, "AssemblePointwiseObservation") header_file = open(os.path.join(sdir, "AssemblePointwiseObservation.h"), "r") code = header_file.read() header_file.close() #check the dolfin version to decide which cpp to include if dlversion() == (1, 4, 0): cpp_sources = ["AssemblePointwiseObservation_v14.cpp"] elif dlversion() == (1, 5, 0): cpp_sources = ["AssemblePointwiseObservation_v15.cpp"] elif dlversion() >= (1, 6, 0): cpp_sources = ["AssemblePointwiseObservation_v16.cpp"] else: raise Exception("Dolfin Version") cpp_module = dl.compile_extension_module(code=code, source_directory=sdir, sources=cpp_sources, include_dirs=[".", sdir]) def assemblePointwiseObservation(Vh, targets): """ Assemble the pointwise observation matrix: Input - Vh: FEniCS finite element space - targets: observation points (numpy array) Note: This Function will not work in parallel!!! """ #Ensure that PetscInitialize is called dummy = dl.assemble( dl.inner(dl.TrialFunction(Vh), dl.TestFunction(Vh)) * dl.dx)
from numbers import Number _sqrt_in_place_code = """ #include "petscvec.h" #include <dolfin/la/PETScVector.h> namespace dolfin { void sqrt_in_place(std::shared_ptr<GenericVector> vec) { VecSqrtAbs(vec->down_cast<PETScVector>().vec()); } } """ try: sqrt_in_place = compile_extension_module(_sqrt_in_place_code).sqrt_in_place except: sqrt_in_place = None class Magnitude(MetaField): """ Compute the magnitude of a Function-evaluated Field. Supports function spaces where all subspaces are equal. """ def before_first_compute(self, get): u = get(self.valuename) if isinstance(u, Function): if LooseVersion(dolfin_version()) > LooseVersion("1.6.0"):
import dolfin as dl import numpy as np import os #Compile the cpp module: cpp_sources = ["myla.cpp"] cpp_module = dl.compile_extension_module( sources=cpp_sources, include_dirs=["."]) #Generate a mesh and some matrices nx = 32 ny = 32 mesh = dl.UnitSquareMesh(nx, ny) Vh = dl.FunctionSpace(mesh, 'Lagrange', 1) ndof = Vh.dim() uh, vh = dl.TrialFunction(Vh), dl.TestFunction(Vh) A = dl.assemble( dl.inner( dl.nabla_grad(uh), dl.nabla_grad(vh) ) *dl.dx ) M = dl.assemble( dl.inner( uh, vh ) *dl.dx ) ones = dl.interpolate(dl.Constant(1.), Vh).vector() Mones = M*ones s = Mones s.set_local( np.ones(ndof) / Mones.array() ) M.zero() M.set_diagonal(s) myla = cpp_module.cpp_linalg() B = myla.MatPtAP(M, A)