Приложения

А. Финальный вычислительный скрипт

Ниже приведён финальный скрипт, принятый в теории как вычислительная основа построения общего внутреннего объёма рядных псевдогиперболоидов n-го порядка. Скрипт помещён в приложение для воспроизводимости геометрических рисунков и проверки алгоритмической базы.

# -*- coding: utf-8 -*-

«»»

ФИНАЛЬНЫЙ СКРИПТ.

Построение открытых псевдогиперболоидов n-го порядка по рекурсивной схеме

    B_2 = {d},

    B_{k+1} = {R_k + r, R_k — r : r in B_k},

    N_n = 2^(n-2).

В ЭТОЙ ВЕРСИИ:

1) строится не просто набор ветвей, а ИТОГОВЫЙ ОБЩИЙ ОБЪЁМ;

2) если отдельные псевдогиперболоидные тороиды пересекаются или вложены,

   удаляется только их общая часть как дублирование объёма;

3) сами тороиды как порождающие объекты НЕ удаляются;

4) итоговая фигура есть объединение всех объёмов;

5) если тороиды не пересекаются, они показываются отдельно;

6) правило действует для всех порядков и для всех рядов.

Поддерживаются:

— вертикальный тип;

— горизонтальный тип;

— все порядки от 2 до n;

— 2D меридиональные сечения общего объёма;

— 3D поверхности общего объёма вращения;

— стек одинаковых экземпляров на общей оси вращения.

«»»

from __future__ import annotations

import math

from pathlib import Path

from dataclasses import dataclass

from typing import Dict, List, Sequence, Tuple

import numpy as np

import matplotlib.pyplot as plt

# ————————————————————

# НАСТРОЙКИ ОТОБРАЖЕНИЯ

# ————————————————————

plt.rcParams.update({

    «figure.dpi»: 140,

    «savefig.dpi»: 300,

    «font.size»: 11,

    «axes.grid»: True,

    «grid.alpha»: 0.22,

    «font.family»: «DejaVu Sans»,

})

SURFACE_ALPHA = 0.62

MERGE_TOL = 1.0e-9

NPHI = 220

# В 2D по умолчанию НЕ заливаем области, чтобы не появлялись

# искусственные прямые замыкающие отрезки от fill_betweenx.

FILL_2D_AREAS = False

# ————————————————————

# БАЗОВАЯ ГЕОМЕТРИЯ

# ————————————————————

def c_focus(a: float, b: float) -> float:

    return math.sqrt(a * a + b * b)

def L_open(a: float, b: float, R: float) -> float:

    «»»Продольный предел существования открытого профиля вертикального типа.»»»

    return a * math.sqrt(1.0 + (R / b) ** 2)

def eta_hyperbola(abs_x: np.ndarray, a: float, b: float) -> np.ndarray:

    abs_x = np.asarray(abs_x, dtype=float)

    val = (abs_x / a) ** 2 — 1.0

    val = np.maximum(val, 0.0)

    return b * np.sqrt(val)

def rho_vertical(abs_s: np.ndarray, a: float, b: float, R: float) -> np.ndarray:

    «»»

    Открытый профиль вертикального типа:

        rho(|s|) = R — b*sqrt((|s|/a)^2 — 1),   a <= |s| <= L.

    «»»

    out = R — eta_hyperbola(abs_s, a, b)

    return np.maximum(out, 0.0)

def x_horizontal(u: np.ndarray, a: float, b: float, R: float) -> np.ndarray:

    «»»

    Горизонтальный тип:

        x_h(u) = a * sqrt(1 + ((R — |u|)/b)^2),   |u| <= R.

    «»»

    u = np.asarray(u, dtype=float)

    return a * np.sqrt(1.0 + ((R — np.abs(u)) / b) ** 2)

# ————————————————————

# БАЗОВЫЕ СЕТКИ ДЛЯ ДВУХ ТИПОВ

# ————————————————————

def _ensure_zero_in_axis(arr: np.ndarray) -> np.ndarray:

    arr = np.asarray(arr, dtype=float)

    if np.any(np.isclose(arr, 0.0, atol=1e-14)):

        return arr

    arr2 = np.concatenate([arr, np.array([0.0])])

    arr2.sort()

    return arr2

def vertical_base_grid(a: float, b: float, R: float, npts: int = 900) -> Dict[str, np.ndarray]:

    L = L_open(a, b, R)

    s_left = np.linspace(-L, -a, npts)

    s_right = np.linspace(a, L, npts)

    d_left = rho_vertical(np.abs(s_left), a, b, R)

    d_right = rho_vertical(np.abs(s_right), a, b, R)

    return {

        «axis_left»: s_left,

        «axis_right»: s_right,

        «d_left»: d_left,

        «d_right»: d_right,

        «L»: L,

    }

def horizontal_base_grid(a: float, b: float, R: float, npts: int = 900) -> Dict[str, np.ndarray]:

    u = np.linspace(-R, R, npts)

    u = _ensure_zero_in_axis(u)

    d = x_horizontal(u, a, b, R)

    return {

        «axis»: u,

        «d»: d,

        «L»: R,

    }

# ————————————————————

# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ

# ————————————————————

def morphology_class(R: float, offsets: Sequence[float]) -> str:

    if not offsets:

        return «только базовый 2-й порядок»

    R_star = max(offsets)

    if R > R_star:

        return «с внутренним пересечением»

    if math.isclose(R, R_star, rel_tol=1e-12, abs_tol=1e-12):

        return «симметричный»

    return «кольцевой непересекающийся»

def validate_offsets(base_distance: np.ndarray, offsets: Sequence[float]) -> List[str]:

    «»»

    Не блокирующая проверка. Строить всё равно можно.

    Сообщения носят информационный характер.

    «»»

    msgs = []

    current_max = float(np.max(base_distance))

    for i, offset in enumerate(offsets, start=1):

        if offset < current_max:

            msgs.append(

                f»На шаге R{i}: R{i} = {offset:.6f} < {current_max:.6f}. «

                f»Это означает пересечение / вложение компонент и необходимость брать объединение объёмов.»

            )

        elif math.isclose(offset, current_max, rel_tol=1e-12, abs_tol=1e-12):

            msgs.append(

                f»На шаге R{i}: R{i} = {offset:.6f} равно {current_max:.6f}. «

                f»Это предельный случай касания компонент.»

            )

        current_max = offset + current_max

    return msgs

def stack_shifts(axis_half_length: float, h: float, m: int) -> np.ndarray:

    «»»

    Возвращает сдвиги центров m одинаковых экземпляров вдоль общей оси вращения.

    Полная длина одного экземпляра вдоль общей оси = 2 * axis_half_length.

    Шаг между центрами соседних экземпляров:

        step = 2 * axis_half_length + h

    «»»

    if int(m) != m or m < 1:

        raise ValueError(«Параметр m должен быть целым числом >= 1»)

    m = int(m)

    step = 2.0 * float(axis_half_length) + float(h)

    return -np.arange(m, dtype=float) * step

def _ensure_dir(path: Path):

    path.mkdir(parents=True, exist_ok=True)

def _save_or_show(fig, path: Path | None, show: bool):

    if path is not None:

        fig.savefig(path, bbox_inches=»tight»)

    if show:

        plt.show()

    else:

        plt.close(fig)

# ————————————————————

# РЕКУРСИВНЫЕ РАДИАЛЬНЫЕ ИНТЕРВАЛЫ

# ————————————————————

