Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
# BasedOnStyle: LLVM # but heavily modified
# Modified to resemble Black format for Python
# The if statements are sub-optimal, it needs dangling parenthesis (D33029).
# https://reviews.llvm.org/D33029
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakStringLiterals: false
ColumnLimit: 88
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
IndentCaseLabels: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: c++11
TabWidth: 4
UseCRLF: false
UseTab: Never
...
18 changes: 18 additions & 0 deletions .github/workflows/clang-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Lint clang-format

on:
- push
- pull_request

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Get clang-format-lint-action as image
run: |
docker build -t doozyx/clang-format-lint-action "github.com/DoozyX/clang-format-lint-action"
- name: Run clang-format lint
run: |
docker run --rm --workdir /src -v $(pwd):/src doozyx/clang-format-lint-action --clang-format-executable /clang-format/clang-format10 -r --exclude .git include/*.hpp src/*.cpp
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "pybind11"]
path = pybind11
url = https://github.com/pybind/pybind11.git
[submodule "PoPS"]
path = PoPS
url = https://github.com/ncsu-landscape-dynamics/PoPS.git
[submodule "pops-core"]
path = pops-core
url = https://github.com/ncsu-landscape-dynamics/pops-core.git
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ project(PyPoPS
#include_directories("${PROJECT_SOURCE_DIR}/")

add_subdirectory(pybind11)
add_subdirectory(PoPS)
add_subdirectory(pops-core)

pybind11_add_module(_pypops src/pypops.cpp include/raster.hpp include/helpers.hpp)

Expand Down
1 change: 0 additions & 1 deletion PoPS
Submodule PoPS deleted from 835748
38 changes: 26 additions & 12 deletions include/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,27 @@
#include <string>
#include <sstream>

template <typename T>
std::string to_string(const T& value) {
template<typename T>
std::string to_string(const T& value)
{
std::stringstream stream;
stream << value;
return stream.str();
}

std::string to_string(const pybind11::buffer_info& info) {
std::string to_string(const pybind11::buffer_info& info)
{
std::stringstream stream;
stream << "itemsize: " << info.itemsize << "\n"
<< "format: " << info.format << "\n"
<< "ndim: " << info.ndim << "\n"
<< "ndim: " << info.ndim
<< "\n"
// TODO: generalize
<< "shape[0], shape[1]: " << info.shape[0] << ", " << info.shape[1] << "\n"
<< "strides[0], strides[1]: " << info.strides[0] << ", " << info.strides[1] << "\n"
<< "strides / itemsize: " << info.strides[0] / info.itemsize << ", " << info.strides[1] / info.itemsize << "\n";
<< "strides[0], strides[1]: " << info.strides[0] << ", " << info.strides[1]
<< "\n"
<< "strides / itemsize: " << info.strides[0] / info.itemsize << ", "
<< info.strides[1] / info.itemsize << "\n";
// TODO: tell if it is C or F order (silent otherwise)
return stream.str();
}
Expand All @@ -48,13 +53,20 @@ void compatible_scalar_type_or_throw(const pybind11::buffer_info& info)

if (diff_format && !diff_size)
throw std::runtime_error(
"Incompatible scalar format in array: expected " + expected_format + ", got " + provided_format + " (both have " + expected_size + " bytes, using C++ type with id: "+ expected_cpp_typeid + ")");
"Incompatible scalar format in array: expected " + expected_format
+ ", got " + provided_format + " (both have " + expected_size
+ " bytes, using C++ type with id: " + expected_cpp_typeid + ")");
else if (!diff_format && diff_size)
throw std::runtime_error(
"Incompatible scalar size in array: expected " + expected_size + ", got " + provided_size + " (both have " + expected_format + " format, using C++ type with id: "+ expected_cpp_typeid + ")");
"Incompatible scalar size in array: expected " + expected_size + ", got "
+ provided_size + " (both have " + expected_format
+ " format, using C++ type with id: " + expected_cpp_typeid + ")");
else
throw std::runtime_error(
"Incompatible scalar in array: expected " + expected_format + " format with " + expected_size + " bytes, got " + provided_format + " format with " + provided_size + " bytes (using C++ type with id: "+ expected_cpp_typeid + ")");
"Incompatible scalar in array: expected " + expected_format
+ " format with " + expected_size + " bytes, got " + provided_format
+ " format with " + provided_size
+ " bytes (using C++ type with id: " + expected_cpp_typeid + ")");
}

template<typename Number>
Expand All @@ -64,8 +76,10 @@ void raster_compatible_or_throw(const pybind11::buffer_info& info)
if (info.ndim != 2)
throw std::runtime_error("Incompatible buffer dimension: expected a 2D array!");
if (info.strides[0] != info.itemsize * info.shape[1]
&& info.strides[1] != info.itemsize)
throw std::runtime_error("Incompatible order: expected row-major (C-style) order. Got " + to_string(info)); // TODO: tell if it is the F order
&& info.strides[1] != info.itemsize)
throw std::runtime_error(
"Incompatible order: expected row-major (C-style) order. Got "
+ to_string(info)); // TODO: tell if it is the F order
}

#endif // HELPERS_HPP
#endif // HELPERS_HPP
44 changes: 20 additions & 24 deletions include/raster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ RasterType py_buffer_info_to_raster(pybind11::buffer b)
// TODO: The return from function does not work, so unused for now.
// Perhaps a 3D array will be needed for interface anyway.
template<typename RasterType>
std::vector<RasterType> py_buffers_info_to_rasters(std::vector<pybind11::buffer>& buffers)
std::vector<RasterType>
py_buffers_info_to_rasters(std::vector<pybind11::buffer>& buffers)
{
std::vector<RasterType> rasters;
rasters.reserve(buffers.size());
Expand All @@ -93,33 +94,29 @@ pybind11::buffer_info raster_to_py_buffer_info(RasterType& raster)
// Buffer dimensions
{raster.rows(), raster.cols()},
// Strides (in bytes) for each index, row-major order
{sizeof(NumberType) * raster.cols(),
sizeof(NumberType) * 1}
);
{sizeof(NumberType) * raster.cols(), sizeof(NumberType) * 1});
}

// We use template parameter instead of py::module to avoid this
// implementation detail by duck typing.
template<typename RasterType, typename PythonModule>
void raster_class(PythonModule& m, const std::string& name) {
void raster_class(PythonModule& m, const std::string& name)
{
pybind11::class_<RasterType>(m, name.c_str(), pybind11::buffer_protocol())
.def(pybind11::init([](pybind11::buffer b) {
return py_buffer_info_to_raster<RasterType>(b);
// return by raw pointer
// or: return std::make_unique<Foo>(...); // return by holder
// or: return Foo(...); // return by value (move constructor)
}))
.def(pybind11::init([](pybind11::buffer b) {
return py_buffer_info_to_raster<RasterType>(b);
// return by raw pointer
// or: return std::make_unique<Foo>(...); // return by holder
// or: return Foo(...); // return by value (move constructor)
}))

.def_buffer(
raster_to_py_buffer_info<RasterType>
);
.def_buffer(raster_to_py_buffer_info<RasterType>);
}

template<typename NumberType, typename PythonModule>
void test_compatibility(PythonModule m, std::string name)
{
m.def(name.c_str(),
[](pybind11::buffer b) {
m.def(name.c_str(), [](pybind11::buffer b) {
pybind11::buffer_info info = b.request();
raster_compatible_or_throw<NumberType>(info);
});
Expand All @@ -131,17 +128,16 @@ pybind11::object get_float_raster_scalar_type()
// https://docs.scipy.org/doc/numpy/user/basics.types.html
pybind11::object dtype = np.attr("dtype");
std::vector<pybind11::object> candidates = {
// numpy.attr("double").attr("itemsize"),
// numpy.attr("single"),
// numpy.attr("longdouble"),
// numpy.attr("float16"),
// numpy.attr("half")
// numpy.attr("double").attr("itemsize"),
// numpy.attr("single"),
// numpy.attr("longdouble"),
// numpy.attr("float16"),
// numpy.attr("half")
dtype("float64"),
dtype("float32"),
dtype("double"),
dtype("single"),
dtype("longdouble")
};
dtype("longdouble")};
for (const auto candidate : candidates) {
if (sizeof(Float) == pybind11::int_(candidate.attr("itemsize")))
return candidate;
Expand All @@ -166,4 +162,4 @@ pybind11::object get_integer_raster_scalar_type()
throw std::logic_error("Cannot find a compatible scalar type");
}

#endif // RASTER_HPP
#endif // RASTER_HPP
1 change: 1 addition & 0 deletions pops-core
Submodule pops-core added at 8edb66
19 changes: 17 additions & 2 deletions pypops/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,36 @@
"""PyPoPS - Main simulation interface
"""

import json

import _pypops
from _pypops import Config


int_type = _pypops.get_integer_raster_scalar_type()
float_type = _pypops.get_float_raster_scalar_type()


def json_to_config(config):
"""Run one PoPS simulation"""
with open(config) as config_file:
config_values = json.load(config_file)
result = Config()
for key, value in config_values.items():
setattr(result, key, value)
return result


def pops(
random_seed,
steps,
use_lethal_temperature=False,
lethal_temperature=None,
infected=None,
susceptible=None,
exposed=None,
total_plants=None,
mortality_tracker=None,
died=None,
# dispersers=dispersers,
weather=False,
temperature=None,
Expand All @@ -50,13 +64,14 @@ def pops(
"""Run one PoPS simulation"""
result = _pypops.test_simulation(
random_seed=random_seed,
steps=steps,
use_lethal_temperature=use_lethal_temperature,
lethal_temperature=lethal_temperature,
infected=infected,
susceptible=susceptible,
exposed=exposed,
total_plants=total_plants,
mortality_tracker=mortality_tracker,
died=died,
weather=weather,
temperature=temperature,
weather_coefficient=weather_coefficient,
Expand Down
Loading