def test_poisson_2d_unity_dielectric():
    x = np.linspace(0, 5, 11)
    y = np.linspace(0, 5, 11)
    X, Y = np.meshgrid(x, y, indexing='ij')
    er = np.ones_like(X[1:, 1:])
    v0 = 10
    V = fdm.poisson_2d(X, Y, v_left=v0, conv=1e-7)
    Ver = fdm.poisson_2d(X, Y, dielectric=er, v_left=v0, conv=1e-7)
    assert V == approx(Ver)
def test_poisson_2d_dielectric():
    w = 2.0
    h = 1.0
    x = np.linspace(0, w, 41)
    y = np.linspace(0, h, 21)
    X, Y = np.meshgrid(x, y, indexing='ij')
    bc = {'v_top': 10, 'v_left': 5, 'v_right': -2, 'v_bottom': -4}
    er = np.ones_like(X)[:-1, :-1]
    V1 = fdm.poisson_2d(X, Y, **bc, conv=1e-3)
    V2 = fdm.poisson_2d(X, Y, **bc, dielectric=er, conv=1e-3)
    assert V1 == approx(V2)
def test_poisson_2d():
    w = 2.0
    h = 1.0
    x = np.linspace(0, w, 101)
    y = np.linspace(0, h, 51)
    X, Y = np.meshgrid(x, y, indexing='ij')
    bc = {'v_top': 10, 'v_left': 5, 'v_right': -2, 'v_bottom': -4}
    V = fdm.poisson_2d(X, Y, **bc, conv=1e-5)
    Va = fdm.trough_analytical(X, Y, **bc)
    # Exclude boundaries due to analytical error at corners
    assert V[1:-1, 1:-1] == approx(Va[1:-1, 1:-1], abs=0.1)
def test_poisson_2d_bc_slice():
    x = np.linspace(0, 1, 5)
    y = np.linspace(0, 1, 5)
    X, Y = np.meshgrid(x, y, indexing='ij')
    vbc = 16
    bc_val = np.zeros_like(X)
    bc_val[1:4, 2] = vbc
    bc_bool = bc_val > 0
    bc = (bc_bool, bc_val)
    V = fdm.poisson_2d(X, Y, bc=bc, conv=1e-6, sor=1)
    assert V[1:4, 2] == approx(vbc)
def test_poisson_2d_bc():
    x = np.linspace(0, 1, 5)
    y = np.linspace(0, 1, 5)
    X, Y = np.meshgrid(x, y, indexing='ij')
    bc_val = np.zeros_like(X)
    bc_val[2, 2] = 12.0
    bc_bool = bc_val > 0
    bc = (bc_bool, bc_val)
    V = fdm.poisson_2d(X, Y, bc=bc, conv=1e-6, sor=1)
    assert V == approx(
        np.array([[0, 0, 0, 0, 0], [0, 2, 4, 2, 0], [0, 4, 12, 4, 0],
                  [0, 2, 4, 2, 0], [0, 0, 0, 0, 0]]))
def test_poisson_2d_bc_mult():
    x = np.linspace(0, 1, 5)
    y = np.linspace(0, 1, 5)
    X, Y = np.meshgrid(x, y, indexing='ij')
    vbc1 = 13
    vbc2 = 7
    bc_val = np.zeros_like(X)
    bc_val[1, 3] = vbc1
    bc_val[3, 1] = vbc2
    bc_bool = bc_val > 0
    bc = (bc_bool, bc_val)
    V = fdm.poisson_2d(X, Y, bc=bc, conv=1e-6, sor=1)
    assert V[1, 3] == approx(vbc1)
    assert V[3, 1] == approx(vbc2)
def test_poisson_2d_coax_xysym():
    ri = 2.0e-3
    ro = 4.0e-3
    w = 1.1 * ro
    dx = ri / 40
    Va = 10.0
    x = np.arange(0, w, dx)
    y = np.arange(0, w, dx)
    X, Y = np.meshgrid(x, y, indexing='ij')
    R = np.sqrt(X**2 + Y**2)
    bc_bool = np.logical_or(R < ri, R > ro)
    bc_val = np.select([R < ri, R > ro], [Va, 0])
    bc = (bc_bool, bc_val)
    cc = CoaxCapacitor(ri, 1.0, ro - ri)
    expected = cc.potential(X, Y, Va=Va)
    potential = fdm.poisson_2d(X, Y, bc=bc, conv=1e-6, xsym=True, ysym=True)
    assert potential == approx(expected, abs=0.4)
def test_poisson_2d_coax():
    ri = 2.0e-3
    ro = 4.0e-3
    w = 1.1 * ro
    N = 101
    Va = 10.0
    x = np.linspace(-w, w, N)
    y = np.linspace(-w, w, N)
    X, Y = np.meshgrid(x, y, indexing='ij')
    R = np.sqrt(X**2 + Y**2)
    bc_bool = np.logical_or(R < ri, R > ro)
    bc_val = np.select([R < ri, R > ro], [Va, 0])
    bc = (bc_bool, bc_val)
    cc = CoaxCapacitor(ri, 1.0, ro - ri)
    expected = cc.potential(X, Y, Va=Va)
    potential = fdm.poisson_2d(X, Y, bc=bc, conv=1e-5)
    assert potential == approx(expected, abs=0.4)