def build_recursive_interval_arrays(base_distance: np.ndarray,

                                    offsets: Sequence[float]) -> List[Tuple[np.ndarray, np.ndarray]]:

    «»»

    Строит интервалы радиального объёма для одного порядка.

    Порядок 2:

        [0, d]

    Следующий шаг для каждого интервала [lo, hi]:

        [R — hi, R — lo]  и  [R + lo, R + hi]

    Это соответствует объединению объёмов порождающих тороидов,

    без удаления самих тороидов как объектов построения.

    «»»

    zero = np.zeros_like(base_distance, dtype=float)

    intervals = [(zero.copy(), np.asarray(base_distance, dtype=float).copy())]

    for Rk in offsets:

        nxt: List[Tuple[np.ndarray, np.ndarray]] = []

        for lo, hi in intervals:

            a = np.maximum(Rk — hi, 0.0)

            b = np.maximum(Rk — lo, 0.0)

            c = np.maximum(Rk + lo, 0.0)

            d = np.maximum(Rk + hi, 0.0)

            nxt.append((a, b))

            nxt.append((c, d))

        intervals = nxt

    return intervals

@dataclass

class Piece:

    axis: np.ndarray

    lo: np.ndarray

    hi: np.ndarray

# ————————————————————

# ПОСТРОЕНИЕ ОБЩЕГО ОБЪЁМА ДЛЯ ДАННОГО ПОРЯДКА

# ————————————————————

