diff --git a/examples/dem.py b/examples/dem.py index 550c3902218c6f1aea246d5d89c42b67377a426a..a64139bef97fd8a2353e11da8069b8bf28a9cd10 100644 --- a/examples/dem.py +++ b/examples/dem.py @@ -4,8 +4,13 @@ import sys def update_mass_and_inertia(i): - mass[i] = (4.0 / 3.0) * pi * radius[i] * radius[i] * radius[i] * densityParticle_SI - inv_inertia[i] = diagonal_matrix(1.0 / (0.4 * mass[i] * radius[i] * radius[i])) + if is_sphere(i): + mass[i] = ((4.0 / 3.0) * pi) * radius[i] * radius[i] * radius[i] * densityParticle_SI + inv_inertia[i] = inversed(diagonal_matrix(0.4 * mass[i] * radius[i] * radius[i])) + + else: + mass[i] = infinity + inv_inertia[i] = 0.0 def linear_spring_dashpot(i, j): @@ -161,7 +166,8 @@ psim.read_particle_data( pairs.halfspace()) psim.setup(update_mass_and_inertia, {'densityParticle_SI': densityParticle_SI, - 'pi': math.pi }) + 'pi': math.pi, + 'infinity': math.inf }) psim.build_neighbor_lists(linkedCellWidth + skin) psim.vtk_output(f"output/dem_{target}", frequency=visSpacing) diff --git a/src/pairs/code_gen/cgen.py b/src/pairs/code_gen/cgen.py index b31e997c1b4611bd3fe8613d4c7aebb0e67ac222..d38b06134d61acadef76ee93b5c77f1780b707a0 100644 --- a/src/pairs/code_gen/cgen.py +++ b/src/pairs/code_gen/cgen.py @@ -1,3 +1,4 @@ +import math from pairs.ir.assign import Assign from pairs.ir.atomic import AtomicAdd from pairs.ir.arrays import Array, ArrayAccess, DeclareStaticArray, RegisterArray, ReallocArray @@ -56,6 +57,7 @@ class CGen: if self.target.is_gpu(): self.print("#define PAIRS_TARGET_CUDA") + self.print("#include <limits.h>") self.print("#include <math.h>") self.print("#include <stdbool.h>") self.print("#include <stdio.h>") @@ -806,6 +808,9 @@ class CGen: assert index is not None, "Index must be set for non-scalar literals." return ast_node.value[index] + if isinstance(ast_node.value, float) and math.isinf(ast_node.value): + return "std::numeric_limits<double>::infinity()" + return ast_node.value if isinstance(ast_node, MathFunction): diff --git a/src/pairs/mapping/keywords.py b/src/pairs/mapping/keywords.py index cf28e9cff2cb634ca1a31ac5a1b9626315ca9b8a..c5e84597be7691a2addb247f24edc6cb6148749e 100644 --- a/src/pairs/mapping/keywords.py +++ b/src/pairs/mapping/keywords.py @@ -5,9 +5,11 @@ from pairs.ir.loops import Continue from pairs.ir.math import Abs, Cos, Sin, Sqrt from pairs.ir.matrices import Matrix from pairs.ir.quaternions import Quaternion +from pairs.ir.scalars import ScalarOp from pairs.ir.select import Select from pairs.ir.types import Types from pairs.ir.vectors import Vector, ZeroVector +from pairs.sim.shapes import Shapes class Keywords: @@ -27,6 +29,18 @@ class Keywords: method = self.get_method(f"keyword_{keyword}") return method is not None + def keyword_is_sphere(self, args): + assert len(args) == 1, "is_sphere() keyword requires one parameter." + particle_id = args[0] + assert particle_id.type() == Types.Int32, "Particle ID must be an integer." + return ScalarOp.cmp(self.sim.particle_shape[particle_id], Shapes.Sphere) + + def keyword_is_halfspace(self, args): + assert len(args) == 1, "is_sphere() keyword requires one parameter." + particle_id = args[0] + assert particle_id.type() == Types.Int32, "Particle ID must be an integer." + return ScalarOp.cmp(self.sim.particle_shape[particle_id], Shapes.Halfspace) + def keyword_select(self, args): assert len(args) == 3, "select() keyword requires three parameters!" return Select(self.sim, args[0], args[1], args[2]) @@ -84,23 +98,42 @@ class Keywords: #return vector * inv_length def keyword_squared_length(self, args): - assert len(args) == 1, "length() keyword requires one parameter!" + assert len(args) == 1, "length() keyword requires one parameter." vector = args[0] - assert vector.type() == Types.Vector, "length(): Argument must be a vector!" + assert vector.type() == Types.Vector, "length(): Argument must be a vector." return sum([vector[d] * vector[d] for d in range(self.sim.ndims())]) def keyword_zero_vector(self, args): - assert len(args) == 0, "zero_vector() keyword requires no parameter!" + assert len(args) == 0, "zero_vector() keyword requires no parameter." return ZeroVector(self.sim) def keyword_transposed(self, args): - assert len(args) == 1, "transposed() keyword requires one parameter!" + assert len(args) == 1, "transposed() keyword requires one parameter." matrix = args[0] - assert matrix.type() == Types.Matrix, "tranposed(): Argument must be a matrix!" + assert matrix.type() == Types.Matrix, "tranposed(): Argument must be a matrix." return Matrix(self.sim, [ matrix[0], matrix[3], matrix[6], matrix[1], matrix[4], matrix[7], matrix[2], matrix[5], matrix[8] ]) + def keyword_inversed(self, args): + assert len(args) == 1, "inversed() keyword requires one parameter." + matrix = args[0] + assert matrix.type() == Types.Matrix, "inversed(): Argument must be a matrix." + det = matrix[0] * ((matrix[4] * matrix[8]) - (matrix[7] * matrix[5])) + \ + matrix[1] * ((matrix[5] * matrix[6]) - (matrix[8] * matrix[3])) + \ + matrix[2] * ((matrix[3] * matrix[7]) - (matrix[4] * matrix[6])) + + inv_det = 1.0 / det + return Matrix(self.sim, [ inv_det * ((matrix[4] * matrix[8]) - (matrix[5] * matrix[7])), + inv_det * ((matrix[7] * matrix[2]) - (matrix[8] * matrix[1])), + inv_det * ((matrix[1] * matrix[5]) - (matrix[2] * matrix[4])), + inv_det * ((matrix[5] * matrix[6]) - (matrix[3] * matrix[8])), + inv_det * ((matrix[8] * matrix[0]) - (matrix[6] * matrix[2])), + inv_det * ((matrix[2] * matrix[3]) - (matrix[0] * matrix[5])), + inv_det * ((matrix[3] * matrix[7]) - (matrix[4] * matrix[6])), + inv_det * ((matrix[6] * matrix[1]) - (matrix[7] * matrix[0])), + inv_det * ((matrix[0] * matrix[4]) - (matrix[1] * matrix[3])) ]) + def keyword_diagonal_matrix(self, args): assert len(args) == 1, "diagonal_matrix() keyword requires one parameter!" value = args[0]