Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Complex Boundaries #366

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion cli/new_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@


def ValidateSimName(sim_name):
pattern = re.compile("^[a-zA-Z]+[a-zA-Z0-9\-_]+$")
pattern = re.compile(r"^[a-zA-Z]+[a-zA-Z0-9\-_]+$")
if not pattern.match(sim_name):
Print.error('Error: simulation name "{}" is not valid.'.format(sim_name))
Print.error(" Allowed characters are a-z A-Z 0-9 - and _")
Expand Down
2 changes: 1 addition & 1 deletion cli/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
def GetBinaryName():
with open("CMakeLists.txt") as f:
content = f.read()
return re.search("project\((.*)\)", content).group(1)
return re.search(r"project\((.*)\)", content).group(1)

6 changes: 5 additions & 1 deletion cmake/external/ROOT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ if(APPLE)
"${DETECTED_OS_VERS}" MATCHES "^osx-11.7")
execute_process(COMMAND bash "-c" "xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9\.]*)/\\1/p'" OUTPUT_VARIABLE XCODE_VERS)
message(STATUS "##### XCODE version: ${XCODE_VERS}")
if("${XCODE_VERS}" GREATER_EQUAL "15.0")
if("${XCODE_VERS}" GREATER_EQUAL "15.3")
message(STATUS "##### Using ROOT builds for XCODE 15.3")
set(ROOT_TAR_FILE root_v6.30.06_cxx17_python3.9_osx-xcode-15.3-${DETECTED_ARCH}.tar.gz)
set(ROOT_SHA_KEY osx-xcode-15.3-${DETECTED_ARCH}-ROOT)
elseif("${XCODE_VERS}" GREATER_EQUAL "15.0")
message(STATUS "##### Using ROOT builds for XCODE 15.2")
set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-15.2-${DETECTED_ARCH}.tar.gz)
set(ROOT_SHA_KEY osx-xcode-15.2-${DETECTED_ARCH}-ROOT)
Expand Down
6 changes: 6 additions & 0 deletions cmake/external/SHA256Digests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ SET(osx-14.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e8055
SET(osx-14.2-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4)
SET(osx-14.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb)
SET(osx-14.3-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4)
SET(osx-14.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb)
SET(osx-14.4-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4)
SET(osx-14.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb)
SET(osx-14.5-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4)
SET(osx-xcode-13.1-i386-ROOT be97dd72022c8d082fbe4394f18b55c4920f20b138cfff1b5fc2b41d397ac203)
SET(osx-xcode-13.1-arm64-ROOT 0a55b91c6df42d152b7943912e134f05c3872a73e73fcc129ee87fd847240ec8)
SET(osx-xcode-14.1-i386-ROOT 001311608512b24535bb9710b8baf006bd00e9b0595fd6bdf900d28b1e22c395)
Expand All @@ -68,6 +72,8 @@ SET(osx-xcode-14.3-i386-ROOT c4f4c7a9848121ae19f3fe3c40c5812813ed42d9dfa7f1948f6
SET(osx-xcode-14.3-arm64-ROOT 6ffcfaadd4de627cffde2e42fded9175b730769071396d7abdabeefc2714839a)
SET(osx-xcode-15.2-i386-ROOT 3dea500451dc2c84d150a7d5f4b27d2cba3e867d7c775b744ac898f9f6e51249)
SET(osx-xcode-15.2-arm64-ROOT 677429937f13a44a088b71851f0af111509bf81a9a25a299c905b6c9f7249587)
SET(osx-xcode-15.3-i386-ROOT 52cef545acf679c3e491c9ef14e18edee454c90309b7fcf5f36fc2e659bdbde5)
SET(osx-xcode-15.3-arm64-ROOT 3ee0885c329fab9a965c278cc491db82dcbde3999a96ac80d6f5145fb6794d1e)

SET(ubuntu-18.04-Libroadrunner bf9293c1c95d0b65227bd7e08c0048116ba851bcec5028ef72ea13762ef79276)
SET(ubuntu-18.04-ParaView e3fd74b13e9a4086988c5104c6b8d95c56365d25b491706a8e72018d0e5c76f1)
Expand Down
38 changes: 37 additions & 1 deletion src/core/diffusion/diffusion_grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ std::string BoundaryTypeToString(const BoundaryConditionType& type) {
return "Dirichlet";
case BoundaryConditionType::kPeriodic:
return "Periodic";
case BoundaryConditionType::kComplex:
return "Complex";
default:
return "unknown";
}
Expand All @@ -52,6 +54,8 @@ BoundaryConditionType StringToBoundaryType(const std::string& type) {
return BoundaryConditionType::kDirichlet;
} else if (type == "Periodic") {
return BoundaryConditionType::kPeriodic;
} else if (type == "Complex") {
return BoundaryConditionType::kComplex;
} else {
Log::Fatal("StringToBoundaryType", "Unknown boundary type: ", type);
return BoundaryConditionType::kNeumann;
Expand All @@ -64,7 +68,9 @@ DiffusionGrid::DiffusionGrid(int substance_id,
: dc_({{1 - dc, dc / 6, dc / 6, dc / 6, dc / 6, dc / 6, dc / 6}}),
mu_(mu),
resolution_(resolution),
boundary_condition_(std::make_unique<ConstantBoundaryCondition>(0.0)) {
boundary_condition_(std::make_unique<ConstantBoundaryCondition>(0.0)),
boundary_condition_neumann_(std::make_unique<ConstantBoundaryCondition>(0.0)),
boundary_condition_dirichlet_(std::make_unique<ConstantBoundaryCondition>(0.0)) {
// Compatibility with new abstract interface
SetContinuumId(substance_id);
SetContinuumName(substance_name);
Expand All @@ -81,6 +87,24 @@ void DiffusionGrid::Initialize() {
"')");
}

if (bc_type_ == BoundaryConditionType::kComplex) {
auto* param = Simulation::GetActive()->GetParam();
complex_bct_ = {param->diffusion_bc_x_min,
param->diffusion_bc_x_max,
param->diffusion_bc_y_min,
param->diffusion_bc_y_max,
param->diffusion_bc_z_min,
param->diffusion_bc_z_max};
for (int i=0; i<6; i++) {
if (complex_bct_[i] != "Neumann" && complex_bct_[i] != "Dirichlet" &&
complex_bct_[i] != "Periodic") {
Log::Fatal("DiffusionGrid::Initialize",
"Complex boundaries: unknown boundary condition ", complex_bct_[i],
". Select 'Neumann', 'Dirichlet' or 'Periodic' for each side of boundary.");
}
}
}

// Get neighbor grid dimensions
auto* env = Simulation::GetActive()->GetEnvironment();
auto bounds = env->GetDimensionThresholds();
Expand Down Expand Up @@ -145,6 +169,8 @@ void DiffusionGrid::Diffuse(real_t dt) {
DiffuseWithNeumann(dt);
} else if (bc_type_ == BoundaryConditionType::kPeriodic) {
DiffuseWithPeriodic(dt);
} else if (bc_type_ == BoundaryConditionType::kComplex) {
DiffuseWithComplex(dt);
} else {
Log::Error(
"EulerGrid::Diffuse", "Boundary condition of type '",
Expand Down Expand Up @@ -533,6 +559,16 @@ void DiffusionGrid::SetBoundaryCondition(
boundary_condition_ = std::move(bc);
}

void DiffusionGrid::SetBoundaryCondition_neumann(
std::unique_ptr<BoundaryCondition> bc) {
boundary_condition_neumann_ = std::move(bc);
}

void DiffusionGrid::SetBoundaryCondition_dirichlet(
std::unique_ptr<BoundaryCondition> bc) {
boundary_condition_dirichlet_ = std::move(bc);
}

BoundaryCondition* DiffusionGrid::GetBoundaryCondition() const {
return boundary_condition_.get();
}
Expand Down
20 changes: 19 additions & 1 deletion src/core/diffusion/diffusion_grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ enum class BoundaryConditionType {
kNeumann,
kOpenBoundaries,
kClosedBoundaries,
kPeriodic
kPeriodic,
kComplex
};

enum class InteractionMode { kAdditive = 0, kExponential = 1, kLogistic = 2 };
Expand Down Expand Up @@ -121,6 +122,11 @@ class DiffusionGrid : public ScalarField {
/// Compute the diffusion of the substance with Periodic boundary conditions
/// (u_{-1} = {u_N-1}, u_{N} = u_{0}) for a given time step dt.
virtual void DiffuseWithPeriodic(real_t dt) = 0;
/// Compute the diffusion of the substance with Complex boundary conditions,
/// where the boundary type can be Dirichlet, Neumann or Periodic depending on
/// the side of the environment.
virtual void DiffuseWithComplex(real_t dt) = 0;


/// Calculates the gradient for each box in the diffusion grid.
/// The gradient is calculated in each direction (x, y, z) as following:
Expand Down Expand Up @@ -323,6 +329,10 @@ class DiffusionGrid : public ScalarField {
/// `ConstantBoundaryCondition`
void SetBoundaryCondition(std::unique_ptr<BoundaryCondition> bc);

void SetBoundaryCondition_neumann(std::unique_ptr<BoundaryCondition> bc);

void SetBoundaryCondition_dirichlet(std::unique_ptr<BoundaryCondition> bc);

/// @brief Returns the boundary condition. Does not transfer ownership.
/// @return const Pointer to the boundary condition
BoundaryCondition* GetBoundaryCondition() const;
Expand Down Expand Up @@ -415,6 +425,14 @@ class DiffusionGrid : public ScalarField {
BoundaryConditionType bc_type_ = BoundaryConditionType::kDirichlet;
/// Object that implements the boundary conditions.
std::unique_ptr<BoundaryCondition> boundary_condition_ = nullptr;
/// Object that implements the boundary condition for Neumann type when
/// using complex boundaries.
std::unique_ptr<BoundaryCondition> boundary_condition_neumann_ = nullptr;
/// Object that implements the boundary condition for Dirichlet type when
/// using complex boundaries.
std::unique_ptr<BoundaryCondition> boundary_condition_dirichlet_ = nullptr;
/// Stores the boundary condition types when using complex boundaries.
std::array<std::string, 6> complex_bct_ = {{""}};
/// Flag to indicate if the grid is initialized
bool initialized_ = false;
/// Flag to indicate if we want to print information about the grid after
Expand Down
146 changes: 146 additions & 0 deletions src/core/diffusion/euler_grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,150 @@ void EulerGrid::DiffuseWithPeriodic(real_t dt) {
c1_.swap(c2_);
}




void EulerGrid::DiffuseWithComplex(real_t dt) {

const auto nx = resolution_;
const auto ny = resolution_;
const auto nz = resolution_;
const auto num_boxes = nx * ny * nz;

const real_t d = 1 - dc_[0];
const real_t dx = box_length_;

const auto sim_time = GetSimulatedTime();

constexpr size_t YBF = 16;
#pragma omp parallel for collapse(2)
for (size_t yy = 0; yy < ny; yy += YBF) {
for (size_t z = 0; z < nz; z++) {
size_t ymax = yy + YBF;
if (ymax >= ny) {
ymax = ny;
}
for (size_t y = yy; y < ymax; y++) {
size_t x{0};
size_t c{0};
size_t l{0};
size_t r{0};
size_t n{0};
size_t s{0};
size_t b{0};
size_t t{0};
c = x + y * nx + z * nx * ny;
#pragma omp simd
for (x = 0; x < nx; x++) {
l = c - 1;
r = c + 1;
n = c - nx;
s = c + nx;
b = c - nx * ny;
t = c + nx * ny;

// Clamp to avoid out of bounds access. Clamped values are initialized
// to a wrong value but will be overwritten by the boundary condition
// evaluation. All other values are correct.
real_t left{c1_[std::clamp(l, size_t{0}, num_boxes - 1)]};
real_t right{c1_[std::clamp(r, size_t{0}, num_boxes - 1)]};
real_t bottom{c1_[std::clamp(b, size_t{0}, num_boxes - 1)]};
real_t top{c1_[std::clamp(t, size_t{0}, num_boxes - 1)]};
real_t north{c1_[std::clamp(n, size_t{0}, num_boxes - 1)]};
real_t south{c1_[std::clamp(s, size_t{0}, num_boxes - 1)]};

real_t CF_x{2.0};
real_t CF_y{2.0};
real_t CF_z{2.0};

if (x == 0 || x == (nx - 1) || y == 0 || y == (ny - 1) || z == 0 ||
z == (nz - 1)) {

real_t real_x = grid_dimensions_[0] + x * box_length_;
real_t real_y = grid_dimensions_[2] + y * box_length_;
real_t real_z = grid_dimensions_[4] + z * box_length_;

real_t boundary_value_neumann = boundary_condition_neumann_->Evaluate(real_x, real_y, real_z, sim_time);
real_t boundary_value_dirichlet = boundary_condition_dirichlet_->Evaluate(real_x, real_y, real_z, sim_time);

if (x == 0) {
if (complex_bct_[0] == "Dirichlet") {
left = boundary_value_dirichlet;
} else if (complex_bct_[0] == "Neumann") {
left = - boundary_value_neumann * box_length_;
CF_x -= 1.0;
} else if (complex_bct_[0] == "Periodic") {
l = nx-1 + y * nx + z * nx * ny;
left = c1_[l];
}
} else if (x == (nx - 1)) {
if (complex_bct_[1] == "Dirichlet") {
right = boundary_value_dirichlet;
} else if (complex_bct_[1] == "Neumann") {
right = - boundary_value_neumann * box_length_;
CF_x -= 1.0;
} else if (complex_bct_[1] == "Periodic") {
r = 0 + y * nx + z * nx * ny;
right = c1_[r];
}
}

if (y == 0) {
if (complex_bct_[2] == "Dirichlet") {
north = boundary_value_dirichlet;
} else if (complex_bct_[2] == "Neumann") {
north = - boundary_value_neumann * box_length_;
CF_y -= 1.0;
} else if (complex_bct_[2] == "Periodic") {
n = x + (ny-1) * nx + z * nx * ny;
north = c1_[n];
}
} else if (y == (ny - 1)) {
if (complex_bct_[3] == "Dirichlet") {
south = boundary_value_dirichlet;
} else if (complex_bct_[3] == "Neumann") {
south = - boundary_value_neumann * box_length_;
CF_y -= 1.0;
} else if (complex_bct_[3] == "Periodic") {
s = x + 0 * nx + z * nx * ny;
south = c1_[s];
}
}

if (z == 0) {
if (complex_bct_[4] == "Dirichlet") {
bottom = boundary_value_dirichlet;
} else if (complex_bct_[4] == "Neumann") {
bottom = - boundary_value_neumann * box_length_;
CF_z -= 1.0;
} else if (complex_bct_[4] == "Periodic") {
b = x + y * nx + (nz-1) * nx * ny;
bottom = c1_[b];
}
} else if (z == (nz - 1)) {
if (complex_bct_[5] == "Dirichlet") {
top = boundary_value_dirichlet;
} else if (complex_bct_[5] == "Neumann") {
top = - boundary_value_neumann * box_length_;
CF_z -= 1.0;
} else if (complex_bct_[5] == "Periodic") {
t = x + y * nx + 0 * nx * ny;
top = c1_[t];
}
}
}

c2_[c] = c1_[c] * (1 - (mu_ * dt)) + ( (d * dt / (dx*dx) ) * (left + right - CF_x*c1_[c]) )
+ ( (d * dt / (dx*dx) ) * (south + north - CF_y*c1_[c]) )
+ ( (d * dt / (dx*dx) ) * (top + bottom - CF_z*c1_[c]) );

++c;
}
} // tile ny
} // tile nz
} // block ny
c1_.swap(c2_);
}


} // namespace bdm
1 change: 1 addition & 0 deletions src/core/diffusion/euler_grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class EulerGrid : public DiffusionGrid {
void DiffuseWithDirichlet(real_t dt) override;
void DiffuseWithNeumann(real_t dt) override;
void DiffuseWithPeriodic(real_t dt) override;
void DiffuseWithComplex(real_t dt) override;

private:
BDM_CLASS_DEF_OVERRIDE(EulerGrid, 1);
Expand Down
6 changes: 6 additions & 0 deletions src/core/param/param.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ void Param::AssignFromConfig(const std::shared_ptr<cpptoml::table>& config) {
BDM_ASSIGN_CONFIG_VALUE(max_bound, "simulation.max_bound");
BDM_ASSIGN_CONFIG_VALUE(diffusion_boundary_condition,
"simulation.diffusion_boundary_condition");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_x_min, "simulation.diffusion_bc_x_min");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_x_max, "simulation.diffusion_bc_x_max");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_y_min, "simulation.diffusion_bc_y_min");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_y_max, "simulation.diffusion_bc_y_max");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_z_min, "simulation.diffusion_bc_z_min");
BDM_ASSIGN_CONFIG_VALUE(diffusion_bc_z_max, "simulation.diffusion_bc_z_max");
BDM_ASSIGN_CONFIG_VALUE(diffusion_method, "simulation.diffusion_method");
BDM_ASSIGN_CONFIG_VALUE(calculate_gradients,
"simulation.calculate_gradients");
Expand Down
16 changes: 16 additions & 0 deletions src/core/param/param.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ struct Param {
/// diffusion_boundary_condition = "Neumann"
std::string diffusion_boundary_condition = "Neumann";

/// Define the boundary condition of each side of the simulation space
/// when using complex boundaries [Neumann, Dirichlet, Periodic].
/// Default value: `"Neumann"`\n TOML config file:
///
/// [simulation]
/// diffusion_bc_x_min = "Neumann"
/// diffusion_bc_x_max = "Neumann"
/// ....
std::string diffusion_bc_x_min = "Neumann";
std::string diffusion_bc_x_max = "Neumann";
std::string diffusion_bc_y_min = "Neumann";
std::string diffusion_bc_y_max = "Neumann";
std::string diffusion_bc_z_min = "Neumann";
std::string diffusion_bc_z_max = "Neumann";


/// A string for determining diffusion type within the simulation space.
/// Currently, only the method "euler" implementing a FTCS scheme is
/// supported. See for instance here:
Expand Down
1 change: 1 addition & 0 deletions test/unit/core/diffusion_init_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TestGrid : public DiffusionGrid {
void DiffuseWithDirichlet(real_t dt) override { return; };
void DiffuseWithNeumann(real_t dt) override { return; };
void DiffuseWithPeriodic(real_t dt) override { return; };
void DiffuseWithComplex(real_t dt) override { return; };

void Swap() { c1_.swap(c2_); }

Expand Down
Loading
Loading