Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
liquid_crystal_elastomer.hpp
Go to the documentation of this file.
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
17 #pragma once
18 
23 
24 namespace smith {
25 
31  static constexpr int dim = 3;
32 
34  struct State {
37  double temperature;
38  };
39 
51  LiquidCrystElastomerBrighenti(double rho, double shear_modulus, double bulk_modulus, double order_constant,
52  double order_parameter, double transition_temperature, double N_b_squared)
53  : density(rho),
54  shear_modulus_(shear_modulus),
55  bulk_modulus_(bulk_modulus),
56  order_constant_(order_constant),
57  initial_order_parameter_(order_parameter),
58  transition_temperature_(transition_temperature),
59  N_b_squared_(N_b_squared)
60  {
61  SLIC_ERROR_ROOT_IF(density <= 0.0, "Density must be positive in the LCE material model.");
62  SLIC_ERROR_ROOT_IF(shear_modulus_ <= 0.0, "Shear modulus must be positive in the LCE material model.");
63  SLIC_ERROR_ROOT_IF(bulk_modulus_ <= 0.0, "Bulk modulus must be positive in the LCE material model.");
64  SLIC_ERROR_ROOT_IF(order_constant_ <= 0.0, "Order constant must be positive in the LCE material model.");
65  SLIC_ERROR_ROOT_IF(transition_temperature_ <= 0.0,
66  "The transition temperature must be positive in the LCE material model.");
67  }
68 
82  template <typename DispGradType, typename OrderParamType, typename GammaAngleType>
83  SMITH_HOST_DEVICE auto operator()(State& state, const tensor<DispGradType, dim, dim>& displacement_grad,
84  OrderParamType temperature_tuple, GammaAngleType gamma_tuple) const
85  {
86  using std::cos, std::sin;
87 
88  // get the values from the packed value/gradient tuples
89  auto temperature = get<0>(temperature_tuple);
90  auto gamma = get<0>(gamma_tuple);
91 
92  auto I = Identity<dim>();
93  double q0 = initial_order_parameter_;
94  tensor normal{{cos(gamma), sin(gamma), 0.0 * gamma}};
95 
96  if (norm(state.deformation_gradient) == 0) {
97  state.distribution_tensor = get_value((N_b_squared_ / 3.0) * ((1 - q0) * I) + (3 * q0 * outer(normal, normal)));
98  state.deformation_gradient = get_value(displacement_grad) + I;
99  state.temperature = get_value(temperature);
100  }
101 
102  // kinematics
103  auto F = displacement_grad + I;
104  auto F_old = state.deformation_gradient;
105  auto F_hat = dot(F, inv(F_old));
106  auto J = det(F);
107 
108  // Distribution tensor function of nematic order tensor
109  auto mu = calculateDistributionTensor(state, F_hat, temperature, normal);
110  auto mu0 = (N_b_squared_ / 3.0) * ((1 - q0) * I) + (3 * q0 * outer(normal, normal));
111 
112  // stress output
113  // Note to Jorge-Luis: the paper is omits a prefactor of 1/J in the
114  // Cauchy stress equation because they assume J = 1 strictly
115  // (the incompressible limit). It needs to be retained for this
116  // compressible model.
117  const double lambda = bulk_modulus_ - (2.0 / 3.0) * shear_modulus_;
118  using std::log;
119  auto stress = ((3 * shear_modulus_ / N_b_squared_) * (mu - mu0) + lambda * log(J) * I) / J;
120 
121  // update state variables
122  state.deformation_gradient = get_value(F);
123  state.temperature = get_value(temperature);
124  state.distribution_tensor = get_value(mu);
125 
126  return stress;
127  }
128 
130 
145  template <typename S, typename T, typename U>
146  auto calculateDistributionTensor(const State& state, const tensor<S, dim, dim>& F_hat, const T theta,
147  const tensor<U, dim>& normal) const
148  {
149  // Nematic order scalar
150  using std::exp;
151  auto theta_old = state.temperature;
152  auto q_old = initial_order_parameter_ / (1 + exp((theta_old - transition_temperature_) / order_constant_));
154 
155  // Nematic order tensor
156  constexpr auto I = Identity<dim>();
157  auto n_dyad = outer(normal, normal);
158  // BT: These are different than what Jorge-Luis had. I found the papers
159  // to be confusing on this point. I'm extrapolating from Eq (7)
160  // in https://doi.org/10.1016/j.mechrescom.2022.103858
161  // Well-defined validation problems would help to confirm.
162  auto Q_old = 0.5 * ((1.0 - q_old) * I + 3.0 * q_old * n_dyad);
163  auto Q = 0.5 * ((1.0 - q) * I + 3.0 * q * n_dyad);
164 
165  // Polar decomposition of incremental deformation gradient
166  auto U_hat = matrix_sqrt(transpose(F_hat) * F_hat);
167  auto R_hat = F_hat * inv(U_hat);
168 
169  // Distribution tensor (using 'Strang Splitting' approach)
170  double alpha = 2.0 * N_b_squared_ / 3.0;
171  auto mu_old = state.distribution_tensor;
172  auto mu_hat = mu_old + alpha * (Q - Q_old);
173  auto mu_a = dot(F_hat, dot(mu_hat, transpose(F_hat)));
174  auto mu_b = alpha * (Q - dot(R_hat, dot(Q, transpose(R_hat))));
175 
176  return mu_a + mu_b;
177  }
178 
180 
181  // Sam: please forgive some of the tautological
182  // explanations below, I'm not knowledgeable enough
183  // about this model to write meaningful descriptions,
184  // so these placeholders really only exist to satisfy
185  // our doxygen requirements
186  //
187  // suggestions are welcome
188 
189  double density;
190  double shear_modulus_;
191  double bulk_modulus_;
195 
196  // BT: I think this can be removed - it looks like it cancels out every place it appears.
197  double N_b_squared_;
198 };
199 
203 
211  using State = Empty;
212 
214  static constexpr int dim = 3;
215 
225  LiquidCrystalElastomerBertoldi(double rho, double young_modulus, double poisson_ratio, double initial_order_parameter,
226  double beta_parameter)
227  : density(rho),
228  young_modulus_(young_modulus),
229  poisson_ratio_(poisson_ratio),
230  initial_order_parameter_(initial_order_parameter),
231  beta_parameter_(beta_parameter)
232  {
233  SLIC_ERROR_ROOT_IF(density <= 0.0, "Density must be positive in the LCE material model.");
234  SLIC_ERROR_ROOT_IF(young_modulus_ <= 0.0, "Bulk modulus must be positive in the LCE material model.");
235  SLIC_ERROR_ROOT_IF(poisson_ratio_ <= 0.0, "Poisson ratio must be positive in the LCE material model.");
236  SLIC_ERROR_ROOT_IF(initial_order_parameter_ <= 0.0,
237  "Initial order parameter must be positive in the LCE material model.");
238  SLIC_ERROR_ROOT_IF(beta_parameter_ <= 0.0, "The beta parameter must be positive in the LCE material model.");
239  }
240 
242 
257  template <typename DispGradType, typename OrderParamType, typename GammaAngleType, typename EtaAngleType>
258  SMITH_HOST_DEVICE auto operator()(State& /*state*/, const tensor<DispGradType, dim, dim>& displacement_grad,
259  OrderParamType inst_order_param_tuple, GammaAngleType gamma_tuple,
260  EtaAngleType eta_tuple) const
261  {
262  using std::cos, std::sin;
263 
264  // Compute the normal
265  auto gamma = get<0>(gamma_tuple);
266  auto eta = get<0>(eta_tuple);
267  tensor normal{{cos(gamma) * cos(eta), sin(gamma) * cos(eta), 0.0 * gamma + sin(eta)}};
268 
269  // Get order parameters
270  auto St = get<0>(inst_order_param_tuple);
271  double S0 = initial_order_parameter_;
272 
273  const double lambda = poisson_ratio_ * young_modulus_ / (1.0 + poisson_ratio_) / (1.0 - 2.0 * poisson_ratio_);
274  const double mu = young_modulus_ / 2.0 / (1.0 + poisson_ratio_);
275 
276  // kinematics
277  auto I = Identity<dim>();
278  auto F = displacement_grad + I;
279  auto C = dot(transpose(F), F);
280  auto E = 0.5 * (C - I);
281  auto J = det(F);
282 
283  // Compute the second Piola-Kirchhoff stress, i.e., \partial strain_energy / \partial E
284  auto S_stress_1 = lambda * tr(E) * I;
285  auto S_stress_2 = 2 * mu * E;
286  auto S_stress_3 = -0.5 * beta_parameter_ * (St - S0) * (3 * outer(normal, normal) - I);
287 
288  // transform from second Piola-Lichhoff to Cauchy stress
289  auto stress = 1.0 / J * F * (S_stress_1 + S_stress_2 + S_stress_3) * transpose(F);
290 
291  return stress;
292  }
293 
295 
311  template <typename DispGradType, typename orderParamType, typename GammaAngleType, typename EtaAngleType>
312  auto calculateStrainEnergy(const State& /*state*/, const tensor<DispGradType, dim, dim>& displacement_grad,
313  orderParamType inst_order_param_tuple, GammaAngleType gamma_tuple,
314  EtaAngleType eta_tuple) const
315  {
316  using std::cos, std::sin;
317 
318  // Compute the normal
319  auto gamma = get<0>(gamma_tuple);
320  auto eta = get<0>(eta_tuple);
321  tensor normal{{cos(gamma) * cos(eta), sin(gamma) * cos(eta), 0.0 * gamma + sin(eta)}};
322 
323  // Get order parameters
324  auto St = get<0>(inst_order_param_tuple);
325  double S0 = initial_order_parameter_;
326 
327  const double lambda = poisson_ratio_ * young_modulus_ / (1.0 + poisson_ratio_) / (1.0 - 2.0 * poisson_ratio_);
328  const double mu = young_modulus_ / 2.0 / (1.0 + poisson_ratio_);
329 
330  // kinematics
331  auto I = Identity<dim>();
332  auto F = displacement_grad + I;
333  auto C = dot(transpose(F), F);
334  auto E = 0.5 * (C - I);
335 
336  // Compute the second Piola-Kirchhoff stress, i.e., \partial strain_energy / \partial E
337  auto strain_energy_1 = 0.5 * lambda * tr(E) * tr(E);
338  auto strain_energy_2 = mu * inner(E, E);
339  auto strain_energy_3 = -0.5 * beta_parameter_ * (St - S0) * inner(3 * outer(normal, normal) - I, E);
340 
341  auto strain_energy = strain_energy_1 + strain_energy_2 + strain_energy_3;
342 
343  return strain_energy;
344  }
345 
346  double density;
347  double young_modulus_;
348  double poisson_ratio_;
351 };
352 
353 } // namespace smith
#define SMITH_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc or amdclang and does nothing on ...
Definition: accelerator.hpp:37
This file contains the declaration of a dual number class.
Accelerator functionality.
Definition: smith.cpp:36
SMITH_HOST_DEVICE auto log(dual< gradient_type > a)
implementation of the natural logarithm function for dual numbers
Definition: dual.hpp:389
constexpr SMITH_HOST_DEVICE auto outer(double A, tensor< T, n > B)
Definition: tensor.hpp:603
SMITH_HOST_DEVICE auto exp(dual< gradient_type > a)
implementation of exponential function for dual numbers
Definition: dual.hpp:381
constexpr SMITH_HOST_DEVICE auto inv(const isotropic_tensor< T, m, m > &I)
return the inverse of an isotropic tensor
constexpr SMITH_HOST_DEVICE auto norm(const isotropic_tensor< T, m, m > &I)
compute the Frobenius norm (sqrt(tr(dot(transpose(I), I)))) of an isotropic tensor
SMITH_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
Definition: dual.hpp:316
constexpr SMITH_HOST_DEVICE auto transpose(const isotropic_tensor< T, m, m > &I)
return the transpose of an isotropic tensor
auto matrix_sqrt(const tensor< T, dim, dim > &A)
compute the matrix square root of a square, real-valued, symmetric matrix i.e. given A,...
Definition: tensor.hpp:1366
constexpr SMITH_HOST_DEVICE auto get_value(const T &arg)
return the "value" part from a given type. For non-dual types, this is just the identity function
Definition: dual.hpp:445
constexpr SMITH_HOST_DEVICE auto det(const isotropic_tensor< T, m, m > &I)
compute the determinant of an isotropic tensor
constexpr SMITH_HOST_DEVICE auto inner(const dual< S > &A, const dual< T > &B)
Definition: dual.hpp:281
constexpr SMITH_HOST_DEVICE auto tr(const isotropic_tensor< T, m, m > &I)
calculate the trace of an isotropic tensor
SMITH_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
Definition: dual.hpp:324
constexpr SMITH_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor
The material and load types for the solid functional physics module.
see Nothing for a complete description of this class and when to use it
internal variables for the liquid crystal elastomer model
double temperature
temperature at the last timestep
tensor< double, dim, dim > distribution_tensor
mu from the last timestep
tensor< double, dim, dim > deformation_gradient
F from the last timestep.
Brighenti's liquid crystal elastomer model.
double N_b_squared_
Kuhn segment parameters.
double shear_modulus_
shear modulus in stress-free configuration
SMITH_HOST_DEVICE auto operator()(State &state, const tensor< DispGradType, dim, dim > &displacement_grad, OrderParamType temperature_tuple, GammaAngleType gamma_tuple) const
Material response.
auto calculateDistributionTensor(const State &state, const tensor< S, dim, dim > &F_hat, const T theta, const tensor< U, dim > &normal) const
Compute the distribution tensor using Brighenti's model.
double transition_temperature_
Transition temperature.
double bulk_modulus_
bulk modulus in stress-free configuration
static constexpr int dim
this model is only intended to be used in 3D
double initial_order_parameter_
initial value of order parameter
LiquidCrystElastomerBrighenti(double rho, double shear_modulus, double bulk_modulus, double order_constant, double order_parameter, double transition_temperature, double N_b_squared)
Constructor.
Bertoldi's liquid crystal elastomer model Paper: Li, S., Librandi, G., Yao, Y., Richard,...
LiquidCrystalElastomerBertoldi(double rho, double young_modulus, double poisson_ratio, double initial_order_parameter, double beta_parameter)
Constructor.
double initial_order_parameter_
initial value of order parameter
double young_modulus_
Young's modulus in stress-free configuration.
SMITH_HOST_DEVICE auto operator()(State &, const tensor< DispGradType, dim, dim > &displacement_grad, OrderParamType inst_order_param_tuple, GammaAngleType gamma_tuple, EtaAngleType eta_tuple) const
Material response.
double beta_parameter_
Degree of coupling between elastic and nematic energies.
auto calculateStrainEnergy(const State &, const tensor< DispGradType, dim, dim > &displacement_grad, orderParamType inst_order_param_tuple, GammaAngleType gamma_tuple, EtaAngleType eta_tuple) const
Compute the strain energy.
static constexpr int dim
this model is only intended to be used in 3D
Implementation of the tensor class used by Functional.
Smith tuple compatibility layer over mfem::future::tuple.