def get_weights_circ(r, Nbar, Y): """ it evaluates integral weights, which are used for upper-lower bounds calculation, with constant circular inclusion Parameters ---------- r - the parameter determining the size of inclusion Nbar - no. of points of regular grid where the weights are evaluated Y - the size of periodic unit cell Returns ------- Wphi - integral weights at regular grid sizing Nbar """ d = np.size(Y) ZN2l = Grid.get_ZNl(Nbar) meas_puc = np.prod(Y) circ = 0 for m in np.arange(d): Nshape = np.ones(d) Nshape[m] = Nbar[m] Nrep = np.copy(Nbar) Nrep[m] = 1 xi_p2 = np.tile(np.reshape((ZN2l[m] / Y[m])**2, Nshape), Nrep) circ += xi_p2 circ = circ**0.5 ind = tuple(np.round(Nbar / 2)) circ[ind] = 1. Wphi = r**2 * sp.jn(1, 2 * np.pi * circ * r) / (circ * r) Wphi[ind] = np.pi * r**2 Wphi = Wphi / meas_puc return Wphi
def get_weights_circ(r, Nbar, Y): """ it evaluates integral weights, which are used for upper-lower bounds calculation, with constant circular inclusion Parameters ---------- r - the parameter determining the size of inclusion Nbar - no. of points of regular grid where the weights are evaluated Y - the size of periodic unit cell Returns ------- Wphi - integral weights at regular grid sizing Nbar """ d = np.size(Y) ZN2l = Grid.get_ZNl(Nbar) meas_puc = np.prod(Y) circ = 0 for m in np.arange(d): Nshape = np.ones(d) Nshape[m] = Nbar[m] Nrep = np.copy(Nbar) Nrep[m] = 1 xi_p2 = np.tile(np.reshape((ZN2l[m]/Y[m])**2, Nshape), Nrep) circ += xi_p2 circ = circ**0.5 ind = tuple(np.round(Nbar/2)) circ[ind] = 1. Wphi = r**2 * sp.jn(1, 2*np.pi*circ*r) / (circ*r) Wphi[ind] = np.pi*r**2 Wphi = Wphi / meas_puc return Wphi
def get_A_GaNi(self, N, primaldual='primal'): """ Returns stiffness matrix for a scheme with trapezoidal quadrature rule. """ coord = Grid.get_coordinates(N, self.Y) A = self.evaluate(coord) if primaldual is 'dual': A = A.inv() return A
def get_A_Ga(self, Nbar, primaldual='primal', order=None, P=None): """ Returns stiffness matrix for scheme with exact integration.""" if order is None and 'order' in self.conf: order = self.conf['order'] if order is None: shape_funs = self.get_shape_functions(Nbar) val = np.zeros(self.conf['vals'][0].shape + shape_funs[0].shape) for ii in range(len(self.conf['inclusions'])): if primaldual is 'primal': Aincl = self.conf['vals'][ii] elif primaldual is 'dual': Aincl = np.linalg.inv(self.conf['vals'][ii]) val += np.einsum('ij...,k...->ijk...', Aincl, shape_funs[ii]) return Matrix(name='A_Ga', val=val, Fourier=False) else: if P is None and 'P' in self.conf: P = self.conf['P'] coord = Grid.get_coordinates(P, self.Y) vals = self.evaluate(coord) dim = vals.d if primaldual is 'dual': vals = vals.inv() h = self.Y/P if order in [0, 'constant']: Wraw = get_weights_con(h, Nbar, self.Y) elif order in [1, 'bilinear']: Wraw = get_weights_lin(h, Nbar, self.Y) Aapp = np.zeros(np.hstack([dim, dim, Nbar])) for m in np.arange(dim): for n in np.arange(dim): hAM0 = DFT.fftnc(vals[m, n], P) if np.allclose(P, Nbar): hAM = hAM0 elif np.all(np.greater_equal(P, Nbar)): hAM = decrease(hAM0, Nbar) elif np.all(np.less(P, Nbar)): factor = np.ceil(np.array(Nbar, dtype=np.float64) / P) hAM0per = np.tile(hAM0, 2*factor-1) hAM = decrease(hAM0per, Nbar) else: raise ValueError() pNbar = np.prod(Nbar) """ if DFT is normalized in accordance with articles there should be np.prod(M) instead of np.prod(Nbar)""" Aapp[m, n] = np.real(pNbar*DFT.ifftnc(Wraw*hAM, Nbar)) name = 'A_Ga_o%d_P%d' % (order, P.max()) return Matrix(name=name, val=Aapp, Fourier=False)
def savefig(self, fname='material.pdf', N=50*np.ones(2)): import pylab as pl pl.figure(num=None, figsize=(3,3), dpi=1000) coord = Grid.get_coordinates(N, self.Y) vals = self.evaluate(coord)[0, 0] pl.pcolor(coord[0], coord[1], -vals) pl.xlim([-self.Y[0]/2, self.Y[0]/2]) pl.ylim([-self.Y[1]/2, self.Y[1]/2]) pl.xlabel(r'coordinate $x_1$') pl.ylabel(r'coordinate $x_2$') pl.savefig(fname, pad_inches=0.02, bbox_inches='tight') pl.close()
def savefig(self, fname='material.pdf', N=50 * np.ones(2)): import pylab as pl pl.figure(num=None, figsize=(3, 3), dpi=1000) coord = Grid.get_coordinates(N, self.Y) vals = self.evaluate(coord)[0, 0] pl.pcolor(coord[0], coord[1], -vals) pl.xlim([-self.Y[0] / 2, self.Y[0] / 2]) pl.ylim([-self.Y[1] / 2, self.Y[1] / 2]) pl.xlabel(r'coordinate $x_1$') pl.ylabel(r'coordinate $x_2$') pl.savefig(fname, pad_inches=0.02, bbox_inches='tight') pl.close()
def get_shift_inclusion(N, h, Y): N = np.array(N, dtype=np.int32) Y = np.array(Y, dtype=np.float64) dim = N.size ZN = Grid.get_ZNl(N) SS = np.ones(N, dtype=np.complex128) for ii in np.arange(dim): Nshape = np.ones(dim) Nshape[ii] = N[ii] Nrep = N Nrep[ii] = 1 SS *= np.tile(np.reshape(np.exp(-2*np.pi*1j*(h[ii]*ZN[ii]/Y[ii])), Nshape), Nrep) return SS
def get_shift_inclusion(N, h, Y): N = np.array(N, dtype=np.int32) Y = np.array(Y, dtype=np.float64) dim = N.size ZN = Grid.get_ZNl(N) SS = np.ones(N, dtype=np.complex128) for ii in np.arange(dim): Nshape = np.ones(dim) Nshape[ii] = N[ii] Nrep = N Nrep[ii] = 1 SS *= np.tile( np.reshape(np.exp(-2 * np.pi * 1j * (h[ii] * ZN[ii] / Y[ii])), Nshape), Nrep) return SS
def curl_norm(e, Y): """ it calculates curl-based norm, it controls that the fields are curl-free with zero mean as it is required of electric fields Parameters ---------- e - electric field Y - the size of periodic unit cell Returns ------- curlnorm - curl-based norm """ N = np.array(np.shape(e[0])) d = np.size(N) xil = Grid.get_xil(N, Y) xiM = [] Fe = [] for m in np.arange(d): Nshape = np.ones(d) Nshape[m] = N[m] Nrep = np.copy(N) Nrep[m] = 1 xiM.append(np.tile(np.reshape(xil[m], Nshape), Nrep)) Fe.append(DFT.fftnc(e[m], N)/np.prod(N)) if d == 2: Fe.append(np.zeros(N)) xiM.append(np.zeros(N)) ind_mean = tuple(np.fix(N/2)) curl = [] e0 = [] for m in np.arange(3): j = (m+1) % 3 k = (j+1) % 3 curl.append(xiM[j]*Fe[k]-xiM[k]*Fe[j]) e0.append(np.real(Fe[m][ind_mean])) curl = np.array(curl) curlnorm = np.real(np.sum(curl[:]*np.conj(curl[:]))) curlnorm = (curlnorm/np.prod(N))**0.5 norm_e0 = np.linalg.norm(e0) if norm_e0 > 1e-10: curlnorm = curlnorm/norm_e0 return curlnorm
def matrix(self): """ This function returns the object as a matrix of DFT or iDFT resp. """ prodN = np.prod(self.N) proddN = self.d*prodN DTM = np.zeros(np.hstack([self.N, self.N]), dtype=np.complex128) ZNl = Grid.get_ZNl(self.N) if not self.inverse: coef = 1./np.prod(self.N) else: coef = np.prod(self.N) for nx in ZNl[0]: for ny in ZNl[1]: IM = np.zeros(np.array(self.N), dtype=np.float64) IM[nx, ny] = 1 DTM[nx, ny, :, :] = coef*DFT.fftnc(IM, self.N) import numpy.matlib as npmatlib DTMd = npmatlib.zeros([proddN, proddN], dtype=np.complex128) for ii in np.arange(self.d): DTMd[prodN*ii:prodN**(ii+1), prodN*ii:prodN**(ii+1)] = DTM return DTMd
def scalar(N, Y, centered=True, NyqNul=True): """ Assembly of discrete kernels in Fourier space for scalar elliptic problems. Parameters ---------- N : numpy.ndarray no. of discretization points Y : numpy.ndarray size of periodic unit cell Returns ------- G1l : numpy.ndarray discrete kernel in Fourier space; provides projection on curl-free fields with zero mean G2l : numpy.ndarray discrete kernel in Fourier space; provides projection on divergence-free fields with zero mean """ d = np.size(N) N = np.array(N) if NyqNul: Nred = get_Nodd(N) else: Nred = N xi = Grid.get_xil(Nred, Y) xi2 = [] for m in np.arange(d): xi2.append(xi[m]**2) G0l = np.zeros(np.hstack([d, d, Nred])) G1l = np.zeros(np.hstack([d, d, Nred])) G2l = np.zeros(np.hstack([d, d, Nred])) num = np.zeros(np.hstack([d, d, Nred])) denom = np.zeros(Nred) ind_center = tuple(np.fix(np.array(Nred)/2)) for m in np.arange(d): # diagonal components Nshape = np.ones(d) Nshape[m] = Nred[m] Nrep = np.copy(Nred) Nrep[m] = 1 a = np.reshape(xi2[m], Nshape) num[m][m] = np.tile(a, Nrep) # numerator denom = denom + num[m][m] G0l[m, m][ind_center] = 1 for m in np.arange(d): # upper diagonal components for n in np.arange(m+1, d): NshapeM = np.ones(d) NshapeM[m] = Nred[m] NrepM = np.copy(Nred) NrepM[m] = 1 NshapeN = np.ones(d) NshapeN[n] = Nred[n] NrepN = np.copy(Nred) NrepN[n] = 1 num[m][n] = np.tile(np.reshape(xi[m], NshapeM), NrepM) \ * np.tile(np.reshape(xi[n], NshapeN), NrepN) # avoiding a division by zero denom[ind_center] = 1 # calculation of projections for m in np.arange(d): for n in np.arange(m, d): G1l[m][n] = num[m][n]/denom G2l[m][n] = (m == n)*np.ones(Nred) - G1l[m][n] G2l[m][n][ind_center] = 0 # symmetrization for m in np.arange(1, d): for n in np.arange(m): G1l[m][n] = G1l[n][m] G2l[m][n] = G2l[n][m] if not centered: for m in np.arange(d): for n in np.arange(d): G1l[m][n] = np.fft.ifftshift(G1l[m][n]) G2l[m][n] = np.fft.ifftshift(G2l[m][n]) G0l = Matrix(name='hG0', val=G0l, Fourier=True) G1l = Matrix(name='hG1', val=G1l, Fourier=True) G2l = Matrix(name='hG2', val=G2l, Fourier=True) if NyqNul: G0l = G0l.enlarge(N) G1l = G1l.enlarge(N) G2l = G2l.enlarge(N) return G0l, G1l, G2l
def elasticity(N, Y, centered=True, NyqNul=True): """ Projection matrix on a space of admissible strain fields INPUT = N : ndarray of e.g. stiffness coefficients d : dimension; d = 2 D : dimension in engineering notation; D = 3 Y : the size of periodic unit cell OUTPUT = G1h,G1s,G2h,G2s : projection matrices of size DxDxN """ xi = Grid.get_xil(N, Y) N = np.array(N) d = N.size D = d*(d+1)/2 if NyqNul: Nred = get_Nodd(N) else: Nred = N xi2 = [] for ii in np.arange(d): xi2.append(xi[ii]**2) num = np.zeros(np.hstack([d, d, Nred])) norm2_xi = np.zeros(Nred) for mm in np.arange(d): # diagonal components Nshape = np.ones(d) Nshape[mm] = Nred[mm] Nrep = np.copy(Nred) Nrep[mm] = 1 num[mm][mm] = np.tile(np.reshape(xi2[mm], Nshape), Nrep) # numerator norm2_xi += num[mm][mm] norm4_xi = norm2_xi**2 ind_center = tuple(Nred/2) # avoid division by zero norm2_xi[ind_center] = 1 norm4_xi[ind_center] = 1 for m in np.arange(d): # upper diagonal components for n in np.arange(m+1, d): NshapeM = np.ones(d) NshapeM[m] = Nred[m] NrepM = np.copy(Nred) NrepM[m] = 1 NshapeN = np.ones(d) NshapeN[n] = Nred[n] NrepN = np.copy(Nred) NrepN[n] = 1 num[m][n] = np.tile(np.reshape(xi[m], NshapeM), NrepM) \ * np.tile(np.reshape(xi[n], NshapeN), NrepN) # G1h = np.zeros([D,D]).tolist() G1h = np.zeros(np.hstack([D, D, Nred])) G1s = np.zeros(np.hstack([D, D, Nred])) IS0 = np.zeros(np.hstack([D, D, Nred])) mean = np.zeros(np.hstack([D, D, Nred])) Lamh = np.zeros(np.hstack([D, D, Nred])) S = np.zeros(np.hstack([D, D, Nred])) W = np.zeros(np.hstack([D, D, Nred])) WT = np.zeros(np.hstack([D, D, Nred])) for m in np.arange(d): S[m][m] = 2*num[m][m]/norm2_xi for n in np.arange(d): G1h[m][n] = num[m][m]*num[n][n]/norm4_xi Lamh[m][n] = np.ones(Nred)/d Lamh[m][n][ind_center] = 0 for m in np.arange(D): IS0[m][m] = np.ones(Nred) IS0[m][m][ind_center] = 0 mean[m][m][ind_center] = 1 if d == 2: S[0][2] = 2**0.5*num[0][1]/norm2_xi S[1][2] = 2**0.5*num[0][1]/norm2_xi S[2][2] = np.ones(Nred) S[2][2][ind_center] = 0 G1h[0][2] = 2**0.5*num[0][0]*num[0][1]/norm4_xi G1h[1][2] = 2**0.5*num[0][1]*num[1][1]/norm4_xi G1h[2][2] = 2*num[0][0]*num[1][1]/norm4_xi for m in np.arange(d): for n in np.arange(d): W[m][n] = num[m][m]/norm2_xi W[2][m] = 2**.5*num[0][1]/norm2_xi elif d == 3: for m in np.arange(d): S[m+3][m+3] = 1 - num[m][m]/norm2_xi S[m+3][m+3][ind_center] = 0 for m in np.arange(d): for n in np.arange(m+1, d): S[m+3][n+3] = num[m][n]/norm2_xi G1h[m+3][n+3] = num[m][m]*num[n][n]/norm4_xi for m in np.arange(d): for n in np.arange(d): ind = sp.setdiff1d(np.arange(d), [n]) S[m][n+3] = (0 == (m == n))*2**.5*num[ind[0]][ind[1]]/norm2_xi G1h[m][n+3] = 2**.5*num[m][m]*num[ind[0]][ind[1]]/norm4_xi W[m][n] = num[m][m]/norm2_xi W[n+3][m] = 2**.5*num[ind[0]][ind[1]]/norm2_xi for m in np.arange(d): for n in np.arange(d): ind_m = sp.setdiff1d(np.arange(d), [m]) ind_n = sp.setdiff1d(np.arange(d), [n]) G1h[m+3][n+3] = 2*num[ind_m[0]][ind_m[1]] \ * num[ind_n[0]][ind_n[1]] / norm4_xi # symmetrization for n in np.arange(D): for m in np.arange(n+1, D): S[m][n] = S[n][m] G1h[m][n] = G1h[n][m] for m in np.arange(D): for n in np.arange(D): G1s[m][n] = S[m][n] - 2*G1h[m][n] WT[m][n] = W[n][m] G2h = 1./(d-1)*(d*Lamh + G1h - W - WT) G2s = IS0 - G1h - G1s - G2h if not centered: for m in np.arange(d): for n in np.arange(d): G1h[m][n] = np.fft.ifftshift(G1h[m][n]) G1s[m][n] = np.fft.ifftshift(G1s[m][n]) G2h[m][n] = np.fft.ifftshift(G2h[m][n]) G2s[m][n] = np.fft.ifftshift(G2s[m][n]) G0 = Matrix(name='hG1', val=mean, Fourier=True) G1h = Matrix(name='hG1', val=G1h, Fourier=True) G1s = Matrix(name='hG1', val=G1s, Fourier=True) G2h = Matrix(name='hG1', val=G2h, Fourier=True) G2s = Matrix(name='hG1', val=G2s, Fourier=True) if NyqNul: G0 = G0.enlarge(N) G1h = G1h.enlarge(N) G1s = G1s.enlarge(N) G2h = G2h.enlarge(N) G2s = G2s.enlarge(N) return mean, G1h, G1s, G2h, G2s
def get_A_Ga(self, Nbar, primaldual='primal', order=-1, P=None): """ Returns stiffness matrix for scheme with exact integration. """ if order == -1: if 'order' in self.conf: order = self.conf['order'] else: raise ValueError('The material order is undefined!') elif order not in [None, 'exact', 0, 1]: raise ValueError('Wrong material order (%s)!' % str(order)) if order in [None, 'exact']: shape_funs = self.get_shape_functions(Nbar) val = np.zeros(self.conf['vals'][0].shape + shape_funs[0].shape) for ii in range(len(self.conf['inclusions'])): if primaldual is 'primal': Aincl = self.conf['vals'][ii] elif primaldual is 'dual': Aincl = np.linalg.inv(self.conf['vals'][ii]) val += np.einsum('ij...,k...->ijk...', Aincl, shape_funs[ii]) name = 'A_Ga' else: if P is None and 'P' in self.conf: P = self.conf['P'] coord = Grid.get_coordinates(P, self.Y) vals = self.evaluate(coord) dim = vals.d if primaldual is 'dual': vals = vals.inv() h = self.Y / P if order in [0, 'constant']: Wraw = get_weights_con(h, Nbar, self.Y) elif order in [1, 'bilinear']: Wraw = get_weights_lin(h, Nbar, self.Y) val = np.zeros(np.hstack([dim, dim, Nbar])) for m in np.arange(dim): for n in np.arange(dim): hAM0 = DFT.fftnc(vals[m, n], P) if np.allclose(P, Nbar): hAM = hAM0 elif np.all(np.greater_equal(P, Nbar)): hAM = decrease(hAM0, Nbar) elif np.all(np.less(P, Nbar)): factor = np.ceil(np.array(Nbar, dtype=np.float64) / P) hAM0per = np.tile(hAM0, 2 * factor - 1) hAM = decrease(hAM0per, Nbar) else: raise ValueError() pNbar = np.prod(Nbar) """ if DFT is normalized in accordance with articles there should be np.prod(M) instead of np.prod(Nbar)""" val[m, n] = np.real(pNbar * DFT.ifftnc(Wraw * hAM, Nbar)) name = 'A_Ga_o%d_P%d' % (order, P.max()) return Matrix(name=name, val=val, Fourier=False)
def get_A_GaNi(self, N, primaldual='primal'): coord = Grid.get_coordinates(N, self.Y) A = self.evaluate(coord) if primaldual is 'dual': A = A.inv() return A