def test_poisson_2d_coax_2layer():
    ri = 2.0e-3
    re = 2.8e-3
    ro = 4.0e-3
    er1, er2 = 4.0, 1.0
    w = 1.1 * ro
    N = 101
    Va = 10.0
    x = np.linspace(-w, w, N)
    y = np.linspace(-w, w, N)
    X, Y = np.meshgrid(x, y, indexing='ij')
    R = np.sqrt(X**2 + Y**2)
    er = np.select([R <= re, R > re], [er1, er2])[:-1, :-1]
    bc_bool = np.logical_or(R < ri, R > ro)
    bc_val = np.select([R < ri, R > ro], [Va, 0])
    bc = (bc_bool, bc_val)
    cc = CoaxCapacitor(ri, (er1, er2), (re - ri, ro - re))
    expected = cc.potential(X, Y, Va=Va)
    np.savetxt('e2d.csv', expected, delimiter=',', fmt='%.3f')
    potential = fdm.poisson_2d(X, Y, dielectric=er, bc=bc, conv=1e-5)
    assert potential == approx(expected, abs=0.6)
Exemple #10
0
class WireMtl():
    """Multi-conductor transmission line composed of round wires.

    The reference conductor can be a wire, plane, or round shield
    """
    def __init__(self, wires: list, ref, er: float = 1.0):
        """Create a wire-type MTL with the given wires.

        The wires are provided as Wire objects
        The wires are immersed in a relative permittivity of er
        ref is the reference conductor, of type Wire, Plane or Shield
        """
        if type(ref) not in (Wire, Plane, Shield):
            raise TypeError('ref must be wire, plane or shield')
        if len(wires) < 1:
            raise ValueError(
                'Requires at least 2 wires, or a reference plane or shield')
        for w in wires:
            if type(w) is not Wire:
                raise TypeError(f'Bad wire type')
        # TODO validate positions and radii
        self.wires = wires
        self.er = er
        self.ref = ref

    def get_tline(self, freq) -> TLine:
        return TLine(self.inductance(), self.capacitance(), freq=freq)

    def capacitance(self,
                    /,
                    method: str = None,
                    fdm_params: dict = {}) -> np.ndarray:
        """Calculate and return the capacitance matrix."""
        for wire in self.wires:  # Insulation is not yet supported
            assert wire.ins_thickness == 0.0
        if method is None or method.lower() == 'ana':
            return MU0 * EPS0 * self.er * np.linalg.inv(self.inductance())
        elif method.lower() == 'fdm':
            if type(self.ref) is not Wire or len(self.wires) != 1:
                raise Exception(
                    'FDM currently supports only two wires, no reference')
            # Define simulation region
            pad = 20  # Zero potential boundaries must be far away
            w_list = np.array([[wi.x - pad * wi.radius for wi in self.wires],
                               [wi.x + pad * wi.radius for wi in self.wires]])
            h_list = np.array([[wi.y - pad * wi.radius for wi in self.wires],
                               [wi.y + pad * wi.radius for wi in self.wires]])
            # Grid based on wire size or user configured
            x0, y0, r0 = self.ref.x, self.ref.y, self.ref.radius
            x1, y1, r1 = self.wires[0].x, self.wires[0].y, self.wires[0].radius
            dx = fdm_params.get('dx', min(r0, r1) / 6)
            x = np.arange(w_list.min(), w_list.max(), dx)
            y = np.arange(h_list.min(), h_list.max(), dx)
            X, Y = np.meshgrid(x, y, indexing='ij')
            print(
                f'{x.max() - x.min():.3e}, {y.max() - y.min():.3e} dimensions')
            print(f'{X.shape}, {dx:.3e} grid')
            print(f'{X.size} points')
            # Solve for potential
            V1 = 100.0
            bc1 = np.sqrt((X - x0)**2 + (Y - y0)**2) <= r0
            bc2 = np.sqrt((X - x1)**2 + (Y - y1)**2) <= r1
            bc_val = np.zeros_like(X)
            bc_val[bc1] = 0.5 * V1
            bc_val[bc2] = -0.5 * V1
            bc_bool = bc_val != 0.0
            V = fdm.poisson_2d(X, Y, bc=(bc_bool, bc_val), conv=1e-5)
            er = self.er * np.ones_like(X)[:-1, :-1]
            # Calculate charge and capacitances
            C = np.zeros((len(self.wires), len(self.wires)))
            for i, wi in enumerate(self.wires):
                # Keep some distance from wire surface, but cannot overlap other wire
                # TODO make this more robust
                gpad = wi.radius + 4 * dx
                xi1 = np.searchsorted(x, wi.x - gpad)
                xi2 = np.searchsorted(x, wi.x + gpad)
                yi1 = np.searchsorted(y, wi.y - gpad)
                yi2 = np.searchsorted(y, wi.y + gpad)
                print(
                    f'({x[xi1]:.3e}, {x[xi2]:.3e}), ({y[yi1]:.3e}, {y[yi2]:.3e}) gauss'
                )
                C[i] = abs(fdm.gauss_2d(X, Y, V, er, xi1, xi2, yi1, yi2) / V1)
            return np.array([C[0]])
        else:
            raise Exception(f'Invalid method specified: {method}')
def test_poisson_2d_indexing():
    x = np.linspace(0, 2.0, 21)
    y = np.linspace(0, 1.0, 11)
    X, Y = np.meshgrid(x, y, indexing='ij')
    with pytest.raises(Exception):
        fdm.poisson_2d(X, Y)