Module weac.fracture

Fracture mechanics methods for WEak Layer AntiCrack nucleation model.

Expand source code
"""Fracture mechanics methods for WEak Layer AntiCrack nucleation model."""

# from scipy.optimize import root_scalar, basinhopping, brentq
# from scipy.integrate import quad, trapz, romberg


# def energy_criterion():
#     """Evaluate the energy criterion for a crack da = [xstart, xstop]."""
#     pass
#
#
# def stress_criterion(self, x, C, phi, li, ki, crit='quads', **kwargs):
#     """Evaluate the stress criterion at locations x."""
#     # Unused arguments
#     _ = kwargs
#
#     # Unpack strengths (given in kPa)
#     Sc = self.weak['Sc']
#     Tc = self.weak['Tc']
#
#     # Make sure x is np.ndarray and determine its size
#     x = np.asarray([x]) if np.isscalar(x) else np.asarray(x)
#     n = x.size
#
#     # Compute cumulate lengths list and segment index of all x
#     lic = np.cumsum(li)
#     nsegment = np.searchsorted(lic, x)
#
#     # Calculate global x coordinate of left segment ends and init stresses
#     x0 = np.insert(lic, 0, 0)
#     sig = np.zeros(n)
#     tau = np.zeros(n)
#
#     # Compute stresses at x and convert to kPa
#     for i, seg in enumerate(nsegment):
#         z0 = self.z(x[i] - x0[seg], C[:, [seg]], li[seg], phi, bed=ki[seg])
#         sig[i] = 1e3*max([0, self.sig(z0)])
#         tau[i] = 1e3*self.tau(z0)
#
#     # Evaluate stress criterion
#     if crit == 'quads':
#         return np.sqrt((sig/Sc)**2 + (tau/Tc)**2) - 1
#
# def external_potential(self, C, phi, **segments):
#     """Compute total external potential(PST or skier-on-slab setup)."""
#     # Rasterize solution
#     xq, zq, _ = self.rasterize_solution(C=C, phi=phi, **segments)
#     # Compute displacements where weight loads are applied
#     w0 = self.w(zq)
#     us = self.u(zq, z0=self.zs)
#     # Get weight loads
#     qn, qt = self.get_weight_load(phi)
#     # Integrate external work
#     Wext = trapz(qn*w0 + qt*us, xq)
#
#     if self.system == 'skier':
#         # Get skier weight and length of left free beam segment
#         m, l2 = segments['mi'][1], segments['li'][1]
#         # Compute solution at the skier's location
#         z0 = self.z(x=l2, C=C[:, [1]], l=l2, phi=phi, bed=False)
#         # Compute skier force
#         Fn, Ft = self.get_skier_load(m, phi)
#         # Add external work of the skier loading
#         Wext += Fn*self.w(z0) + Ft*self.u(z0, z0=-self.h/2)
#     elif self.system != 'pst-':
#         sys.exit('Input error: Only skier-on-slab and PST setups '
#                  + 'implemented at the moment.')
#
#     # Return potential of external forces Pext = - Wext
#     return -Wext
#
# def internal_potential(self, C, phi, **segments):
#     """Compute total internal potential(PST or skier-on-slab setup)."""
#     # Rasterize solution
#     xq, zq, xb = self.rasterize_solution(C=C, phi=phi, **segments)
#     # Compute section forces
#     N, M, V = self.N(zq), self.M(zq), self.V(zq)
#     # Compute stored energy of the slab (beam)
#     Pint = trapz(N**2/self.A11 + M**2/self.D11 + V**2/self.kA55, xq)/2
#
#     # Drop parts of the solution that are not a foundation
#     zweak = zq[:, ~np.isnan(xb)]
#     xweak = xb[~np.isnan(xb)]
#
#     if self.system == 'pst-':
#         # Compute displacments of segment on foundation
#         # w = self.w(zweak)
#         # u = self.u(zweak, z0=self.h/2)
#         eps = self.eps(zweak)
#         gamma = self.gamma(zweak)
#         sig = self.sig(zweak)
#         tau = self.tau(zweak)
#         # Compute stored energy of the weak layer (foundation)
#         # Pint += trapz(self.kn*w**2 + self.kt*u**2, xweak)/2
#         Pint += 1/2*trapz(sig*eps + tau*gamma, xweak)*self.t
#     elif self.system == 'skier':
#         # Split left and right bedded segments
#         zl, zr = np.array_split(zweak, 2, axis=1)
#         xl, xr = np.array_split(xweak, 2)
#         # Compute displacements on left and right foundations
#         wl, wr = self.w(zl), self.w(zr)
#         ul, ur = self.u(zl, z0=self.h/2), self.u(zr, z0=self.h/2)
#         # Compute stored energy of the weak layer (foundation)
#         Pint += trapz(self.kn*wl**2 + self.kt*ul**2, xl)/2
#         Pint += trapz(self.kn*wr**2 + self.kt*ur**2, xr)/2
#     else:
#         sys.exit('Input error: Only skier-on-slab and PST setups '
#                  + 'implemented at the moment.')
#
#     return Pint

# def find_roots(self, L, C, phi, nintervals=50, **kwargs):
#     """Find points where the stress criterion is satisfied identically."""
#     # Subdivide domain into intervals
#     intvls = np.linspace(0, L, num=nintervals+1)
#     roots = []
#
#     # See if we can find roots in given intervals
#     for i in range(nintervals):
#         try:
#             roots.append(root_scalar(
#                 self.stress_criterion, method='brentq',
#                 args=(C, phi, kwargs['li'], kwargs['ki']),
#                 bracket=intvls[i:i+2], xtol=1e-1).root)
#         except ValueError:
#             pass
#
#     # Determine index to insert skier position
#     iskier = np.searchsorted(roots, L/2)
#     # Add domain ends and skier position to points of interest
#     poi = np.unique(np.insert(roots, [0, iskier, len(roots)], [0, L/2, L]))
#     # Compute new segment lengths
#     li = poi[1:] - poi[:-1]
#     # Compute new segment midpoints
#     xmid = (poi[1:] + poi[:-1])/2
#     # Compute new foundation order
#     ki = self.stress_criterion(
#         xmid, C, phi, kwargs['li'], kwargs['ki']) < 0
#     k0 = np.full_like(ki, True)
#     # Compute new position of skier weight
#     lic = np.cumsum(li)[:-1]
#     iskier = np.searchsorted(lic, L/2)
#     mi = np.insert(np.zeros_like(lic), iskier, kwargs['mi'].sum())
#     print(lic)
#     print(mi)
#
#     # Assemble update segmentation as output
#     segments = {
#         'nocrack': {'li': li, 'mi': mi, 'ki': k0},
#         'crack': {'li': li, 'mi': mi, 'ki': ki},
#         'both': {'li': li, 'mi': mi, 'ki': ki, 'k0': k0}}
#
#     return segments