diff --git a/src/bvpy/bvp.py b/src/bvpy/bvp.py index 2f3299b77c79255052d49170916ac0986d06f7aa..246b53bef2784daa72501e482f34377a7899cfcd 100644 --- a/src/bvpy/bvp.py +++ b/src/bvpy/bvp.py @@ -456,14 +456,22 @@ class BVP(object): # self.solver.set_problem(self.solution, lhs, # rhs, self.dirichletCondition, # self._pointsources) - - self.solver = fem.petsc.LinearProblem(lhs, - rhs, - bcs=self.dirichletCondition, - petsc_options={ - "ksp_type": "preonly", - "pc_type": "lu"}) - self.solution = self.solver.solve() + if isinstance(rhs, ufl.constantvalue.Zero): + self.solver = NonLinearSolver() + self._set_solver_parameter(**kwargs) + jacobian = ufl.derivative(lhs, self.solution, self.trialFunction) + self.solver.set_problem(self.solution, lhs, + jacobian, self.dirichletCondition, + self._pointsources) + self.solver.solve() + else: + self.solver = fem.petsc.LinearProblem(lhs, + rhs, + bcs=self.dirichletCondition, + petsc_options={ + "ksp_type": "preonly", + "pc_type": "lu"}) + self.solution = self.solver.solve() def info(self): """Prints the descrition of the problem. diff --git a/src/bvpy/utils/post_processing.py b/src/bvpy/utils/post_processing.py index 6a0babe9393227785a0c6fa4c2b6e84ff4395a68..95cdcd82632263970cfa13b37724db6b8fe70643 100644 --- a/src/bvpy/utils/post_processing.py +++ b/src/bvpy/utils/post_processing.py @@ -25,6 +25,7 @@ import numpy as np import operator from bvpy.utils.pre_processing import create_expression +import basix.ufl_wrapper as bu import ufl from dolfinx import fem @@ -75,14 +76,15 @@ class SolutionExplorer(object): if self._dof_per_nodes == 0: self._dof_per_nodes = int(1) # for scalar Function - self.nb_dofs = len(self._functionSpace.dofmap().dofs()) + # self.nb_dofs = len(self._functionSpace.dofmap().dofs()) + self.nb_dofs = len(self._functionSpace.dofmap.list) self.nb_nodes = int(self.nb_dofs/self._dof_per_nodes) - if isinstance(self._functionSpace.ufl_element(), ufl.FiniteElement): + if isinstance(self._functionSpace.ufl_element(), bu.BasixElement): self._type = 'scalar' - elif isinstance(self._functionSpace.ufl_element(), ufl.VectorElement): + elif isinstance(self._functionSpace.ufl_element(), bu.VectorElement): self._type = 'vector' - elif isinstance(self._functionSpace.ufl_element(), ufl.TensorElement): + elif isinstance(self._functionSpace.ufl_element(), bu.TensorElement): self._type = 'tensor' def __call__(self, *x): @@ -97,7 +99,8 @@ class SolutionExplorer(object): Array containing the vertex position """ - return self._mesh.coordinates() + # return self._mesh.coordinates() + return self._mesh.geometry.x def get_dofs_position(self): """Generates a Fenics object containing the dofs positions. @@ -119,7 +122,8 @@ class SolutionExplorer(object): The array of the dofs' values """ - return self._fenics.vector().get_local() + # return self._fenics.vector().get_local() + return self._fenics.vector.array def to_fenics(self): """Returns a fenics.Function from the considered function. @@ -141,23 +145,31 @@ class SolutionExplorer(object): """ if self._type == 'scalar': - return self._fenics.compute_vertex_values() + # return self._fenics.compute_vertex_values() + return self._fenics.x.array else: size_n = self.shape[0] if self._type == 'vector': - res = np.zeros((self._mesh.num_entities(0), self.shape[0])) + # res = np.zeros((self._mesh.num_entities(0), self.shape[0])) + res = np.zeros((self._mesh.geometry.x.shape[0], self.shape[0])) for i in range(size_n): - res[:, i] = self._fenics.sub(i, deepcopy=True).compute_vertex_values() + # res[:, i] = self._fenics.sub(i, deepcopy=True).compute_vertex_values() + res[:, i] = self._fenics.sub(i).collapse().x.array if self._type == 'tensor': - res = np.zeros((self._mesh.num_entities(0), + # res = np.zeros((self._mesh.num_entities(0), + # self.shape[0], self.shape[1])) + res = np.zeros((self._fenics.x.array.shape[0], self.shape[0], self.shape[1])) count = 0 for i in range(size_n): for j in range(size_n): - res[:, i, j] = self._fenics.sub(count+j, deepcopy=True).compute_vertex_values() + # res[:, i, j] = self._fenics.sub(count+j, deepcopy=True).compute_vertex_values() + #TODO: BE CAREFUL HERE j is no more used + res[:, i, j] = self._fenics.x.array count += size_n return res + def geometric_filter(self, axe='x', threshold=0, comparator=">", return_position=False, sort=None): diff --git a/src/bvpy/vforms/elasticity.py b/src/bvpy/vforms/elasticity.py index e02110e68551ef82dcea55aaa7427ca63b459b1e..66d92199b6f3e84e488ba9fe25d027c7e2c7aea2 100644 --- a/src/bvpy/vforms/elasticity.py +++ b/src/bvpy/vforms/elasticity.py @@ -329,10 +329,11 @@ class HyperElasticForm(ElasticForm): def construct_form(self, u, v, sol): E = self._strain(sol) + mesh = v.ufl_function_space().mesh # -- Constitutive models if self.model == 'st_venant': - W = ufl.Constant(0.5) * self._parameters['lmbda']\ + W = fem.Constant(mesh, 0.5) * self._parameters['lmbda']\ * ufl.tr(E) * ufl.tr(E) W += self._parameters['mu'] * ufl.tr(E * E) @@ -349,7 +350,12 @@ class HyperElasticForm(ElasticForm): ufl.ln(J) + (self._parameters['lmbda'] / 2) * (ufl.ln(J))**2 self.lhs = self._parameters['thickness'] * W * self.dx - self.lhs -= ufl.dot(self._parameters['source'], sol) * self.dx + + source = self._parameters['source'] + if isinstance(source, (int, float, list, tuple, np.ndarray)): + source = fem.Constant(mesh, source) + + self.lhs -= ufl.dot(source, sol) * self.dx self.lhs = ufl.derivative(self.lhs, sol, v) diff --git a/tutorials/bvpy_tutorial_7_hyper_elasticity.ipynb b/tutorials/bvpy_tutorial_7_hyper_elasticity.ipynb index 1d8ed92fac62b38c13966ad876dc13e38821f40d..321e2eecfd2ac5c0f1545e5f7b386b07c58c11d2 100644 --- a/tutorials/bvpy_tutorial_7_hyper_elasticity.ipynb +++ b/tutorials/bvpy_tutorial_7_hyper_elasticity.ipynb @@ -217,7 +217,7 @@ "source": [ "from bvpy.vforms import LinearElasticForm\n", "\n", - "linear_response = LinearElasticForm(young=Young, poisson=Poisson, source=[0., 0.], plane_stress=True)\n", + "linear_response = LinearElasticForm(young=Young, poisson=Poisson, source=[0., 0., 0.], plane_stress=True)\n", "\n", "linear_response.info()" ] @@ -237,7 +237,7 @@ "source": [ "from bvpy.vforms import HyperElasticForm\n", "\n", - "non_linear_response = HyperElasticForm(young=Young, poisson=Poisson, source=[0., 0.], plane_stress=True)\n", + "non_linear_response = HyperElasticForm(young=Young, poisson=Poisson, source=[0., 0., 0.], plane_stress=True)\n", "\n", "non_linear_response.info()" ] @@ -299,10 +299,9 @@ " for name, response in {'ln': linear_response, 'nl': non_linear_response}.items():\n", " # -- Setting the problem\n", " stretching = BVP(patch, response, traction)\n", - " \n", + " \n", " # -- Solving the problems\n", " stretching.solve()\n", - " \n", " # -- Computing the corresponding strain field\n", " fe_strain = response.strain(stretching.solution)\n", " np_strain = SolutionExplorer(fe_strain).to_vertex_values()\n", @@ -463,7 +462,9 @@ }, "outputs": [], "source": [ - "import fenics as fe\n", + "# import fenics as fe\n", + "from dolfinx import fem, mesh\n", + "\n", "\n", "def compute_young(concentrations, Young_iso=1e3, domain=globe, component=0):\n", " \"\"\"Computes Young's modulus given a concentration field.\n", @@ -489,23 +490,38 @@ " \n", " \"\"\"\n", " \n", - " vct_func_space = fe.VectorFunctionSpace(domain.mesh, \"P\", 1, dim=2)\n", + " # vct_func_space = fe.VectorFunctionSpace(domain.mesh, \"P\", 1, dim=2)\n", + "\n", + " vct_func_space = fem.VectorFunctionSpace(domain.mesh, (\"P\", 1))\n", + " c_func = fem.Function(vct_func_space)\n", + "\n", + " if isinstance(concentrations, (list, np.ndarray)):\n", + " # c_func = fe.interpolate(concentrations, vct_func_space).sub(component)\n", + " if(vct_func_space.num_sub_spaces > 0):\n", + " for i in range(vct_func_space.num_sub_spaces):\n", + " # self.solution.sub(i).interpolate(solution[i])\n", + " c_func.sub(i).interpolate(concentrations[i])\n", + " else:\n", + " c_func.interpolate(concentrations)\n", " \n", - " if isinstance(concentrations, fe.UserExpression):\n", - " c_func = fe.interpolate(concentrations, vct_func_space).sub(component)\n", - " \n", - " elif isinstance(concentrations, fe.Function):\n", - " c_func = fe.project(concentrations, vct_func_space).sub(component)\n", + " elif isinstance(concentrations, fem.Function):\n", + " # c_func = fe.project(concentrations, vct_func_space).sub(component)\n", + " c_func.interpolate(concentrations)\n", " \n", " else:\n", " print(\"WARNING: the type of the input is not supported\")\n", " \n", - " c_max = c_func.vector().max()\n", - " c_min = c_func.vector().min()\n", - "\n", - " Young = fe.Constant(1)\n", - " Young += fe.Constant(100 / (c_max - c_min)) * (fe.Constant(c_max) - c_func)\n", - " Young *= fe.Constant(Young_iso)\n", + " # c_max = c_func.vector().max()\n", + " # c_min = c_func.vector().min()\n", + " c_max = c_func.vector.max()\n", + " c_min = c_func.vector.min()\n", + "\n", + " # Young = fe.Constant(1)\n", + " # Young += fe.Constant(100 / (c_max - c_min)) * (fe.Constant(c_max) - c_func)\n", + " # Young *= fe.Constant(Young_iso)\n", + " Young = fem.Constant(domain.mesh, 1)\n", + " Young += fem.Constant(domain.mesh, 100 / (c_max - c_min)) * (fem.Constant(domain.mesh, c_max) - c_func)\n", + " Young *= fem.Constant(domain.mesh, Young_iso)\n", " \n", " return Young" ] @@ -718,19 +734,30 @@ "metadata": {}, "outputs": [], "source": [ - "from bvpy.utils.pre_processing import create_expression\n", + "# from bvpy.utils.pre_processing import create_expression\n", + "\n", + "# # -- Creating the initial concentration distribution\n", + "# ka = 9\n", + "# kb = 11\n", + "\n", + "# np.random.seed(1093)\n", + "# globe.discretize()\n", + "# random = np.random.uniform(low=-1, high=1, size=globe.mesh.num_entities(2))\n", + "\n", + "# random_pattern = [[1+0.04*ka**2+0.1*r, 0.2*kb+0.1*r] for r in random]\n", + "\n", + "# concentrations = create_expression(random_pattern)\n", + "\n", + "import numpy as np\n", "\n", - "# -- Creating the initial concentration distribution\n", "ka = 9\n", "kb = 11\n", "\n", - "np.random.seed(1093)\n", "globe.discretize()\n", - "random = np.random.uniform(low=-1, high=1, size=globe.mesh.num_entities(2))\n", - "\n", - "random_pattern = [[1+0.04*ka**2+0.1*r, 0.2*kb+0.1*r] for r in random]\n", - "\n", - "concentrations = create_expression(random_pattern)" + "dim = 3 # each node is presented by (x, y, z)\n", + "_size = globe.mesh.geometry.dofmap.num_nodes*dim\n", + "random = np.random.uniform(low=-1, high=1, size=_size)\n", + "concentrations = [1+ 0.04*ka**2+0.1*random, 0.2*kb+0.1*random] " ] }, {