I want to compress particles(Take example of powder particles), How we can give boundary conditions to the particles for using It in FEniCS(I want to do particles compression)?

import gmsh
import random
import math

class SpherePacking:
    def __init__(self, number, min_radius, max_radius, box, k_move, operation):
        self.number = number
        self.min_radius = min_radius
        self.max_radius = max_radius
        self.box = box  # [x_min, y_min, z_min, x_max, y_max, z_max]
        self.k_move = k_move
        self.operation = operation
        self.objects = []

    def generate_random_positions(self):
        for _ in range(self.number):
            radius = random.uniform(self.min_radius, self.max_radius)

            # Generate random position in cylindrical coordinates
            r = random.uniform(0, self.box[3])  # Assume max radius from the bounding box
            theta = random.uniform(0, 2 * math.pi)
            z = random.uniform(self.box[2] + radius, self.box[5] - radius)

            # Convert cylindrical to Cartesian coordinates
            x = r * math.cos(theta)
            y = r * math.sin(theta)

            # Ensure the particle stays within the cylindrical boundary
            if r + radius <= self.box[3]:
                self.objects.append({"x": x, "y": y, "z": z, "radius": radius})

    def validate_positions(self):
        for obj in self.objects:
            # Check box boundary
            obj["x"] = max(self.box[0] + obj["radius"], min(self.box[3] - obj["radius"], obj["x"]))
            obj["y"] = max(self.box[1] + obj["radius"], min(self.box[4] - obj["radius"], obj["y"]))
            obj["z"] = max(self.box[2] + obj["radius"], min(self.box[5] - obj["radius"], obj["z"]))

    def resolve_collisions(self):
        for _ in range(500):  # Increased iteration limit for more thorough resolution
            stabilized = True
            for i in range(len(self.objects)):
                for j in range(i + 1, len(self.objects)):
                    obj_i, obj_j = self.objects[i], self.objects[j]
                    dx = obj_i["x"] - obj_j["x"]
                    dy = obj_i["y"] - obj_j["y"]
                    dz = obj_i["z"] - obj_j["z"]
                    dist = math.sqrt(dx**2 + dy**2 + dz**2)

                    # Check if particles overlap
                    if dist < obj_i["radius"] + obj_j["radius"]:
                        stabilized = False
                        overlap = (obj_i["radius"] + obj_j["radius"] - dist) / 2
                        move_dist = overlap / dist

                        # Apply displacement in both directions along the line of collision
                        obj_i["x"] += dx * move_dist
                        obj_i["y"] += dy * move_dist
                        obj_i["z"] += dz * move_dist
                        obj_j["x"] -= dx * move_dist
                        obj_j["y"] -= dy * move_dist
                        obj_j["z"] -= dz * move_dist

            if stabilized:
                break
        self.validate_positions()  # Validate positions after collision resolution

    def generate_geometry(self):
        gmsh.initialize()
        gmsh.option.setNumber("General.Terminal", 1)
        gmsh.model.add("Sphere Packing in Cylinder")

        # Add spheres
        for i, obj in enumerate(self.objects):
            gmsh.model.occ.addSphere(obj["x"], obj["y"], obj["z"], obj["radius"], tag=i + 1)

        gmsh.model.occ.synchronize()
        gmsh.option.setNumber("Mesh.CharacteristicLengthMin", 0.01)
        gmsh.option.setNumber("Mesh.CharacteristicLengthMax", 0.05)

        try:
            gmsh.model.mesh.generate(3)
        except Exception as e:
            print(f"Error during mesh generation: {e}")

        gmsh.write("sphere_packing_cylinder.msh")
        gmsh.write("sphere_packing_cylinder.step")
        gmsh.finalize()

    def run(self):
        print("Generating random positions...")
        self.generate_random_positions()
        print("Resolving collisions...")
        self.resolve_collisions()
        print("Generating Gmsh geometry...")
        self.generate_geometry()
        print("Done! Files saved as 'sphere_packing_cylinder.msh' and 'sphere_packing_cylinder.step'.")

# Parameters
number_of_spheres = 3000
min_particle_radius = 0.05
max_particle_radius = 0.1
bounding_box = [-1, -1, 0, 1, 1, 2]  # [x_min, y_min, z_min, x_max, y_max, z_max]
k_move = 0.0001
operation = "Fragments"

sphere_packing = SpherePacking(number_of_spheres, min_particle_radius, max_particle_radius, bounding_box, k_move, operation)
sphere_packing.run()

Hoping will get some ideas to implement using FEniCS.

The code isn’t really helpful, because it is a gmsh code. If you have a question about gmsh, you should ask it on the gmsh support channel.

If your question is not about gmsh, that you should try expressing it with more details than just the title of the post. Closing.