print(f'dolfinx: {dolfinx.__version__}')
'''
dolfinx: 0.8.0
'''
import dolfinx
from dolfinx import mesh, fem
from mpi4py import MPI
import basix
import numpy as np
from petsc4py import PETSc
# A six degrees of freedom per node tetrahedral domain was created and a #function space was created with the element called V...
...
# Create a function to hold the force vector at each node
force = fem.Function(V)
# Initialize the force vector to zero
force.vector.set(0.0)
# Get the topology and connectivity of the mesh
topology = domain.topology
cells = topology.connectivity(topology.dim, 0)
cell_vertices = domain.geometry.x[cells.array]
# Define a function to calculate the force vector at each node based on the coordinates
def calculate_force(x):
fx = 0.1 * x[0] # Example formula for force in x-direction
fy = 0.2 * x[1] # Example formula for force in y-direction
fz = 0.3 * x[2] # Example formula for force in z-direction
mx = 0.0 # Example moment about x-axis (set to 0)
my = 0.0 # Example moment about y-axis (set to 0)
mz = 0.0 # Example moment about z-axis (set to 0)
return [fx, fy, fz, mx, my, mz]
# Assemble the force vector by looping over the DOFs
dofmap = V.dofmap
num_dofs = force.vector.getSize()
# Define the bilinear form (stiffness matrix)
u = fem.Function(V)
v = fem.Function(V)
# Access the vector of the function
u_vector = u.vector.getArray()
v_vector = u.vector.getArray()
# Extract displacements (assuming the first 3 DOFs correspond to displacements)
u_disp = u_vector[:3] # Get the first 3 components for displacement (u1, u2, u3)
v_disp = v_vector[:3]
# Create UFL expressions for the displacement components (use vector components directly)
u_disp = u.split()[0] # Extract the displacement component (u1, u2, u3)
v_disp = v.split()[0] # Extract the displacement component (v1, v2, v3)
# Compute the gradient of each displacement component
grad_u_disp = ufl.grad(u_disp) # Gradient of displacement u (which will give us a 3x3 tensor)
grad_v_disp = ufl.grad(v_disp) # Gradient of displacement v (same 3x3 tensor)
# Now compute the symmetric part of the gradient (this is the strain tensor)
epsilon_u = ufl.sym(grad_u_disp) # Symmetric part of the gradient for strain tensor of u
epsilon_v = ufl.sym(grad_v_disp) # Symmetric part of the gradient for strain tensor of v
# For rotations, define an appropriate formulation (e.g., assuming small rotations)
# You may need to modify this based on your problem's specific formulation.
# For example, rotation-related strain could be modeled in a different way.
# Here, we assume the rotation strain is zero for simplicity.
#epsilon_rot_u = u[3:6] # Extract rotations (last 3 DOFs)
#epsilon_rot_v = v[3:6] # Extract rotations (last 3 DOFs)
# Bilinear form for displacements
#a_displacements = fem.form(ufl.inner(epsilon_u, epsilon_v) * ufl.dx)
# Bilinear form for rotations (example, can be expanded for real problem)
#a_rotations = fem.form(ufl.inner(epsilon_rot_u, epsilon_rot_v) * ufl.dx)
# Total bilinear form (sum of displacement and rotation contributions)
#a = a_displacements + a_rotations
# Define the linear form (force vector)
#L = fem.form(force * v) # Linear term (force)
# Create a linear problem
#problem = fem.LinearProblem(a, L, petsc_options={"ksp_type": "gmres", "pc_type": "hypre"})
# Solve the linear problem
#solution = problem.solve()
# Optionally, print out the solution (displacement and rotations) at nodes
#print(solution.vector)
So far I am under the impression that a more advanced type of bi-linear form would have to be created to solve a problem with forces and rotations. This is my first attempt to do so. I’ll admit that so far I am just understanding what the trial and test function actually are and I am working under the impression that u and v stem from gradients that are formed from the evaluation of the basis functions and some other factors during assembly. I have a text that describes the process fairly well and some MatLabs that I read through…
At this point, I can see that epsilon_u = ufl.sym(grad_u_disp), is certainly not the way to be doing things and at this point does lead to:
Traceback (most recent call last):
File "/home/prusso/dolfinx-beam_w/tetra_forcevector3.py", line 66, in <module>
epsilon_u = ufl.sym(grad_u_disp) # Symmetric part of the gradient for strain tensor of u
File "/home/prusso/spack/var/spack/environments/fenicsx-env/.spack-env/view/lib/python3.10/site-packages/ufl/operators.py", line 337, in sym
return Sym(A)
File "/home/prusso/spack/var/spack/environments/fenicsx-env/.spack-env/view/lib/python3.10/site-packages/ufl/tensoralgebra.py", line 542, in __new__
raise ValueError("Symmetric part of tensor with rank != 2 is undefined.")
ValueError: Symmetric part of tensor with rank != 2 is undefined.
So if I understand correctly the element here of degree 1 can be solved using “LinearProblem”…
Could I get some help to get a solution vector U coming out here? One thing I am also inquiring is, how to set a demonstration force vector. Mostly I would like to say for example have forces on the Y-axis only of the same amount each node. I will have to set up Dirichlet conditions as well and I understand that those aren’t shown since this is a work in progress still…I plan to have a fixed support so far at all nodes x=0.0…
Is anything on the right track here? How to start to get a solution vector U from this type of problem?