Since the CompiledSubdomain
class only supports simple inside
expressions, I constructed up a new CompiledPBC
class to get periodic boundary conditions working with C++
for two dimensional rectangular domains of size [lx \times ly]. Here’s the source code. Put it in compiledpbc.py
file to use.
@dokken @bhaveshshrimali Any tips on maybe simplifying it?
Usage:
from compiledpbc import CompiledPBC
pbc = CompiledPBC(lx,ly)
Source:
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Chris N. Richardson and Garth N. Wells
#
# This file is part of DOLFIN.
#
# DOLFIN 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.
#
# DOLFIN 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 DOLFIN. If not, see <http://www.gnu.org/licenses/>.
import dolfin.cpp as cpp
from dolfin.cpp import MPI
from dolfin.cpp.log import log, LogLevel
from dolfin.jit.jit import compile_class, _math_header
def jit_generate(class_data, module_name, signature, parameters):
template_code = """
// Based on https://gcc.gnu.org/wiki/Visibility
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define DLL_EXPORT __attribute__ ((dllexport))
#else
#define DLL_EXPORT __declspec(dllexport)
#endif
#else
#define DLL_EXPORT __attribute__ ((visibility ("default")))
#endif
#include <dolfin/common/Array.h>
#include <dolfin/math/basic.h>
#include <dolfin/mesh/SubDomain.h>
#include <Eigen/Dense>
{math_header}
namespace dolfin
{{
class {classname} : public SubDomain
{{
public:
{members}
{classname}()
{{
{constructor}
}}
// Return true for points inside the sub domain
bool inside(const Eigen::Ref<const Eigen::VectorXd> x, bool on_boundary) const final
{{
bool left = std::fabs(x[0]) < DOLFIN_EPS;
bool bottom = std::fabs(x[1]) < DOLFIN_EPS;
bool right = std::fabs(x[0] - {lengthx}) < DOLFIN_EPS;
bool top = std::fabs(x[1] - {lengthy}) < DOLFIN_EPS;
return ( left || bottom ) && (!( right || top )) && on_boundary;
}}
void map(const Eigen::Ref<const Eigen::VectorXd> x, Eigen::Ref<Eigen::VectorXd> y) const
{{
y[0] = x[0];
y[1] = x[1];
if (std::fabs(x[0] - ({lengthx})) < DOLFIN_EPS)
y[0] -= {lengthx};
if (std::fabs(x[1] - ({lengthy})) < DOLFIN_EPS)
y[1] -= {lengthy};
}}
void set_property(std::string name, double value)
{{
{set_props}
}}
double get_property(std::string name) const
{{
{get_props}
return 0.0;
}}
}};
}}
extern "C" DLL_EXPORT dolfin::SubDomain * create_{classname}()
{{
return new dolfin::{classname};
}}
"""
_set_prop = """ if (name == "{name}") {name} = value;\n"""
_get_prop = """ if (name == "{name}") return {name};\n"""
log(LogLevel.TRACE, "Calling dijitso just-in-time (JIT) compiler for SubDomain.")
lengthx = class_data['statements'][0]
lengthy = class_data['statements'][1]
members = ""
get_props = ""
set_props = ""
for k in class_data['properties']:
members += " double " + k + ";\n"
get_props += _get_prop.format(name=k)
set_props += _set_prop.format(name=k)
classname = signature
code_c = template_code.format(lengthx=lengthx,
lengthy=lengthy,
classname=classname,
math_header=_math_header,
members=members, constructor="",
get_props=get_props,
set_props=set_props)
code_h = ""
depends = []
return code_h, code_c, depends
def compile_pbc(lengthx, lengthy, properties):
mpi_comm = properties.pop("mpi_comm", MPI.comm_world)
cpp_data = {'statements': [lengthx,lengthy], 'properties': properties,
'name': 'subdomain', 'jit_generate': jit_generate}
subdomain = compile_class(cpp_data, mpi_comm=mpi_comm)
return subdomain
class CompiledPBC(cpp.mesh.SubDomain):
def __new__(cls, lengthx, lengthy, **kwargs):
properties = kwargs
return compile_pbc(f'{lengthx:.5E}', f'{lengthy:.5E}', properties)