def _check(self, shape): # check that both are im materials and store ims if not self._pre_solve_checks or shape != self._last_shape: if isinstance(self.model.surface_1.material, _IMMaterial) and \ isinstance(self.model.surface_2.material, _IMMaterial): span = tuple([ s * (2 - pa) for s, pa in zip(shape, self._periodic_axes) ]) im_1 = self.model.surface_1.material.influence_matrix( [self.component], [self.model.surface_1.grid_spacing] * 2, span)[self.component] im_2 = self.model.surface_2.material.influence_matrix( [self.component], [self.model.surface_1.grid_spacing] * 2, span)[self.component] self._im_1 = im_1 self._im_2 = im_2 self._im_total = im_1 + im_2 self._pre_solve_checks = True self._base_conv_func = plan_convolve(np.zeros(shape), self._im_total, None, self._periodic_axes) self._last_shape = shape else: raise ValueError( "This sub model only supports influence matrix based materials" )
def test_inverse_conv(): np.random.seed(0) with slippy.OverRideCuda(): loads = np.random.rand(128, 128) im = e_im('zz', loads.shape, (1e-6, 1e-6), 200e9, 0.3) conv_func = c.plan_convolve(loads, im, circular=True, fft_im=False) recovered = conv_func.inverse_conv(conv_func(loads), True) npt.assert_allclose(loads, recovered)
def test_raises_uequal_shapes_circ(): with slippy.OverRideCuda(): im = e_im('zz', (128, 128), (0.01, 0.01), 200e9, 0.3) load_shapes = [(128, 129), (128, 129), (129, 128), (129, 128)] circulars = [True, (False, True), True, (True, False)] for l_s, circ in zip(load_shapes, circulars): with npt.assert_raises(AssertionError): loads = np.zeros(l_s) _ = c.plan_convolve(loads, im, circular=circ)
def contact_nodes(self, value): if value is None: self._contact_nodes = None else: value = np.array(value, dtype=bool) self._contact_nodes = value if self.im_mats: self.conv_func = plan_convolve(self._just_touching_gap, self.total_im, self._contact_nodes, circular=self._periodic_axes)
def test_non_circ_convolve_vs_scipy(): with slippy.OverRideCuda(): for l_s in loads_shapes: # generate an influence matrix, pick a component which is not symmetric! im_s = tuple(s * 2 for s in l_s) im = e_im('zx', im_s, (0.01, 0.01), 200e9, 0.3) loads = 1000 * np.random.rand(*l_s) scipy_result = fftconvolve(loads, im, mode='same') conv_func = c.plan_convolve(loads, im, fft_im=False) slippy_result = conv_func(loads) err_msg = f'Non circular convolution did not match scipy output for loads shape: {l_s} and IM shape: {im_s}' npt.assert_allclose(slippy_result, scipy_result, err_msg=err_msg)
def test_inverse_conv(): np.random.seed(0) try: import cupy # noqa: F401 slippy.CUDA = True except ImportError: return loads = np.random.rand(128, 128) im = e_im('zz', loads.shape, (1e-6, 1e-6), 200e9, 0.3) conv_func = c.plan_convolve(loads, im, circular=True, fft_im=False) recovered = conv_func.inverse_conv(conv_func(loads), True) npt.assert_allclose(loads, cp.asnumpy(recovered))
def test_dont_raise_equal_shapes_circ(): with slippy.OverRideCuda(): im = e_im('zz', (128, 128), (0.01, 0.01), 200e9, 0.3) load_shapes = [(128, 128), (128, 64), (64, 64), (64, 128)] circulars = [True, (True, False), False, (False, True)] for l_s, circ in zip(load_shapes, circulars): loads = np.zeros(l_s) try: _ = c.plan_convolve(loads, im, circular=circ) except: # noqa: E722 raise AssertionError( f"Plan convolve raised wrong error for mixed " f"convolution load shape: {l_s}, circ: {circ}")
def test_raises_uequal_shapes_circ(): try: import cupy # noqa: F401 slippy.CUDA = True except ImportError: return im = e_im('zz', (128, 128), (0.01, 0.01), 200e9, 0.3) load_shapes = [(128, 129), (128, 129), (129, 128), (129, 128)] circulars = [True, (False, True), True, (True, False)] for l_s, circ in zip(load_shapes, circulars): with npt.assert_raises(AssertionError): loads = np.zeros(l_s) _ = c.plan_convolve(loads, im, circular=circ)
def test_circ_convolve_location(): with slippy.OverRideCuda(): for im_s, l_s in zip(shapes_circ, shapes_circ): # generate an influence matrix, pick a component which is not symmetric! im = e_im('zz', im_s, (0.01, 0.01), 200e9, 0.3) loads = np.zeros(l_s) loads[64, 64] = 1000 conv_func = c.plan_convolve(loads, im, circular=True) slippy_result = conv_func(loads) loc_load = np.argmax(loads) loc_result = np.argmax(slippy_result) err_msg = f'Circular convolution, location of load dosn\'t match displacement' \ f'for loads shape: {l_s} and IM shape: {im_s} \n ' \ f'expected: {np.unravel_index(loc_load,l_s)}, found: {np.unravel_index(loc_result,l_s)}' assert loc_load == loc_result, err_msg
def test_mixed_convolve(): with slippy.OverRideCuda(): for circ in [[True, False], [False, True]]: loads = np.zeros([128, 128]) im_s = tuple((2 - p) * s for p, s in zip(circ, loads.shape)) im = e_im('zz', im_s, (0.01, 0.01), 200e9, 0.3) loads[64, 64] = 1000 conv_func = c.plan_convolve(loads, im, circular=circ) slippy_result = conv_func(loads) loc_load = np.argmax(loads) loc_result = np.argmax(slippy_result) err_msg = f'Mixed circular convolution, location of load dosn\'t match displacement' \ f'for circular: {circ} \n ' \ f'expected: {np.unravel_index(loc_load, loads.shape)}, ' \ f'found: {np.unravel_index(loc_result, loads.shape)}' assert loc_load == loc_result, err_msg
def test_vs_sequential(): try: import cupy as cp slippy.CUDA = True except ImportError: return periodics = [(False, False), (True, False), (False, True), (True, True)] domains = (None, 0.5 > np.random.rand(16, 16)) comps = ['xz', 'zz'] loads = np.random.rand(16, 16) for p, d in itertools.product(periodics, domains): im_shape = tuple((2 - p) * s for p, s in zip(p, loads.shape)) ims = np.array([ core.elastic_influence_matrix_spatial(comp, im_shape, [1e-6] * 2, 200e9, 0.3) for comp in comps ]) multi_func = core.plan_multi_convolve(loads, ims, d, p, fft_ims=False) if d is None: multi_result = multi_func(loads) else: multi_result = multi_func(loads[d]) single_results = np.zeros_like(multi_result) single_funcs = [] for i in range(2): single_func = core.plan_convolve(loads, ims[i], d, p, fft_im=False) if d is None: single_results[i] = single_func(loads) else: single_results[i] = single_func(loads[d]) single_funcs.append(single_func) npt.assert_allclose(cp.asnumpy(multi_result), cp.asnumpy(single_results), atol=1e-30) if d is not None: multi_result = multi_func(loads[d], ignore_domain=True) single_results = np.zeros_like(multi_result) for i in range(2): single_results[i] = single_funcs[i](loads[d], ignore_domain=True) npt.assert_allclose(cp.asnumpy(multi_result), cp.asnumpy(single_results), atol=1e-30)
def test_non_circ_convolve_location(): try: import cupy as cp slippy.CUDA = True except ImportError: return for l_s in loads_shapes: # generate an influence matrix, pick a component which is not symmetric! im_s = tuple(s * 2 for s in l_s) im = e_im('zz', im_s, (0.01, 0.01), 200e9, 0.3) loads = np.zeros(l_s) loads[64, 64] = 1000 conv_func = c.plan_convolve(loads, im) slippy_result = cp.asnumpy(conv_func(loads)) loc_load = np.argmax(loads) loc_result = np.argmax(slippy_result) err_msg = f'Non circular convolution, location of load dosn\'t match displacement' \ f'for loads shape: {l_s} and IM shape: {im_s} \n ' \ f'expected: {np.unravel_index(loc_load,l_s)}, found: {np.unravel_index(loc_result,l_s)}' assert loc_load == loc_result, err_msg
def results(self): if self._results is None: print("No results found in height opt func") if slippy.CUDA: xp = cp else: xp = np if self.im_mats and 'surface_1_displacement' not in self._results: # need to put the loads into an np array of right shape # find the full displacements (and convert to np array) # find disp on surface 1 and surface 2 surf_1 = self._model.surface_1 surf_2 = self._model.surface_2 span = tuple([ s * (2 - pa) for s, pa in zip(self._just_touching_gap.shape, self._periodic_axes) ]) # noinspection PyUnresolvedReferences im1 = surf_1.material.influence_matrix( span=span, grid_spacing=[surf_1.grid_spacing] * 2, components=['zz'])['zz'] # noinspection PyUnresolvedReferences im2 = surf_2.material.influence_matrix( span=span, grid_spacing=[surf_1.grid_spacing] * 2, components=['zz'])['zz'] if 'domain' in self._results and 'loads_in_domain' in self._results: full_loads = xp.zeros(self._just_touching_gap.shape) full_loads[ self._results['domain']] = self._results['loads_in_domain'] full_disp = slippy.asnumpy( self.conv_func(self._results['loads_in_domain'], ignore_domain=True)) full_loads = slippy.asnumpy(full_loads) elif 'loads_z' in self._results: full_loads = slippy.asnumpy(self._results['loads_z']) full_disp = slippy.asnumpy( self._results['total_displacement_z']) else: raise ValueError("Results not properly set") conv_func_1 = plan_convolve(full_loads, im1, None, circular=self._periodic_axes) conv_func_2 = plan_convolve(full_loads, im2, None, circular=self._periodic_axes) disp_1 = conv_func_1(full_loads) disp_2 = conv_func_2(full_loads) if slippy.CUDA: disp_1, disp_2 = xp.asnumpy(disp_1), xp.asnumpy(disp_2) full_loads = xp.asnumpy(full_loads) total_load = float(np.sum(full_loads) * self._grid_spacing**2) if 'contact_nodes' in self._results: contact_nodes = self._results['contact_nodes'] else: contact_nodes = full_loads > 0 if 'gap' in self._results: gap = self._results['gap'] else: gap = self._just_touching_gap - self._results[ 'interference'] + full_disp results = { 'loads_z': full_loads, 'total_displacement_z': full_disp, 'surface_1_displacement_z': disp_1, 'surface_2_displacement_z': disp_2, 'contact_nodes': contact_nodes, 'total_normal_load': total_load, 'interference': self._results['interference'], 'gap': gap } return results else: return self._results