def _interp_piece_to_global_axis(piece: Piece, global_axis: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:

    x = piece.axis

    lo = piece.lo

    hi = piece.hi

    lo_i = np.interp(global_axis, x, lo)

    hi_i = np.interp(global_axis, x, hi)

    mask = (global_axis >= x.min() — 1e-12) & (global_axis <= x.max() + 1e-12)

    lo_i[~mask] = np.nan

    hi_i[~mask] = np.nan

    return lo_i, hi_i

def _merge_scalar_intervals(intervals: List[Tuple[float, float]], tol: float = MERGE_TOL) -> List[Tuple[float,

    float]]:

    if not intervals:

        return []

    data = [(float(min(a, b)), float(max(a, b))) for a, b in intervals if np.isfinite(a) and np.isfinite(b) and b > a

        + tol]

    if not data:

        return []

    data.sort(key=lambda t: (t[0], t[1]))

    merged = [list(data[0])]

    for a, b in data[1:]:

        if a <= merged[-1][1] + tol:

            merged[-1][1] = max(merged[-1][1], b)

        else:

            merged.append([a, b])

    return [(a, b) for a, b in merged]

def _build_merged_components_from_pieces(pieces: List[Piece], n_global: int | None = None) -> Tuple[np.ndarray,

    List[np.ndarray], List[np.ndarray]]:

    if not pieces:

        raise ValueError(«Нет компонент для построения общего объёма»)

    # Глобальная ось: объединение всех реальных узлов.

    all_axis = np.concatenate([p.axis for p in pieces])

    global_axis = np.unique(np.round(all_axis, 12))

    global_axis.sort()

    if n_global is not None and n_global > global_axis.size:

        dense = np.linspace(global_axis.min(), global_axis.max(), n_global)

        global_axis = np.unique(np.concatenate([global_axis, dense]))

        global_axis.sort()

    # ВАЖНО: если между двумя рядами / компонентами есть реальный пустой зазор,

    # нельзя позволять линии или поверхности соединять края этого зазора.

    # Поэтому добавляем контрольные точки в середины всех пустых промежутков

    # между проекциями компонент на общую ось. В этих точках интервалов нет,

    # и график разрывается сам, без дорисовывания.

    cover = sorted((float(np.min(p.axis)), float(np.max(p.axis))) for p in pieces)

    merged_cover: List[List[float]] = []

    for a0, b0 in cover:

        if not merged_cover or a0 > merged_cover[-1][1] + MERGE_TOL:

            merged_cover.append([a0, b0])

        else:

            merged_cover[-1][1] = max(merged_cover[-1][1], b0)

    gap_points = []

    for left, right in zip(merged_cover[:-1], merged_cover[1:]):

        if right[0] > left[1] + MERGE_TOL:

            gap_points.append(0.5 * (left[1] + right[0]))

    if gap_points:

        global_axis = np.unique(np.concatenate([global_axis, np.array(gap_points, dtype=float)]))

        global_axis.sort()

    interpolated: List[Tuple[np.ndarray, np.ndarray]] = [

        _interp_piece_to_global_axis(piece, global_axis) for piece in pieces

    ]

    merged_per_sample: List[List[Tuple[float, float]]] = []

    max_count = 0

    for j in range(global_axis.size):

        scalars: List[Tuple[float, float]] = []

        for lo_i, hi_i in interpolated:

            lo = lo_i[j]

            hi = hi_i[j]

            if np.isfinite(lo) and np.isfinite(hi) and hi > lo + MERGE_TOL:

                scalars.append((max(0.0, lo), max(0.0, hi)))

        merged = _merge_scalar_intervals(scalars, tol=MERGE_TOL)

        merged_per_sample.append(merged)

        max_count = max(max_count, len(merged))

    lo_components = [np.full(global_axis.shape, np.nan, dtype=float) for _ in range(max_count)]

    hi_components = [np.full(global_axis.shape, np.nan, dtype=float) for _ in range(max_count)]

    for j, merged in enumerate(merged_per_sample):

        for k, (a, b) in enumerate(merged):

            lo_components[k][j] = a

            hi_components[k][j] = b

    return global_axis, lo_components, hi_components

def _contiguous_segments(mask: np.ndarray, axis: np.ndarray | None = None) -> List[Tuple[int, int]]:

    mask = np.asarray(mask, dtype=bool)

    if mask.size == 0:

        return []

    # Дополнительная защита: если две соседние активные точки разделены

    # слишком большим шагом по оси, это означает реальный пустой промежуток

    # между компонентами. Его нельзя соединять прямой линией.

    if axis is not None and axis.size == mask.size and axis.size >= 3:

        dif = np.diff(axis)

        pos = dif[np.isfinite(dif) & (dif > 0)]

        if pos.size:

            med = float(np.median(pos))

            jump_thr = max(1e-12, 4.0 * med)

            jump_breaks = np.where(dif > jump_thr)[0]

            for j in jump_breaks:

                if 0 <= j < mask.size — 1:

                    mask[j] = False

                    mask[j + 1] = False

    segments: List[Tuple[int, int]] = []

    start = None

    for i, ok in enumerate(mask):

        if ok and start is None:

            start = i

        if (not ok) and start is not None:

            if i — start >= 2:

                segments.append((start, i))

            start = None

    if start is not None and mask.size — start >= 2:

        segments.append((start, mask.size))

    return segments

def _split_on_artificial_jumps(radius: np.ndarray) -> List[Tuple[int, int]]:

    «»»

    Дополнительно разбивает кривую там, где последовательность точек делает

    негеометрический скачок из-за смены индекса объединённого интервала.

    Это убирает искусственные прямые соединяющие отрезки.

    «»»

    radius = np.asarray(radius, dtype=float)

    n = radius.size

    if n < 2:

        return [(0, n)] if n > 0 else []

    dr = np.abs(np.diff(radius))

    finite = np.isfinite(dr)

    valid = dr[finite]

    if valid.size == 0:

        return [(0, n)]

    med = float(np.median(valid))

    mx = float(np.max(valid))

    if med <= 1e-12:

        jump_thr = max(1e-8, 0.05 * mx)

    else:

        jump_thr = max(1e-8, 8.0 * med)

    break_ids = np.where(dr > jump_thr)[0] + 1

    if break_ids.size == 0:

        return [(0, n)]

    segments = []

    st = 0

    for br in break_ids:

        if br — st >= 2:

            segments.append((st, int(br)))

        st = int(br)

    if n — st >= 2:

        segments.append((st, n))

    return segments

def _plot_boundary_curve(ax, radius: np.ndarray, axis: np.ndarray, lw: float):

    for st, en in _split_on_artificial_jumps(radius):

        ax.plot(radius[st:en], axis[st:en], lw=lw)

# ————————————————————

# ПОРОЖДАЮЩИЕ КОМПОНЕНТЫ ДЛЯ ОДНОГО ПОРЯДКА

# ————————————————————

def vertical_order_union_components(a: float,

                                    b: float,

                                    R: float,

                                    offsets: Sequence[float],

                                    npts: int,

                                    m: int,

                                    h: float) -> Tuple[np.ndarray, List[np.ndarray], List[np.ndarray], float]:

    base = vertical_base_grid(a, b, R, npts=npts)

    shifts = stack_shifts(float(base[«L»]), h, m)

    interval_left = build_recursive_interval_arrays(base[«d_left»], offsets)

    interval_right = build_recursive_interval_arrays(base[«d_right»], offsets)

    pieces: List[Piece] = []

    for shift in shifts:

        for lo, hi in interval_left:

            pieces.append(Piece(base[«axis_left»] + shift, lo, hi))

        for lo, hi in interval_right:

            pieces.append(Piece(base[«axis_right»] + shift, lo, hi))

    global_axis, lo_components, hi_components = _build_merged_components_from_pieces(pieces, n_global=max(2500, 3 *

        npts))

    return global_axis, lo_components, hi_components, float(base[«L»])

def horizontal_order_union_components(a: float,

                                      b: float,

                                      R: float,

                                      offsets: Sequence[float],

                                      npts: int,

                                      m: int,

                                      h: float) -> Tuple[np.ndarray, List[np.ndarray], List[np.ndarray], float,

                                          np.ndarray]:

    base = horizontal_base_grid(a, b, R, npts=npts)

    shifts = stack_shifts(float(base[«L»]), h, m)

    interval_base = build_recursive_interval_arrays(base[«d»], offsets)

    pieces: List[Piece] = []

    for shift in shifts:

        for lo, hi in interval_base:

            pieces.append(Piece(base[«axis»] + shift, lo, hi))

    global_axis, lo_components, hi_components = _build_merged_components_from_pieces(pieces, n_global=max(2500, 3 *

        npts))

    return global_axis, lo_components, hi_components, float(base[«L»]), shifts

# ————————————————————

# ПОВЕРХНОСТИ ВРАЩЕНИЯ

# ————————————————————

def revolve_about_x(axis_coord: np.ndarray, radius: np.ndarray, nphi: int = NPHI):

    phi = np.linspace(0.0, 2.0 * np.pi, nphi)

    S, Phi = np.meshgrid(axis_coord, phi, indexing=»ij»)

    RR = np.tile(radius[:, None], (1, phi.size))

    X = S

    Y = RR * np.cos(Phi)

    Z = RR * np.sin(Phi)

    return X, Y, Z

def revolve_about_y(axis_coord: np.ndarray, radius: np.ndarray, nphi: int = NPHI):

    phi = np.linspace(0.0, 2.0 * np.pi, nphi)

    U, Phi = np.meshgrid(axis_coord, phi, indexing=»ij»)

    RR = np.tile(radius[:, None], (1, phi.size))

    X = RR * np.cos(Phi)

    Y = U

    Z = RR * np.sin(Phi)

    return X, Y, Z

@dataclass

class PlotBounds3D:

    xmin: float = math.inf

    xmax: float = -math.inf

    ymin: float = math.inf

    ymax: float = -math.inf

    zmin: float = math.inf

    zmax: float = -math.inf

    def update(self, X: np.ndarray, Y: np.ndarray, Z: np.ndarray):

        self.xmin = min(self.xmin, float(np.nanmin(X)))

        self.xmax = max(self.xmax, float(np.nanmax(X)))

        self.ymin = min(self.ymin, float(np.nanmin(Y)))

        self.ymax = max(self.ymax, float(np.nanmax(Y)))

        self.zmin = min(self.zmin, float(np.nanmin(Z)))

        self.zmax = max(self.zmax, float(np.nanmax(Z)))

def set_axes_equal_real_3d(ax, bounds: PlotBounds3D):

    xmid = 0.5 * (bounds.xmin + bounds.xmax)

    ymid = 0.5 * (bounds.ymin + bounds.ymax)

    zmid = 0.5 * (bounds.zmin + bounds.zmax)

    half = 0.5 * max(bounds.xmax — bounds.xmin, bounds.ymax — bounds.ymin, bounds.zmax — bounds.zmin)

    if half <= 0:

        half = 1.0

    ax.set_xlim(xmid — half, xmid + half)

    ax.set_ylim(ymid — half, ymid + half)

    ax.set_zlim(zmid — half, zmid + half)

    try:

        ax.set_box_aspect((1.0, 1.0, 1.0))

    except Exception:

        pass

    try:

        ax.set_proj_type(«ortho»)

    except Exception:

        pass

def _plot_surface_piece_x(ax, axis_seg: np.ndarray, radius_seg: np.ndarray, bounds: PlotBounds3D, stride: int = 3):

    X, Y, Z = revolve_about_x(axis_seg, radius_seg)

    ax.plot_surface(

        X[::stride, ::stride], Y[::stride, ::stride], Z[::stride, ::stride],

        linewidth=0, edgecolor=»none», alpha=SURFACE_ALPHA, antialiased=False, shade=True

    )

    bounds.update(X, Y, Z)

def _plot_surface_piece_y(ax, axis_seg: np.ndarray, radius_seg: np.ndarray, bounds: PlotBounds3D,

                          split_positions: Sequence[float] = (), stride: int = 3):

    # Для горизонтального типа разбиваем по положениям сдвигов рядов,

    # чтобы в центральных зонах не сглаживались изломы.

    split_ids = set()

    for pos in split_positions:

        idx = int(np.argmin(np.abs(axis_seg — pos)))

        if 1 <= idx < axis_seg.size — 1 and np.isclose(axis_seg[idx], pos, atol=1e-10):

            split_ids.add(idx)

    starts = [0] + sorted(split_ids)

    ends = sorted(split_ids) + [axis_seg.size — 1]

    for st, en in zip(starts, ends):

        seg_axis = axis_seg[st:en + 1]

        seg_rad = radius_seg[st:en + 1]

        if seg_axis.size < 2:

            continue

        X, Y, Z = revolve_about_y(seg_axis, seg_rad)

        ax.plot_surface(

            X[::stride, ::stride], Y[::stride, ::stride], Z[::stride, ::stride],

            linewidth=0, edgecolor=»none», alpha=SURFACE_ALPHA, antialiased=False, shade=True

        )

        bounds.update(X, Y, Z)

# ————————————————————

# 2D РИСУНКИ ОБЩЕГО ОБЪЁМА

# ————————————————————

def _plot_component_2d(ax, axis: np.ndarray, lo: np.ndarray, hi: np.ndarray):

    «»»

    Рисует только реальные границы объединённого объёма.

    ВАЖНО:

    — скрипт ничего не дорисовывает;

    — fill_betweenx / fill_between не используются;

    — если после объединения интервалов возникает скачок нумерации компонент,

      кривая разрывается и не соединяется искусственным прямым отрезком.

    «»»

    mask = np.isfinite(lo) & np.isfinite(hi) & (hi > lo + MERGE_TOL)

    for st, en in _contiguous_segments(mask, axis):

        yy = axis[st:en]

        lo_seg = lo[st:en]

        hi_seg = hi[st:en]

        _plot_boundary_curve(ax, hi_seg, yy, lw=1.8)

        _plot_boundary_curve(ax, -hi_seg, yy, lw=1.8)

        if np.nanmax(lo_seg) > MERGE_TOL:

            _plot_boundary_curve(ax, lo_seg, yy, lw=1.5)

            _plot_boundary_curve(ax, -lo_seg, yy, lw=1.5)

def plot_union_section_vertical(order: int,

                                global_axis: np.ndarray,

                                lo_components: List[np.ndarray],

                                hi_components: List[np.ndarray],

                                m: int,

                                h: float,

                                outpath: Path | None = None,

                                show: bool = True):

    fig, ax = plt.subplots(figsize=(9, 10))

    for lo, hi in zip(lo_components, hi_components):

        _plot_component_2d(ax, global_axis, lo, hi)

    rmax = 0.0

    for hi in hi_components:

        if np.any(np.isfinite(hi)):

            rmax = max(rmax, float(np.nanmax(hi)))

    if rmax <= 0:

        rmax = 1.0

    ax.set_xlim(-1.05 * rmax, 1.05 * rmax)

    ax.set_title(f»Вертикальный тип, порядок {order}: общий объём, 2D сечение, m={m}, h={h}»)

    ax.set_xlabel(«Радиальная координата»)

    ax.set_ylabel(«Координата вдоль общей оси»)

    ax.set_aspect(«equal», adjustable=»box»)

    fig.tight_layout()

    _save_or_show(fig, outpath, show)

def plot_union_section_horizontal(order: int,

                                  global_axis: np.ndarray,

                                  lo_components: List[np.ndarray],

                                  hi_components: List[np.ndarray],

                                  m: int,

                                  h: float,

                                  outpath: Path | None = None,

                                  show: bool = True):

    fig, ax = plt.subplots(figsize=(10, 8))

    for lo, hi in zip(lo_components, hi_components):

        _plot_component_2d(ax, global_axis, lo, hi)

    rmax = 0.0

    for hi in hi_components:

        if np.any(np.isfinite(hi)):

            rmax = max(rmax, float(np.nanmax(hi)))

    if rmax <= 0:

        rmax = 1.0

    ax.set_xlim(-1.05 * rmax, 1.05 * rmax)

    ax.set_title(f»Горизонтальный тип, порядок {order}: общий объём, 2D сечение, m={m}, h={h}»)

    ax.set_xlabel(«Радиальная координата»)

    ax.set_ylabel(«Координата вдоль общей оси»)

    ax.set_aspect(«equal», adjustable=»box»)

    fig.tight_layout()

    _save_or_show(fig, outpath, show)

# ————————————————————

# 3D ПОВЕРХНОСТИ ОБЩЕГО ОБЪЁМА

# ————————————————————

def plot_union_surface_vertical(order: int,

                                global_axis: np.ndarray,

                                lo_components: List[np.ndarray],

                                hi_components: List[np.ndarray],

                                m: int,

                                h: float,

                                outpath: Path | None = None,

                                show: bool = True,

                                stride: int = 3):

    fig = plt.figure(figsize=(10, 8))

    ax = fig.add_subplot(111, projection=»3d»)

    bounds = PlotBounds3D()

    for lo, hi in zip(lo_components, hi_components):

        mask = np.isfinite(lo) & np.isfinite(hi) & (hi > lo + MERGE_TOL)

        for st, en in _contiguous_segments(mask, global_axis):

            axis_seg = global_axis[st:en]

            lo_seg = lo[st:en]

            hi_seg = hi[st:en]

            _plot_surface_piece_x(ax, axis_seg, hi_seg, bounds, stride=stride)

            if np.nanmax(lo_seg) > MERGE_TOL:

                _plot_surface_piece_x(ax, axis_seg, lo_seg, bounds, stride=stride)

    set_axes_equal_real_3d(ax, bounds)

    ax.set_title(f»Вертикальный тип, порядок {order}: 3D поверхность общего объёма, m={m}, h={h}»)

    ax.set_xlabel(«X»)

    ax.set_ylabel(«Y»)

    ax.set_zlabel(«Z»)

    fig.tight_layout()

    _save_or_show(fig, outpath, show)

def plot_union_surface_horizontal(order: int,

                                  global_axis: np.ndarray,

                                  lo_components: List[np.ndarray],

                                  hi_components: List[np.ndarray],

                                  shifts: np.ndarray,

                                  m: int,

                                  h: float,

                                  outpath: Path | None = None,

                                  show: bool = True,

                                  stride: int = 3):

    fig = plt.figure(figsize=(10, 8))

    ax = fig.add_subplot(111, projection=»3d»)

    bounds = PlotBounds3D()

    for lo, hi in zip(lo_components, hi_components):

        mask = np.isfinite(lo) & np.isfinite(hi) & (hi > lo + MERGE_TOL)

        for st, en in _contiguous_segments(mask, global_axis):

            axis_seg = global_axis[st:en]

            lo_seg = lo[st:en]

            hi_seg = hi[st:en]

            _plot_surface_piece_y(ax, axis_seg, hi_seg, bounds, split_positions=shifts, stride=stride)

            if np.nanmax(lo_seg) > MERGE_TOL:

                _plot_surface_piece_y(ax, axis_seg, lo_seg, bounds, split_positions=shifts, stride=stride)

    set_axes_equal_real_3d(ax, bounds)

    ax.set_title(f»Горизонтальный тип, порядок {order}: 3D поверхность общего объёма, m={m}, h={h}»)

    ax.set_xlabel(«X»)

    ax.set_ylabel(«Y»)

    ax.set_zlabel(«Z»)

    fig.tight_layout()

    _save_or_show(fig, outpath, show)

# ————————————————————

# ОСНОВНАЯ ФУНКЦИЯ

# ————————————————————

def run_pseudohyperboloids(a: float = 0.5,

                           b: float = 1.0,

                           R: float = 15.0,

                           offsets: Sequence[float] = (14.0, 30.0),

                           geometry_type: str = «both»,   # vertical / horizontal / both

                           mode: str = «all»,             # section / surface / all

                           outdir: str = «pseudohyperboloids_notebook_output»,

                           npts: int = 900,

                           h: float = -2.0,

                           m: int = 3,

                           show: bool = True) -> Dict[str, object]:

    «»»

    Главная функция.

    Строится ИТОГОВЫЙ ОБЩИЙ ОБЪЁМ для каждого порядка от 2 до n,

    включая пересечения и вложения компонент.

    «»»

    offsets = list(offsets)

    outdir_path = Path(outdir)

    _ensure_dir(outdir_path)

    if geometry_type not in {«vertical», «horizontal», «both»}:

        raise ValueError(«geometry_type должен быть ‘vertical’, ‘horizontal’ или ‘both'»)

    if mode not in {«section», «surface», «all»}:

        raise ValueError(«mode должен быть ‘section’, ‘surface’ или ‘all'»)

    if a <= 0 or b <= 0 or R <= 0:

        raise ValueError(«Параметры a, b, R должны быть положительными»)

    if int(m) != m or m < 1:

        raise ValueError(«Параметр m должен быть целым числом >= 1»)

    result = {

        «a»: a,

        «b»: b,

        «R»: R,

        «offsets»: offsets,

        «n_order»: len(offsets) + 2,

        «focus_c»: c_focus(a, b),

        «morphology»: morphology_class(R, offsets),

        «m»: int(m),

        «h»: float(h),

        «volume_mode»: «union_of_all_toroidal_components»,

        «saved_files»: [],

        «warnings»: [],

    }

    print(f»a = {a}»)

    print(f»b = {b}»)

    print(f»R = {R}»)

    print(f»offsets = {offsets}»)

    print(f»Порядок n = {len(offsets) + 2}»)

    print(f»Фокусное расстояние c = {c_focus(a, b):.6f}»)

    print(f»Морфологический класс = {result[‘morphology’]}»)

    print(f»m = {m}»)

    print(f»h = {h}»)

    print(«Режим построения = общий объём как объединение всех компонент»)

    print(«Правило: удаляется только общая перекрывающаяся часть объёма,»)

    print(«а сами псевдогиперболоидные тороиды как порождающие объекты не удаляются.»)

    print(f»Папка вывода = {outdir_path.resolve()}»)

    if geometry_type in {«vertical», «both»}:

        base_v = vertical_base_grid(a, b, R, npts=npts)

        result[«warnings»].extend([f»vertical-left: {w}» for w in validate_offsets(base_v[«d_left»], offsets)])

        result[«warnings»].extend([f»vertical-right: {w}» for w in validate_offsets(base_v[«d_right»], offsets)])

        for p in range(2, len(offsets) + 3):

            used_offsets = offsets[:max(0, p — 2)]

            global_axis, lo_components, hi_components, _ = vertical_order_union_components(

                a, b, R, used_offsets, npts=npts, m=m, h=h

            )

            if mode in {«section», «all»}:

                path = outdir_path / f»vertical_order_{p:02d}_section_m{m}_h{h}.png»

                plot_union_section_vertical(

                    order=p,

                    global_axis=global_axis,

                    lo_components=lo_components,

                    hi_components=hi_components,

                    m=m,

                    h=h,

                    outpath=path,

                    show=show,

                )

                result[«saved_files»].append(str(path))

            if mode in {«surface», «all»}:

                path = outdir_path / f»vertical_order_{p:02d}_surface_m{m}_h{h}.png»

                plot_union_surface_vertical(

                    order=p,

                    global_axis=global_axis,

                    lo_components=lo_components,

                    hi_components=hi_components,

                    m=m,

                    h=h,

                    outpath=path,

                    show=show,

                )

                result[«saved_files»].append(str(path))

    if geometry_type in {«horizontal», «both»}:

        base_h = horizontal_base_grid(a, b, R, npts=npts)

        result[«warnings»].extend([f»horizontal: {w}» for w in validate_offsets(base_h[«d»], offsets)])

        for p in range(2, len(offsets) + 3):

            used_offsets = offsets[:max(0, p — 2)]

            global_axis, lo_components, hi_components, _, shifts = horizontal_order_union_components(

                a, b, R, used_offsets, npts=npts, m=m, h=h

            )

            if mode in {«section», «all»}:

                path = outdir_path / f»horizontal_order_{p:02d}_section_m{m}_h{h}.png»

                plot_union_section_horizontal(

                    order=p,

                    global_axis=global_axis,

                    lo_components=lo_components,

                    hi_components=hi_components,

                    m=m,

                    h=h,

                    outpath=path,

                    show=show,

                )

                result[«saved_files»].append(str(path))

            if mode in {«surface», «all»}:

                path = outdir_path / f»horizontal_order_{p:02d}_surface_m{m}_h{h}.png»

                plot_union_surface_horizontal(

                    order=p,

                    global_axis=global_axis,

                    lo_components=lo_components,

                    hi_components=hi_components,

                    shifts=shifts,

                    m=m,

                    h=h,

                    outpath=path,

                    show=show,

                )

                result[«saved_files»].append(str(path))

    if result[«warnings»]:

        print(«\nПРЕДУПРЕЖДЕНИЯ:»)

        for w in result[«warnings»]:

            print(» -«, w)

    print(«\nСОХРАНЁННЫЕ ФАЙЛЫ:»)

    for f in result[«saved_files»]:

        print(» -«, f)

    return result

# ————————————————————

# ПАРАМЕТРЫ ПО УМОЛЧАНИЮ ДЛЯ ЭТОЙ ТЕМЫ

# ————————————————————

if __name__ == «__main__»:

    a = 0.5

    b = 1.0

    R = 15.0

    offsets = [14.0, 30.0]    # R1, R2, …, R_{n-2}

    geometry_type = «both»   # «vertical», «horizontal», «both»

    mode = «all»             # «section», «surface», «all»

    outdir = «pseudohyperboloids_notebook_output»

    npts = 900

    m = 3

    h = -2.0

    show = True

    results = run_pseudohyperboloids(

        a=a,

        b=b,

        R=R,

        offsets=offsets,

        geometry_type=geometry_type,

        mode=mode,

        outdir=outdir,

        npts=npts,

        m=m,

        h=h,

        show=show,

    )

Б. Основные обозначения

a, b — Параметры исходной гиперболической образующей.

R — базовый радиальный масштаб открытого псевдогиперболоида второго порядка.

R₁, R₂, …, Rₙ₋₂ — Рекурсивные радиальные смещения, последовательно повышающие порядок конструкции.

n — Порядок внутренней рекурсии одного псевдогиперболоидного экземпляра.

m — Число одинаковых экземпляров в рядной системе.

h — Осевой зазор, касание или перекрытие соседних экземпляров рядной системы.

ξ — Обобщённая осевая координата; для вертикального типа обычно s, для горизонтального типа u.

ρ — Радиальная координата относительно оси вращения.

d(ξ) — Базовая радиальная функция второго порядка.

Bₙ — Множество формальных ветвей n-го порядка.

Nₙ = 2ⁿ⁻² — Число формальных ветвей n-го порядка.

Iₙ(ξ) — Множество допустимых радиальных интервалов при фиксированной осевой координате ξ.

C_R — Интервальный рекурсивный оператор скрипта: C_R ([α, β]) = [max(R − β, 0), max(R − α, 0)] ∪ [R + α, R + β].

Merge — Операция слияния пересекающихся или соприкасающихся интервалов.

Ωₙ — Общий внутренний объём одиночного псевдогиперболоида n-го порядка.

Ωₙ,ₘ — Общий внутренний объём рядной системы из m экземпляров.

∂Ω — Граница общего внутреннего объёма.

L — Половина осевой длины вертикального базового экземпляра: L = a√ (1 + (R/b) ²).

H — Половина длины экземпляра вдоль общей оси при рядной компоновке.

step = 2H + h — Шаг между центрами соседних рядных экземпляров.

В. Геометрически выводимые возможности

Ниже перечислены возможности, которые относятся прежде всего к геометрии. Их следует считать подтверждаемыми конструктивной моделью и вычислительной реализацией, но их физическое волновое значение требует отдельной верификации.

  1. Топологический переключатель h.

Возможность: Параметр h управляет расстоянием между рядами (этажами) структуры. При h > 0 ряды раздельны, при h = 0 касаются, а при h < 0 перекрываются и могут объединиться в общий объём.

Геометрический смысл: h задаёт дискретный переход между раздельными и слитыми топологиями внутреннего пространства.

Новизна: Связность становится прямым проектным параметром, а не побочным следствием изготовления. Это позволяет управлять числом независимых полостей на этапе проектирования, что невозможно при плавной регулировке связи между классическими резонаторами.

Потенциальные области: Перестраиваемые СВЧ-фильтры, акустические камеры, многорежимные резонаторы, селективные фильтры, частотно-распределённые лазеры.

  • Переход кольцо ↔ диск/ось через R₁/R.

Возможность: Изменение соотношения рекурсивных смещений меняет тип внутренней области.

Геометрический смысл: Параметр R₁/R определяет, образуется ли кольцевая зона или оседостигающая (дисковая) зона внутри структуры.

Новизна: Один класс геометрии способен задавать принципиально разные типы потенциальной локализации волнового поля, заменяя собой несколько различных классических конструкций.

Потенциальные области: Антенны с различной диаграммой направленности, концентраторы, датчики с разной чувствительной зоной.

  • Топологическая компрессия ветвления.

Возможность: Рекурсия формально увеличивает сложность, но операция Merge её сжимает.

Геометрический смысл: Формальное число ветвей растёт как 2^(n−2), но после алгоритмического слияния (Merge) общих частей число реальных физических областей оказывается существенно меньше.

Новизна: Сложность задаётся рекурсивным законом и автоматически упаковывается в управляемое число функциональных зон, а не создаётся сборкой множества отдельных элементов.

Потенциальные области: Компактные многомодовые резонаторы и фильтры, акустические камеры сложной формы, генеративная инженерия резонаторов.

  • Геометрический рост области с порядком n.

Возможность: Увеличение порядка n расширяет внутреннее пространство.

Геометрический смысл: Площадь меридионального сечения внутреннего объёма удваивается с увеличением порядка на единицу (S(n) = 2^(n−2) · S (2)), экспоненциально увеличивая фазовый объём.

Новизна: Порядок n становится геометрическим усилителем «спектральной ёмкости» конструкции, позволяя при фиксированных габаритах получать больше резонансных полос.

Потенциальные области: Сверхширокополосные приёмники, многоканальные оптические фильтры (DWDM), терагерцовые спектрометры, квантовые многомодовые источники.

  • Разделение объёма и поперечной области.

Возможность: Независимое управление полным объёмом и толщиной канала.

Геометрический смысл: Параметры (R₁ и n) позволяют изменять радиальный вынос («длину») и полный объём структуры без пропорционального изменения локальной толщины профиля («ширины» канала).

Новизна: Появляется дополнительная степень свободы проектирования, разделяющая управление частотой резонанса и модовым объёмом, что снимает классические инженерные компромиссы.

Потенциальные области: Высокомощные лазеры с малой расходимостью, сверхдобротные резонаторы, гравитационно-волновые детекторы, источники одиночных фотонов.

  • Объёмная упаковка рядов при h <0.

Возможность: Эффективное использование пространства при добавлении рядов.

Геометрический смысл: В режиме перекрытия (h <0) добавочный объём каждого нового ряда (m) может быть меньше объёма отдельного экземпляра, так как зоны начинают совместно использовать часть пространства.

Новизна: Многоэлементная система перестаёт масштабироваться строго линейно, позволяя создавать более компактные устройства с высокой плотностью функциональных зон.

Потенциальные области: Компактные многокамерные устройства, СВЧ-модули высокой плотности, акустические глушители, портативные сенсорные камеры.

  • Неэквивалентность вертикального и горизонтального типов.

Возможность: Получение разных классов устройств из одной рекурсивной формулы.

Геометрический смысл: Одна и та же рекурсия, применённая к вертикально-симметричному и горизонтально-симметричному базовому контуру, даёт разные типы связности внутренних областей.

Новизна: Из единого математического ядра возникают два принципиально разных класса устройств: разделяющие (вертикальный тип) и проводящие (горизонтальный тип), что расширяет инженерный потенциал платформы.

Потенциальные области: Парные датчики, волноводы, дипольные структуры, сравнительная спектроскопия.

  • Скрытая селекция границ через Merge.

Возможность: Алгоритмическое определение итоговой формы.

Геометрический смысл: До операции Merge существуют только формальные интервалы и пересечения. Merge сливает общие части, оставляя лишь физически значимые границы конечного общего объёма.

Новизна: Финальная форма резонатора становится результатом работы алгоритма, а не интуитивного ручного черчения. Это переход к генеративной инженерии волновых устройств.

Потенциальные области: Автоматическое порождение сложных резонаторных форм, параметрическая оптимизация под заданные частоты.

  • Рекурсивный усилитель границы.

Возможность: Увеличение активной внутренней поверхности.

Геометрический смысл: Высшие порядки способны радикально увеличивать площадь внутренней границы (активной поверхности) относительно объёма по сравнению с простыми формами.

Новизна: Объект может быть ценен не только (или не столько) как резонатор для удержания волны, но и как мощная поверхность для взаимодействия с волной, средой или покрытием.

Потенциальные области: Поглотители, сенсоры, плазменные и каталитические камеры, структуры для тепло- и массообмена.

Г. Проверяемые волновые гипотезы

Следующая группа утверждений относится уже не к доказанной геометрии, а к программе волновой верификации. Корректный статус — проверяемые гипотезы, вытекающие из геометрической структуры Ωₙ,ₘ.

1. Гибридные моды перекрытия. Это гипотеза о возникновении особой волновой моды в условиях, когда ряды структур перекрываются (параметр h <0). Считается, что при таком перекрытии, создающем общий объём, может сформироваться мода, которая не является свойственной отдельному ряду, а существует исключительно в зоне их объединения. Это качественно отличается от простой связи между резонаторами, представляя собой новую физическую область. Для проверки данной гипотезы методом численного моделирования (FEM/FDTD) необходимо искать распределение поля, где его максимум находится именно в зоне пересечения рядов, а также фиксировать исчезновение такой моды при переходе к нулевому или положительному значению h и наблюдать расщепление резонансных частот.

2. Дисково-кольцевая перестройка моды. Данная гипотеза предполагает, что геометрический переход от дисковой к кольцевой области, управляемый параметром R₁/R, будет напрямую отражаться на распределении волнового поля. Прогнозируется, что при малых значениях R₁/R максимум интенсивности поля (|ψ|² или |E|²) будет сосредоточен на оси симметрии, а при увеличении этого параметра — переместится в кольцевую область по периферии. Критическим для перестройки считается значение R₁/R = 1. Проверка требует серии расчётов распределения поля при различных R₁/R для выявления точки резкого перехода и анализа характеристик смешанной моды вблизи этой точки.

3. Рекурсивное расщепление спектра. Согласно этой гипотезе, увеличение порядка рекурсии n оставляет отпечаток в спектре собственных частот структуры. Ожидается, что спектр будет демонстрировать рекурсивное расщепление, образуя группы или «семейства» частот, соответствующие каждому порядку построения. Хотя операция Merge упрощает физическую структуру, её след в виде самоподобных интервалов между резонансами может сохраниться. Для проверки необходимо сравнивать полные спектры (наборы собственных частот и мод) для структур последовательных порядков, например, от n=2 до n=5, и выявлять в них закономерные группы.

4. Медленная волна в рядной системе. Данный эффект прогнозирует, что цепочка связанных рядов (при m> 1) может функционировать как пассивная линия задержки, в которой групповая скорость волны существенно снижается. Особенностью является то, что связь между элементами задаётся не традиционным зазором, а общей рекурсивной геометрией и степенью перекрытия h. Валидация гипотезы заключается в расчёте зависимости групповой скорости и анализа отклика на импульсное возбуждение при различных конфигурациях (разные h и m), а также в наблюдении перехода от режима слабой связи к полному слиянию рядов.

5. BIC-подобные режимы (Квазисвязанные состояния в континууме). Эта гипотеза основана на предположении, что рекурсивная симметрия структур высших порядков может приводить к взаимной интерференции и гашению нескольких каналов излучения, что характерно для связанных состояний в континууме (BIC). В результате может формироваться мода, существующая в открытом резонаторе, но обладающая крайне низкими радиационными потерями и, следовательно, высокой добротностью (Q). Для поиска таких режимов необходимо проводить параметрическое сканирование, отслеживая резкий рост добротности в узкой области параметров (например, при определённых R₁ или h), а также проверять чувствительность этого состояния к преднамеренному нарушению симметрии конструкции.

6. Каустические кольца и диски. Гипотеза заключается в том, что сложная отрицательная кривизна границ псевдогиперболоида приводит к образованию каустик — областей, где траектории лучей (в приближении геометрической оптики) или фазовые фронты волн сгущаются. В зависимости от геометрии эти области могут формировать кольца или диски. Переход между кольцевой и дисковой каустикой может управляться параметром R₁/R. Проверка осуществляется методами лучевой трассировки для построения карт плотности пересечения траекторий и анализа их устойчивости при изменении точки возбуждения.

7. Устойчивость к дефектам. Данная гипотеза утверждает, что благодаря распределённому характеру сложной рекурсивной структуры, где функция резонатора разделена между множеством внутренних зон, её характеристики (резонансные частоты, добротность, локализация поля) могут быть менее чувствительны к локальным дефектам поверхности по сравнению с простыми резонаторами (например, кольцевыми). Для проверки необходимо в численной модели вводить случайный шум (нерегулярности) на границы, сравнивать возникающие изменения ключевых параметров с эталонной идеальной структурой и проводить сравнение с аналогичным тестом для простого резонатора.

8. Геометрическая память. Предполагается, что благодаря наличию множества внутренних зон и сложным траекториям переотражений, волна может долго циркулировать внутри объёма после импульсного возбуждения. Это проявляется в виде длительного «хвоста» импульсного отклика с последовательными затухающими пиками, что можно интерпретировать как своего рода память системы о начальном воздействии. Исследование эффекта требует анализа временного отклика на короткий импульс, выявления зависимостей длительности и структуры «хвоста» от параметров ряда (m) и перекрытия (h), а также наблюдения перехода к хаотическому отклику при высоких порядках n.

9. Волновое разделение по траекториям.  Гипотеза состоит в том, что различные типы мод или лучей в сложной рекурсивной геометрии могут пространственно разделяться, локализуясь в разных внутренних областях. Например, одни моды могут преимущественно существовать в кольцевых зонах, другие — в дисковых, третьи — в областях перехода между рядами. Это разделение может также сопровождаться различиями в резонансных частотах, времени задержки и направлении излучения для разных мод. Проверка требует проведения полного модального анализа с построением карт локализации поля для каждой резонансной частоты и сопоставления их с внутренней топологией структуры.

10. Нелинейное усиление в выбранных зонах. Эта гипотеза основывается на эффекте локальной концентрации поля в определённых зонах структуры (например, в «горлышке» с максимальной кривизной или в кольцевых областях). Предполагается, если разместить нелинейный материал именно в этих активных областях, можно добиться значительного усиления нелинейно-оптических эффектов (например, генерации второй гармоники) при сравнительно низкой общей мощности накачки. Валидация включает расчёт карт распределения квадрата амплитуды поля (|E|²) для идентификации зон с максимальной концентрацией, и последующую проверку пороговых характеристик нелинейного отклика в зависимости от порядка структуры n.

Д. Прикладные направления после верификации

Ниже перечислены не готовые технические изделия, а направления, в которых рекурсивные псевдогиперболоидные объёмы могут дать принципиально новые инженерные решения после подтверждения расчётами и экспериментами.

  1. СВЧ-резонаторы и фильтры. Возможна реализация в виде многомодовых металлических камер, изготовленных методом 3D-печати. Их ключевые параметры (резонансные частоты, добротность, распределение поля) будут напрямую управляться геометрическими параметрами конструкции: порядком n, отношением R₁/R, числом рядов m и степенью их перекрытия h. Новизна заключается в достижении многополосности, компактности и параметрической настройки характеристик устройства через его геометрию.
  2. Акустические устройства. Данный диапазон является удобной экспериментальной площадкой из-за крупных длин волн, что упрощает изготовление и тестирование прототипов. Структуры могут быть использованы для создания акустических фильтров, звуковых ловушек, направленных камер, концертных диффузоров и шумоподавителей нового типа.
  3. Антенны и апертурные устройства. Кольцевые и дисковые зоны внутри объёма могут служить пассивными формирователями поля для создания антенн фиксированного направления. Новизна подхода в том, что тип локализации и, следовательно, характеристики излучения задаются не активными фазирующими элементами, а самой геометрией конструкции, что особенно ценно для дешёвых, надёжных и специализированных систем, где электронное сканирование не требуется.
  4. Сенсорика. Высокая удельная внутренняя поверхность и сложная модовая структура делают такие объёмы крайне чувствительными к малым изменениям окружающей среды или состояния границ. Это открывает путь к созданию нового поколения газовых, биологических, влажностных, деформационных и поверхностных датчиков, где измеряемый параметр вызывает сдвиг резонансной частоты.
  5. Поглотители и диффузоры. В случаях, когда цель — не удержать волну, а эффективно рассеять или поглотить её, рекурсивная внутренняя поверхность с её сложной кривизной становится мощным инструментом. Такие структуры могут найти применение в радиопоглощающих и акустических глушителях, вибрационных демпферах, защитных покрытиях и в отделке безэховых камер. Их ценность заключается не в высокой добротности, а в управляемом многократном взаимодействии волны со стенкой.
  6. Плазменные и разрядные камеры. Сложная форма внутреннего объёма с криволинейными границами позволяет геометрически управлять распределением СВЧ-поля и, как следствие, плазмы внутри камеры. Это может привести к созданию новых типов плазменных реакторов, СВЧ-разрядных камер, источников плазмы и систем для обработки поверхностей.
  7. Оптика и фотоника. Геометрический принцип построения масштабируем, что позволяет перенести его в микро- и нанометровый диапазон для работы со светом. Основной задачей здесь станет поиск и использование специфических волновых режимов, таких как BIC-подобные состояния с высокой добротностью, режимы медленного света или сложные многомодовые структуры.
  8. Физические вычисления. Сложный пространственно-временной отклик рекурсивного объёма на входной сигнал может быть использован для аналоговых вычислений. Такая структура способна выступать в качестве пассивной вычислительной среды (резервуара) для задач классификации сигналов или обработки радиоволн, преобразуя входные данные в богатый, легко считываемый отклик.

Таким образом, новизна технологии лежит не в создании единого универсального устройства, а в предоставлении новой геометрической платформы для проектирования широкого спектра устройств, управляемых через топологию их внутреннего пространства

Е. Отличия от известных направлений

Сравнения с известными направлениями должны использоваться осторожно. В Томе 1 нельзя утверждать, что псевдогиперболоиды уже превосходят WGM-резонаторы, CROW-цепочки, BIC-платформы, фотонные кристаллы или метаматериалы. Но можно указать конструктивное отличие предлагаемой геометрии.

Сравнение проводиться осторожно, без утверждений о превосходстве, но с чётким указанием на принципиальное конструктивное отличие новой геометрической платформы.

  1. По сравнению с WGM-резонаторами (Whispering Gallery Modes). Обычный принцип WGM: Удержание волны около одной или нескольких гладких криволинейных поверхностей за счёт механизмов, подобных полному внутреннему отражению.

Отличие псевдогиперболоидов: Вместо единой гладкой зоны используется рекурсивная система внутренних зон, формируемая правилом построения и алгоритмически обрабатываемая операцией Merge (Слияние), с дополнительным управлением связностью через рядное перекрытие (параметр h).

  • По сравнению с CROW-цепочками (Coupled Resonator Optical Waveguides). Обычный принцип CROW: Создание волноводных свойств путём связи цепи отдельных, дискретных резонаторов.

Отличие псевдогиперболоидов: При параметре перекрытия h <0 отдельные ряды (этажи) структуры не просто связываются, а топологически объединяются в единый общий внутренний объём Ωₙ,ₘ. Это переход от дискретного массива к слитой геометрии.

  • По сравнению с фотонными кристаллами. Обычный принцип: Управление волнами через строгую пространственную периодичность структуры, создающую запрещённые зоны в спектре.

Отличие псевдогиперболоидов: В основе лежит рекурсивная, но непериодическая внутренняя геометрия, задаваемая порядком (n) и смещениями (R, R₁). Сложность возникает из рекурсивного правила, а не из пространственного повтора элементарной ячейки.

  • По сравнению с BIC-платформами (Bound States in the Continuum). Обычный принцип BIC: Достижение состояний с подавленным излучением (высокой добротностью) за счёт точной симметрии или интерференции каналов излучения в открытых резонаторах.

Отличие псевдогиперболоидов: Структура предоставляет геометрическую платформу, на которой BIC-подобные режимы потенциально можно искать, используя рекурсивные симметрии высших порядков и точки топологических переходов (например, при h=0 или R₁/R=1).

  • По сравнению с метаматериалами. Обычный принцип метаматериалов: Необычные эффективные свойства (например, отрицательный коэффициент преломления) задаются в первую очередь искусственным составом и микроструктурой материала.

Отличие псевдогиперболоидов: Первичным управляющим фактором является форма и связность пустого внутреннего пространства (Ωₙ,ₘ). Свойства волновода определяются геометрией вакуумной или воздушной полости, а не анизотропными свойствами заполняющего её материала.

Итог: подход заключается не в прямом соревновании с существующими технологиями по отдельным показателям (например, добротности), а в смене парадигмы проектирования: переходе от создания отдельных резонаторов, линз или периодических решёток к рекурсивному программированию топологии и связности внутреннего объёма как основного инструмента управления волной.

Ж. Принципы проектирования волновых систем

Потенциал новой теории связан с переходом к новой логике создания устройств, основанной не на сборке деталей, а на программировании пространства. Вот её основные принципы:

1. Принцип программируемой топологии. В отличие от классического подхода, где инженер настраивает размеры внутри жёстко заданной формы (например, меняя радиус сферы), здесь сама внутренняя топология становится переменной. Параметр h управляет связностью: при h <0 раздельные полости сливаются в единый объём. Параметр R₁/R переключает тип внутренней зоны между кольцевой и дисковой. То есть, мы проектируетм не одно устройство, а целое семейство, выбирая нужную конфигурацию из меню параметров.

2. Принцип рекурсивного порождения формы. Сложная структура возникает не из сборки множества отдельных резонаторов, а из выполнения одного рекурсивного геометрического правила. Проектируется не конечный чертёж, а алгоритм, который этот чертёж создаёт. Это переход от конструирования деталей к конструированию правил их создания.

3. Принцип функциональной геометрии. Многие функции, которые в традиционной технике выполняют активные элементы (переключатели, фазовращатели, нелинейные кристаллы), можно закодировать в самой форме. Например, переключение канала задаётся параметром h, а концентрация поля в зонах высокой кривизны может имитировать нелинейные эффекты. Это открывает путь к более простым, надёжным и пассивным устройствам.

4. Принцип топологической сложности как ресурса. В классической инженерии основные ресурсы — это габариты, материалы и количество элементов. Здесь появляется новый ресурс — управляемая сложность внутреннего пространства. Повышая порядок n и настраивая параметры, можно создавать больше внутренних зон, резонансных частот и каналов управления, не добавляя физических деталей, а лишь усложняя геометрию по заданному правилу.

5. Принцип цифровой совместимости. Подобные сложные рекурсивные объёмы практически невозможно изготовить классической механической обработкой. Однако они идеально подходят для современных методов аддитивного производства — 3D-печати и литографии. Таким образом, эта теория предоставляет математический язык, напрямую связывающий цифровое проектирование со сложным цифровым производством.

Итог: В совокупности эти принципы означают переход от управления волнами через набор отдельных компонентов к алгоритмическому проектированию внутреннего пространства как целостной среды. Новизна заключается в том, что волновая инженерия получает качественно новые степени свободы за счёт перехода от черчения форм к программированию геометрии.

З. Итоговая формулировка

Рядные псевдогиперболоиды высших порядков открывают новый подход к проектированию волновых областей: не через отдельную линзу, зеркало, резонатор или решётку, а через рекурсивно программируемый общий внутренний объём. Параметры порядка, смещения, ориентации, рядности и перекрытия позволяют управлять связностью, числом внутренних зон, переходом между кольцевыми и оседостигающими областями, удельной поверхностью и потенциальной модовой структурой.

В этом смысле новые возможности теории состоят в появлении нового уровня инженерной свободы — топологии как проектного параметра. Том 1 строго строит этот геометрический аппарат. Следующие тома и экспериментальные работы покажут, какие из этих возможностей переходят в устойчивые физические эффекты для электромагнитных, акустических, упругих, гидродинамических и иных волновых процессов.

И. Литература

1. Хаустов В. И. (2025). Геометрическая волновая инженерия: наука о новых волновых процессах.

2. Хаустов В. И. (2025). Геометрическая волновая инженерия псевдоповерхностей 2-го и 3-го порядков.

3. Хаустов В. И. (2025). Геометрическая волновая инженерия псевдоповерхностей 4+ порядков.

4. Хаустов В. И. (2025). Геометрическая Волновая Инженерия: Псевдогиперболоиды.

5. Хаустов В. И. (2025). Геометрическая Волновая Инженерия: Псевдопараболоиды.

6. Хаустов В. И. (2025). Геометрическая Волновая Инженерия: Псевдоэллипсоиды.

7. Хаустов В. И. (2025). Геометрическая Волновая Инженерия: Инженерные решения на основе псевдоповерхностей для различных областей науки и техники.

8. Хаустов В. И. (2025). Волновая логика, вычисления и криптография на основе Геометрической Волновой Инженерии.

9. Хаустов В. И. (2025). Новые физические принципы Щита и Меча XXI века на основе Геометрической Волновой Инженерии.

10. Хаустов В. И. (2025). Технологии псевдоповерхностей высших порядков на грани науки и фантастики.

11. Хаустов В. И. (2026). Единая топологическая инженерия. Часть I. Конструктор невозможного: Как проектировать технологии, которых ещё не существует.

12. Хаустов В. И. (2026). Единая топологическая инженерия. Часть II. Инженерно-методологический подход к проектированию систем будущего.

13. Хаустов В. И. (2026). Единая топологическая инженерия. Часть III. Творческие тупики: инженерные методы выхода и стратегии проектирования будущего.

14. Хаустов В. И. (2026). Геометрическая волновая инженерия и имплозивная инженерия: Псевдогиперболоиды высших порядков в вихревой гидродинамике.

15. Хаустов В. И. (2026). Основы геометрической волновой инженерии: Теория псевдогиперболоидов 2-го порядка. Монография.

16. Хаустов В. И. (2026). Основы геометрической волновой инженерии: Теория псевдопараболоидов 2-го порядка. Монография.

17. Хаустов В. И. (2026). Основы геометрической волновой инженерии: Теория псевдоэллипсоидов 2-го порядка. Монография.