diff --git a/data/planes.input b/data/planes.input index 6a52e89546296d49a36239f9991f8bc22497b0ed..5de074bf8a14746a8f30ad3e3f612ff34a0c70c9 100644 --- a/data/planes.input +++ b/data/planes.input @@ -1,2 +1,2 @@ -0,1,0,0,0,0,0,1,13 -0,1,0.8,0.015,0.2,0,0,-1,13 +0,1,0.0,0.0,0.0,0.0,0.0,1.0,13 +0,1,0.8,0.015,0.2,0.0,0.0,-1.0,13 diff --git a/examples/dem.py b/examples/dem.py index a8e78b882203923787cd61021c93507a73364a7f..07b68d75f0cb1d82c8dd58dd82b7908c6c1bb6aa 100644 --- a/examples/dem.py +++ b/examples/dem.py @@ -12,7 +12,7 @@ def update_mass_and_inertia(i): inv_inertia[i] = inversed(diagonal_matrix(0.4 * mass[i] * radius[i] * radius[i])) else: - #mass[i] = infinity + mass[i] = infinity inv_inertia[i] = 0.0 @@ -112,7 +112,7 @@ restitutionCoefficient = 0.1 collisionTime_SI = 5e-4 poissonsRatio = 0.22 timeSteps = 10000 -visSpacing = 1 +visSpacing = 100 denseBottomLayer = False bottomLayerOffsetFactor = 1.0 kappa = 2.0 * (1.0 - poissonsRatio) / (2.0 - poissonsRatio) # from Thornton et al diff --git a/src/pairs/code_gen/cgen.py b/src/pairs/code_gen/cgen.py index d38b06134d61acadef76ee93b5c77f1780b707a0..eae9daa622d315547357875fdde27464c7ec824b 100644 --- a/src/pairs/code_gen/cgen.py +++ b/src/pairs/code_gen/cgen.py @@ -206,12 +206,12 @@ class CGen: for array_access in kernel.array_accesses(): type_kw = Types.c_keyword(array_access.type()) - decl = f"{type_kw} a{array_access.id()}" + decl = f"{type_kw} {array_access.name()}" kernel_params += f", {decl}" for scalar_op in kernel.scalar_ops(): type_kw = Types.c_keyword(scalar_op.type()) - decl = f"{type_kw} e{scalar_op.id()}" + decl = f"{type_kw} {scalar_op.name()}" kernel_params += f", {decl}" self.print(f"__global__ void {kernel.name}({kernel_params}) {{") @@ -268,7 +268,7 @@ class CGen: array_name = self.generate_expression(array_access.array) tkw = Types.c_keyword(array_access.type()) acc_index = self.generate_expression(array_access.flat_index) - acc_ref = f"a{array_access.id()}" + acc_ref = array_access.name() self.print(f"const {tkw} {acc_ref} = {array_name}[{acc_index}];") if isinstance(ast_node.elem, AtomicAdd): @@ -276,7 +276,7 @@ class CGen: elem = self.generate_expression(atomic_add.elem) value = self.generate_expression(atomic_add.value) tkw = Types.c_keyword(atomic_add.type()) - acc_ref = f"atm_add{atomic_add.id()}" + acc_ref = atomic_add.name() prefix = "" if ast_node.elem.device_flag else "host_" if atomic_add.check_for_resize(): @@ -290,7 +290,7 @@ class CGen: contact_prop_access = ast_node.elem contact_prop = contact_prop_access.contact_prop prop_name = self.generate_expression(contact_prop) - acc_ref = f"cp{contact_prop_access.id()}" + acc_ref = contact_prop_access.name() if not contact_prop_access.is_scalar(): for dim in contact_prop_access.indexes_to_generate(): @@ -306,7 +306,7 @@ class CGen: feature_prop_access = ast_node.elem feature_prop = feature_prop_access.feature_prop prop_name = self.generate_expression(feature_prop) - acc_ref = f"f{feature_prop_access.id()}" + acc_ref = feature_prop_access.name() if not feature_prop_access.is_scalar(): for dim in feature_prop_access.indexes_to_generate(): @@ -321,7 +321,7 @@ class CGen: if isinstance(ast_node.elem, PropertyAccess): prop_access = ast_node.elem prop_name = self.generate_expression(prop_access.prop) - acc_ref = f"p{prop_access.id()}" + acc_ref = prop_access.name() if not prop_access.is_scalar(): for dim in prop_access.indexes_to_generate(): @@ -336,7 +336,7 @@ class CGen: quaternion = ast_node.elem for i in quaternion.indexes_to_generate(): expr = self.generate_expression(quaternion.get_value(i)) - self.print(f"const double q{quaternion.id()}_{i} = {expr};") + self.print(f"const double {quaternion.name()}_{i} = {expr};") if isinstance(ast_node.elem, QuaternionOp): quat_op = ast_node.elem @@ -346,9 +346,9 @@ class CGen: operator = quat_op.operator() if operator.is_unary(): - self.print(f"const double e{quat_op.id()}_{dim} = {operator.symbol()}({lhs});") + self.print(f"const double {quat_op.name()}_{dim} = {operator.symbol()}({lhs});") else: - self.print(f"const double e{quat_op.id()}_{dim} = {lhs} {operator.symbol()} {rhs};") + self.print(f"const double {quat_op.name()}_{dim} = {lhs} {operator.symbol()} {rhs};") if isinstance(ast_node.elem, ScalarOp): scalar_op = ast_node.elem @@ -359,13 +359,13 @@ class CGen: tkw = Types.c_keyword(scalar_op.type()) if operator.is_unary(): - self.print(f"const {tkw} e{scalar_op.id()} = {operator.symbol()}({lhs});") + self.print(f"const {tkw} {scalar_op.name()} = {operator.symbol()}({lhs});") else: - self.print(f"const {tkw} e{scalar_op.id()} = {lhs} {operator.symbol()} {rhs};") + self.print(f"const {tkw} {scalar_op.name()} = {lhs} {operator.symbol()} {rhs};") if isinstance(ast_node.elem, Select): select = ast_node.elem - acc_ref = f"s{select.id()}" + acc_ref = select.name() if not select.is_scalar(): for dim in select.indexes_to_generate(): @@ -382,16 +382,15 @@ class CGen: if isinstance(ast_node.elem, MathFunction): math_func = ast_node.elem - acc_ref = f"mf{math_func.id()}" params = ", ".join([str(self.generate_expression(p)) for p in math_func.parameters()]) tkw = Types.c_keyword(math_func.type()) - self.print(f"const {tkw} {acc_ref} = {math_func.function_name()}({params});") + self.print(f"const {tkw} {math_func.name()} = {math_func.function_name()}({params});") if isinstance(ast_node.elem, Matrix): matrix = ast_node.elem for i in matrix.indexes_to_generate(): expr = self.generate_expression(matrix.get_value(i)) - self.print(f"const double m{matrix.id()}_{i} = {expr};") + self.print(f"const double {matrix.name()}_{i} = {expr};") if isinstance(ast_node.elem, MatrixOp): matrix_op = ast_node.elem @@ -401,15 +400,15 @@ class CGen: operator = vector_op.operator() if operator.is_unary(): - self.print(f"const double e{matrix_op.id()}_{dim} = {operator.symbol()}({lhs});") + self.print(f"const double {matrix_op.name()}_{dim} = {operator.symbol()}({lhs});") else: - self.print(f"const double e{matrix_op.id()}_{dim} = {lhs} {operator.symbol()} {rhs};") + self.print(f"const double {matrix_op.name()}_{dim} = {lhs} {operator.symbol()} {rhs};") if isinstance(ast_node.elem, Vector): vector = ast_node.elem for dim in vector.indexes_to_generate(): expr = self.generate_expression(vector.get_value(dim)) - self.print(f"const double v{vector.id()}_{dim} = {expr};") + self.print(f"const double {vector.name()}_{dim} = {expr};") if isinstance(ast_node.elem, VectorOp): vector_op = ast_node.elem @@ -419,9 +418,9 @@ class CGen: operator = vector_op.operator() if operator.is_unary(): - self.print(f"const double e{vector_op.id()}_{dim} = {operator.symbol()}({lhs});") + self.print(f"const double {vector_op.name()}_{dim} = {operator.symbol()}({lhs});") else: - self.print(f"const double e{vector_op.id()}_{dim} = {lhs} {operator.symbol()} {rhs};") + self.print(f"const double {vector_op.name()}_{dim} = {lhs} {operator.symbol()} {rhs};") if isinstance(ast_node, Branch): cond = self.generate_expression(ast_node.cond) @@ -745,10 +744,10 @@ class CGen: acc_index = self.generate_expression(ast_node.flat_index) return f"{array_name}[{acc_index}]" - return f"a{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, AtomicAdd): - return f"atm_add{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, ScalarOp): if ast_node.inlined is True: @@ -758,7 +757,7 @@ class CGen: return f"({operator.symbol()}({lhs}))" if operator.is_unary() else \ f"({lhs} {operator.symbol()} {rhs})" - return f"e{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, Call): extra_params = [] @@ -797,7 +796,7 @@ class CGen: if isinstance(ast_node, Iter): assert mem is False, "Iterator is not lvalue!" - return f"i{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, Lit): assert mem is False, "Literal is not lvalue!" @@ -820,7 +819,7 @@ class CGen: params = ", ".join([str(self.generate_expression(p)) for p in ast_node.parameters()]) return f"{ast_node.function_name()}({params})" - return f"mf{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, Property): return ast_node.name() @@ -837,7 +836,7 @@ class CGen: return f"{prop_name}[{index_expr}]" - return f"p{ast_node.id()}" + (f"_{index}" if not ast_node.is_scalar() else "") + return f"{ast_node.name()}" + (f"_{index}" if not ast_node.is_scalar() else "") if isinstance(ast_node, ContactPropertyAccess): assert ast_node.is_scalar() or index is not None, \ @@ -851,7 +850,7 @@ class CGen: return f"{prop_name}[{index_expr}]" - return f"cp{ast_node.id()}" + (f"_{index}" if not ast_node.is_scalar() else "") + return f"{ast_node.name()}" + (f"_{index}" if not ast_node.is_scalar() else "") if isinstance(ast_node, FeaturePropertyAccess): assert ast_node.is_scalar() or index is not None, \ @@ -865,7 +864,7 @@ class CGen: return f"{feature_name}[{index_expr}]" - return f"f{ast_node.id()}" + (f"_{index}" if not ast_node.is_scalar() else "") + return f"{ast_node.name()}" + (f"_{index}" if not ast_node.is_scalar() else "") if isinstance(ast_node, ParticleAttributeList): tid = CGen.temp_id @@ -892,9 +891,9 @@ class CGen: if not ast_node.is_scalar(): assert index is not None, "Index must be set for non-scalar reference." - return f"s{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" - return f"s{ast_node.id()}" + return f"{ast_node.name()}" if isinstance(ast_node, Var): return ast_node.name() if ast_node.is_scalar() else f"{ast_node.name()}_{index}" @@ -910,27 +909,27 @@ class CGen: if isinstance(ast_node, Vector): assert index is not None, "Index must be set for vector." - return f"v{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, Matrix): assert index is not None, "Index must be set for matrix." - return f"m{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, Quaternion): assert index is not None, "Index must be set for quaternion." - return f"q{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, VectorOp): assert index is not None, "Index must be set for vector operation." - return f"e{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, MatrixOp): assert index is not None, "Index must be set for matrix operation." - return f"e{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, QuaternionOp): assert index is not None, "Index must be set for quaternion operation." - return f"e{ast_node.id()}_{index}" + return f"{ast_node.name()}_{index}" if isinstance(ast_node, ZeroVector): return "0.0" diff --git a/src/pairs/ir/arrays.py b/src/pairs/ir/arrays.py index 445fb96954bac8fce908327b75860b288a687538..b7e1e4245630323a983aa1bba36115162e7a783b 100644 --- a/src/pairs/ir/arrays.py +++ b/src/pairs/ir/arrays.py @@ -190,6 +190,9 @@ class ArrayAccess(ASTTerm): def id(self): return self.acc_id + def name(self): + return f"arr_acc{self.id()}" + self.label_suffix() + def type(self): return self.array.type() diff --git a/src/pairs/ir/ast_term.py b/src/pairs/ir/ast_term.py index 778bdfc01da3d1d0476cd77e324a94e693ed6463..4c2c7b407a5357650f152b8f49dcd07c4b458a55 100644 --- a/src/pairs/ir/ast_term.py +++ b/src/pairs/ir/ast_term.py @@ -8,6 +8,7 @@ class ASTTerm(ASTNode): super().__init__(sim) self._class_type = class_type self._indexes_to_generate = set() + self._label = None def __add__(self, other): return self._class_type(self.sim, self, other, Operators.Add) @@ -84,6 +85,12 @@ class ASTTerm(ASTNode): def is_quaternion(self): return self.type() == Types.Quaternion + def set_label(self, label): + self._label = label + + def label_suffix(self): + return "" if self._label is None else f"_{self._label}" + def indexes_to_generate(self): return self._indexes_to_generate diff --git a/src/pairs/ir/atomic.py b/src/pairs/ir/atomic.py index 4d5c8ce9e27575b4e70292b12acb034d004e6ade..88c54b6180f3fce3d24aa0a2678c546667cf377f 100644 --- a/src/pairs/ir/atomic.py +++ b/src/pairs/ir/atomic.py @@ -32,6 +32,9 @@ class AtomicAdd(ASTTerm): def id(self): return self.atomic_add_id + def name(self): + return f"atm_add{self.id()}" + self.label_suffix() + def type(self): return self.elem.type() diff --git a/src/pairs/ir/features.py b/src/pairs/ir/features.py index 5a2a29270a5ce788b49b1c7f2ae9a40853bebbb1..7067073b67fddfbc034a2230c621e0c4f65f1fee 100644 --- a/src/pairs/ir/features.py +++ b/src/pairs/ir/features.py @@ -185,6 +185,9 @@ class FeaturePropertyAccess(ASTTerm): def id(self): return self.acc_id + def name(self): + return f"feat_prop_acc{self.id()}" + self.label_suffix() + def type(self): return self.feature_prop.type() diff --git a/src/pairs/ir/math.py b/src/pairs/ir/math.py index b1cab83a481d578e719445b2c4da64fa9a6141fa..9dde4d2bedcbd7e7951e77d1bad5f5cdf3469101 100644 --- a/src/pairs/ir/math.py +++ b/src/pairs/ir/math.py @@ -23,6 +23,9 @@ class MathFunction(ASTTerm): def id(self): return self._id + def name(self): + return f"mf{self.id()}" + self.label_suffix() + def function_name(self): return "undefined" diff --git a/src/pairs/ir/matrices.py b/src/pairs/ir/matrices.py index 88baf50dd034287e3791682e8521c4cbaf74d41b..aff53add5cc3db80ef66b098bed1b4e622cf66b7 100644 --- a/src/pairs/ir/matrices.py +++ b/src/pairs/ir/matrices.py @@ -35,6 +35,9 @@ class MatrixOp(ASTTerm): def id(self): return self._id + def name(self): + return f"mat_op{self.id()}" + self.label_suffix() + def type(self): return Types.Matrix @@ -100,6 +103,9 @@ class Matrix(ASTTerm): def id(self): return self._id + def name(self): + return f"mat{self.id()}" + self.label_suffix() + def type(self): return Types.Matrix diff --git a/src/pairs/ir/properties.py b/src/pairs/ir/properties.py index 396510df2d850afdb535ce517003785b1040947c..b4867f8be15acd56e5468f0c0f830163e1a5c4cd 100644 --- a/src/pairs/ir/properties.py +++ b/src/pairs/ir/properties.py @@ -30,6 +30,9 @@ class Properties: def volatiles(self): return [p for p in self.props if p.volatile is True] + def non_volatiles(self): + return [p for p in self.props if p.volatile is False] + def nprops(self): return len(self.props) @@ -135,6 +138,9 @@ class PropertyAccess(ASTTerm): def id(self): return self.acc_id + def name(self): + return f"prop_acc{self.id()}" + self.label_suffix() + def type(self): return self.prop.type() @@ -298,6 +304,9 @@ class ContactPropertyAccess(ASTTerm): def id(self): return self.acc_id + def name(self): + return f"cont_prop_acc{self.id()}" + self.label_suffix() + def type(self): return self.contact_prop.type() diff --git a/src/pairs/ir/quaternions.py b/src/pairs/ir/quaternions.py index ef9a7e02f27a375982a87ddf0eb2b24bbb77c6cf..5406973f160ab306a97fd52fc443dc140ba0a383 100644 --- a/src/pairs/ir/quaternions.py +++ b/src/pairs/ir/quaternions.py @@ -35,6 +35,9 @@ class QuaternionOp(ASTTerm): def id(self): return self._id + def name(self): + return f"quat_op{self.id()}" + self.label_suffix() + def type(self): return Types.Quaternion @@ -100,6 +103,9 @@ class Quaternion(ASTTerm): def id(self): return self._id + def name(self): + return f"quat{self.id()}" + self.label_suffix() + def type(self): return Types.Quaternion diff --git a/src/pairs/ir/scalars.py b/src/pairs/ir/scalars.py index 1e33274122c07f25dde5114e9f10f11dda440c85..12c2462672ab50b3ade5f7b20fc8db36714666eb 100644 --- a/src/pairs/ir/scalars.py +++ b/src/pairs/ir/scalars.py @@ -116,6 +116,9 @@ class ScalarOp(ASTTerm): def id(self): return self.scalar_op_id + def name(self): + return f"sca_op{self.id()}" + self.label_suffix() + def type(self): return self.scalar_op_type diff --git a/src/pairs/ir/select.py b/src/pairs/ir/select.py index 9bc43e10d849c0aa60ea2c288a4adcd9f9e01c81..e920f00b460b3145335556d412af7afb2a65f586 100644 --- a/src/pairs/ir/select.py +++ b/src/pairs/ir/select.py @@ -36,6 +36,9 @@ class Select(ASTTerm): def id(self): return self.select_id + def name(self): + return f"sel{self.id()}" + self.label_suffix() + def type(self): return self.expr_if.type() diff --git a/src/pairs/ir/vectors.py b/src/pairs/ir/vectors.py index 825cb9716f91718794d33a2352db4dc2266cd97b..53e5f57fd6dbe7a6fce847aa5ecfa4bd37938afd 100644 --- a/src/pairs/ir/vectors.py +++ b/src/pairs/ir/vectors.py @@ -35,6 +35,9 @@ class VectorOp(ASTTerm): def id(self): return self._id + def name(self): + return f"vec_op{self.id()}" + self.label_suffix() + def type(self): return Types.Vector @@ -108,6 +111,9 @@ class Vector(ASTTerm): def id(self): return self._id + def name(self): + return f"vec{self.id()}" + self.label_suffix() + def type(self): return Types.Vector diff --git a/src/pairs/mapping/funcs.py b/src/pairs/mapping/funcs.py index 62c7c2bfb535fb46a460fc95a7f6fc97bd68a227..41152b8fcb5a3bc0044d107423d17b9e311096cb 100644 --- a/src/pairs/mapping/funcs.py +++ b/src/pairs/mapping/funcs.py @@ -95,6 +95,7 @@ class BuildParticleIR(ast.NodeVisitor): if isinstance(lhs, UndefinedSymbol): self.add_symbols({lhs.symbol_id: rhs}) + rhs.set_label(lhs.symbol_id) else: Assign(self.sim, lhs, rhs) @@ -106,6 +107,7 @@ class BuildParticleIR(ast.NodeVisitor): if isinstance(lhs, UndefinedSymbol): self.add_symbols({lhs.symbol_id: bin_op}) + rhs.set_label(lhs.symbol_id) else: Assign(self.sim, lhs, bin_op) diff --git a/src/pairs/sim/comm.py b/src/pairs/sim/comm.py index d945a404d335ea0b0294b025eb74258290328845..06186060b6bdeaa30aaad60511d1b2f7fc2df505 100644 --- a/src/pairs/sim/comm.py +++ b/src/pairs/sim/comm.py @@ -46,9 +46,10 @@ class Comm: @pairs_inline def borders(self): - # Every property that is constant across timesteps and have neighbor accesses during any - # interaction kernel (i.e. property[j] in force calculation kernel) - prop_list = [self.sim.property(p) for p in ['mass', 'position', 'linear_velocity', 'angular_velocity', 'flags']] + # Every property that has neighbor accesses during any interaction kernel (i.e. property[j] + # exists in any force calculation kernel) + # We ignore normal because there should be no halfspace ghosts + prop_list = [self.sim.property(p) for p in ['mass', 'radius', 'position', 'linear_velocity', 'angular_velocity', 'shape']] Assign(self.sim, self.nsend_all, 0) Assign(self.sim, self.sim.nghost, 0) @@ -64,7 +65,7 @@ class Comm: @pairs_inline def exchange(self): # Every property except volatiles - prop_list = [self.sim.property(p) for p in ['mass', 'position', 'linear_velocity', 'shape', 'flags']] + prop_list = self.sim.properties.non_volatiles() for step in range(self.dom_part.number_of_steps()): Assign(self.sim, self.nsend_all, 0) Assign(self.sim, self.sim.nghost, 0)